MIDI Sniffer
- The purpose of this program is parsing MIDI messages sent from a master keyboard.
- Messages are then written on a serial terminal ( and by the way passed through )
Architecture
- MIDI frames are the same as RS232, with a special rate of 31250 bauds.
- UART6 is used for midi messages, UART2 is used to write on a PC terminal.
Assembly Instructions
- Plug the midi shield on the nucleo F411.
- Connect the RX and TX MIDI shield to Nucleo F411 UART6-RX and UART6-TX.
Capturing and Analyzing a midi message
If we press e key on a master keyboard, the following message is sent ( Saleae Capture ) :
- NOTE ON : [ 0x90] [ 0x30 ] [ 0x40 ] : [ Type = Note_on + Channel = 1 ] [ note = C5 ] [ Velocity = 0x40 ]
When the key is released :
- NOTE OFF : [ 0x80] [ 0x30 ] [ 0x61 ] : [ Type = Note_off + Channel = 1 ] [ note = C5 ] [ Velocity = 0x61 ]
Look at midi.org for further specifications.
Algorithm
int main(void)
{
uint16_t val;
uint8_t mess_to_send[3];
HAL_Init();
SystemClock_Config();
uart2_Init(); // CABLE VCOM
uart6_Init(); // CABLE MIDI
HAL_Delay(500);
while(1)
{
if(MIDI_receive())
{
switch (midi_mess.type)
{
case NOTE_ON : term_printf("NOTE ON, channel : %d, Note : %d, Velocity : %d \n\r",midi_mess.channel, midi_mess.data1, midi_mess.data2);
mess_to_send[0] = midi_mess.type | ( midi_mess.channel -1 );
mess_to_send[1] = midi_mess.data1;
mess_to_send[2] = midi_mess.data2;
MIDI_send(mess_to_send , 3); // MIDI THROUGH
break;
...
case PROGRAM_CHANGE:
term_printf("PRG CHANGE, channel : %d, Value : %d \n\r",midi_mess.channel,midi_mess.data1);
mess_to_send[0] = midi_mess.type | ( midi_mess.channel -1 );
mess_to_send[1] = midi_mess.data1;
MIDI_send(mess_to_send , 3);
break;
case RESET : term_printf("RESET \n\r");
mess_to_send[0] = midi_mess.type;
MIDI_send(mess_to_send , 3);
break;
default : break ;
}
}
}
return 0;
}
When a byte is received on UART6, a receive interrupt occurs.
The MIDI_rcv_cb() callback function updates MIDI_buf .
|
|
In the main program, we call continuously MIDI_receive() function. MIDI_receive() evaluates the size of the received message, and then looking at the type, manages (or not) to parse the message.
The parsed message is recorded in the MIDI_mess structure.
Message parsed is then displayed on the terminal.
Some messages can be 1 byte , 2 bytes or 3 bytes long.
In addition we can consider a delay between several messages received and the MIDI_receive() function.
The complete algorithm of MIDI_receive() is :