3535 *
3636 * @brief This file contains an implementation of a simple MIDI interpreter to parse incoming messages
3737 *
38- * MIDI_DUMP_Serial1_TO_SERIAL <- when active received data will be output as hex on serial(1)
39- * MIDI_SERIAL1_BAUDRATE <- use define to override baud-rate for MIDI, otherwise default of 31250 will be used
40- *
4138 * @see https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message
4239 */
4340
5047#ifdef ML_SYNTH_INLINE_DECLARATION
5148
5249
53- void Midi_Setup ();
54- void Midi_Process ();
50+ #define MIDI_CHANNEL_MASK 0x10
51+ #define MIDI_CHANNEL_0 0x01
52+ #define MIDI_CHANNEL_1 0x02
53+ #define MIDI_CHANNEL_2 0x04
54+ #define MIDI_CHANNEL_3 0x08
55+
56+
57+ void Midi_Setup (void );
58+ void Midi_Process (void );
5559
5660#ifdef MIDI_VIA_USB_ENABLED
5761void Midi_HandleShortMsg (uint8_t * data , uint8_t cable __attribute__((unused )));
@@ -60,10 +64,18 @@ void Midi_HandleShortMsgEx(uint8_t *data, uint8_t cable __attribute__((unused)))
6064
6165#ifdef MIDI_TX2_PIN
6266void Midi_SendShortMessage (uint8_t * msg );
67+ #endif
68+
69+ #ifdef MIDI_SYSEX_ENABLED
70+ void Midi_HandleSysEx (uint8_t * buf , uint8_t len );
71+ #endif
72+
6373#ifndef ARDUINO_SEEED_XIAO_M0
6474#ifndef SWAP_SERIAL
75+ #ifdef MIDI_TX2_PIN
76+ void Midi_SendShortMessage (uint8_t * msg );
6577void Midi_SendRaw (uint8_t * msg );
66- #endif
78+ #endif /* MIDI_TX2_PIN */
6779#endif
6880#endif
6981
@@ -108,6 +120,10 @@ void Midi_SendRaw(uint8_t *msg);
108120#define MIDI_PORT2_ACTIVE
109121#endif
110122
123+ #ifdef MIDI_SYSEX_ENABLED
124+ #define MIDI_SYSEX_MAX 256
125+ #endif
126+
111127#if (defined ARDUINO_RASPBERRY_PI_PICO ) || (defined ARDUINO_GENERIC_RP2040 )
112128#define PIN_CAPTION "GP"
113129#elif (defined ESP32 )
@@ -123,22 +139,22 @@ struct midi_port_s
123139 uint32_t inMsgWd ;
124140 uint8_t inMsg [3 ];
125141 uint8_t inMsgIndex ;
142+
143+ #ifdef MIDI_SYSEX_ENABLED
144+ bool sysexIncoming ;
145+ uint8_t sysexBuf [MIDI_SYSEX_MAX ];
146+ uint8_t sysexCnt ;
147+ #endif
126148};
127149
128- #ifdef ARDUINO_DAISY_SEED
150+ #if (defined ARDUINO_DAISY_SEED ) || (defined STM32H7xx )
129151HardwareSerial Serial2 (USART1 );
130152#endif
131153
132154#if (defined ARDUINO_GENERIC_F407VGTX ) // || (defined ARDUINO_DISCO_F407VG)
133155HardwareSerial Serial2 (USART2 ); /* PA3 */
134156#endif
135157
136- #if 0
137- #ifdef ARDUINO_GENERIC_F407VGTX
138- HardwareSerial Serial2 (USART3 ); /* PB11 */
139- #endif
140- #endif
141-
142158#ifdef MIDI_PORT_ACTIVE
143159struct midi_port_s MidiPort ;
144160#endif
@@ -270,7 +286,25 @@ inline void Midi_CC_Map(uint8_t channel, uint8_t data1, uint8_t data2, struct mi
270286{
271287 for (int i = 0 ; i < mapSize ; i ++ )
272288 {
273- if ((controlMapping [i ].channel == channel ) && (controlMapping [i ].data1 == data1 ))
289+ /*
290+ * in case channel and control number matches or
291+ * in channel bit 0x10 is set, then the bit of the channel is set too and control number matches
292+ */
293+ #if 0
294+ if ((controlMapping [i ].channel & 0x10 ) != 0 )
295+ {
296+ Serial .printf ("mask\n" );
297+ Serial .printf ("boold %d\n" , (controlMapping [i ].channel & (1 << channel )) != 0 );
298+ Serial .printf ("var %d\n" , (controlMapping [i ].channel & (1 << channel )));
299+ Serial .printf ("var1 %d\n" , controlMapping [i ].channel );
300+ Serial .printf ("var2 %d\n" , (1 << channel ));
301+ }
302+ #endif
303+
304+ if (
305+ ((controlMapping [i ].channel == channel ) && (controlMapping [i ].data1 == data1 ))
306+ || (((controlMapping [i ].channel & 0x10 ) != 0 ) && ((controlMapping [i ].channel & (1 << channel )) != 0 ) && (controlMapping [i ].data1 == data1 ))
307+ )
274308 {
275309 if (controlMapping [i ].callback_mid != NULL )
276310 {
@@ -439,6 +473,11 @@ static void Midi_PortSetup(struct midi_port_s *port)
439473 port -> inMsgWd = 0 ;
440474 memset (port -> inMsg , 0 , sizeof (port -> inMsg ));
441475 port -> inMsgIndex = 0 ;
476+ #ifdef MIDI_SYSEX_ENABLED
477+ port -> sysexIncoming = false;
478+ memset (port -> sysexBuf , 0 , sizeof (port -> sysexBuf ));
479+ port -> sysexCnt = 0 ;
480+ #endif
442481}
443482#endif
444483
@@ -479,8 +518,12 @@ void Midi_Setup()
479518 Serial1 .begin (MIDI_SERIAL1_BAUDRATE , SERIAL_8N1 , MIDI_RX1_PIN );
480519#endif
481520 pinMode (MIDI_RX1_PIN , INPUT_PULLUP ); /* can be connected to open collector output */
521+ #else
522+ #ifdef TEENSYDUINO
523+ Serial .printf ("Setup Serial1 with %d baud with rx: RX1 pin (PIN 0)\n" , MIDI_SERIAL1_BAUDRATE );
482524#else
483525 Serial .printf ("Setup Serial1 with %d baud with rx: RX1 pin\n" , MIDI_SERIAL1_BAUDRATE );
526+ #endif
484527 Serial1 .begin (MIDI_SERIAL1_BAUDRATE );
485528#endif
486529
@@ -525,20 +568,27 @@ void Midi_Setup()
525568 Serial2 .begin (MIDI_SERIAL2_BAUDRATE );
526569#endif /* MIDI_TX2_PIN */
527570
528- #else /* MIDI_RX2_PIN */
571+ #else /* ARDUINO_ARCH_RP2040 */
572+
573+ #ifdef MIDI_RX2_PIN
529574#ifdef MIDI_TX2_PIN
530575 Serial .printf ("Setup Serial2 with %d baud with rx: %s%d and tx %s%d\n" , MIDI_SERIAL2_BAUDRATE , PIN_CAPTION , MIDI_RX2_PIN , PIN_CAPTION , MIDI_TX2_PIN );
531576 Serial2 .setTX (MIDI_TX2_PIN );
532577#else /* MIDI_TX2_PIN */
533578 Serial .printf ("Setup Serial2 with %d baud with rx: %s%d\n" , MIDI_SERIAL2_BAUDRATE , PIN_CAPTION , MIDI_RX2_PIN );
534579#endif /* MIDI_TX2_PIN */
535580 Serial2 .setRX (MIDI_RX2_PIN );
581+ #else
582+ Serial .printf ("Setup Serial2 with %d baud with rx: Serial2.rx\n" , MIDI_SERIAL2_BAUDRATE , PIN_CAPTION );
583+ #endif
536584 Serial2 .begin (MIDI_SERIAL2_BAUDRATE );
537- #endif /* MIDI_RX2_PIN */
585+
586+ #endif /* ARDUINO_ARCH_RP2040 */
538587
539588 MidiPort2 .serial = & Serial2 ;
540589 Midi_PortSetup (& MidiPort2 );
541590 Serial .printf ("Setup MidiPort2 using Serial2\n" );
591+
542592#endif /* MIDI_PORT2_ACTIVE */
543593
544594#ifdef USB_MIDI_ENABLED
@@ -552,13 +602,44 @@ void Midi_CheckMidiPort(struct midi_port_s *port)
552602 {
553603 uint8_t incomingByte = port -> serial -> read ();
554604
605+ #ifdef MIDI_SYSEX_ENABLED
606+ if (port -> sysexIncoming )
607+ {
608+
609+ if (incomingByte == 0xF7 )
610+ {
611+ Serial .printf ("SysexDone\n" );
612+ port -> sysexIncoming = false;
613+ Midi_HandleSysEx (port -> sysexBuf , port -> sysexCnt );
614+ port -> sysexCnt = 0 ;
615+ return ;
616+ }
617+ else
618+ {
619+ port -> sysexBuf [port -> sysexCnt ] = incomingByte ;
620+ port -> sysexCnt ++ ;
621+ return ;
622+ }
623+ }
624+ #endif
625+
555626#ifdef MIDI_DUMP_SERIAL2_TO_SERIAL
556627 Serial .printf ("%02x" , incomingByte );
557628#endif
558629 /* ignore live messages */
559630 if ((incomingByte & 0xF0 ) == 0xF0 )
560631 {
561- Midi_RealTimeMessage (incomingByte );
632+ #ifdef MIDI_SYSEX_ENABLED
633+ if (incomingByte == 0xF0 )
634+ {
635+ Serial .printf ("SysexStart\n" );
636+ port -> sysexIncoming = true;
637+ }
638+ else
639+ #endif
640+ {
641+ Midi_RealTimeMessage (incomingByte );
642+ }
562643 return ;
563644 }
564645
@@ -616,6 +697,24 @@ void Midi_CheckMidiPort(struct midi_port_s *port)
616697 }
617698}
618699
700+ #ifdef MIDI_SYSEX_ENABLED
701+ void Midi_HandleSysEx (uint8_t * buf , uint8_t len )
702+ {
703+ #ifdef MIDI_SYSEX_DUMP
704+ Serial .printf ("SysExRecv (%d):\n" , len );
705+ for (int i = 0 ; i < len ; i ++ )
706+ {
707+ Serial .printf ("%02x" , buf [i ]);
708+ }
709+ Serial .printf ("\n" );
710+ #endif
711+ if (midiMapping .sysEx != NULL )
712+ {
713+ midiMapping .sysEx (buf , len );
714+ }
715+ }
716+ #endif
717+
619718/*
620719 * this function should be called continuously to ensure that incoming messages can be processed
621720 */
0 commit comments