/** * Performs processing on incoming serial MIDI data from an attached * microcontroller. Incoming data is parsed for command and data bytes, * with a packet being transmitted to the host computer once the proper * combination of bytes have been received. */ void handle_MIDI_in(uint8_t b) { if (b & 0x80) { //Is this a command or data byte //New command byte. if (b == 0xF0) { //SysEx Begin command, handle as special case. current_cmd = 0xF0; data_ct = 1; packet_size = 3; MIDIpacket.Event = 0x04; MIDIpacket.Data1 = 0xF0; } else if (b == 0xF7) { //SysEx End message, also a special case if (data_ct == 0) { MIDIpacket.Event = 0x05; MIDIpacket.Data1 = 0xF7; } else if (data_ct == 1) { MIDIpacket.Event = 0x06; MIDIpacket.Data2 = 0xF7; } else { MIDIpacket.Event = 0x07; MIDIpacket.Data3 = 0xF7; } MIDI_Device_SendEventPacket(&Keyboard_MIDI_Interface,&MIDIpacket); MIDIpacket.Data1 = 0; MIDIpacket.Data2 = 0; MIDIpacket.Data3 = 0; current_cmd = 0x00; } else { current_cmd = b; data_ct = 0; //First, check for a System Common Message. if (b >= 0xF6) { //Single byte System Common Message, send it MIDIpacket.Event = 0x05; MIDIpacket.Data1 = b; MIDI_Device_SendEventPacket(&Keyboard_MIDI_Interface,&MIDIpacket); current_cmd = 0; } else if (b == 0xF3) { //Two byte System Common Message MIDIpacket.Event = 0x02; MIDIpacket.Data1 = b; packet_size = 1; } else if (b == 0xF2) { //The only three-byte System Common Message MIDIpacket.Event = 0x03; MIDIpacket.Data1 = b; packet_size = 2; } else { //Channel-specific Message current_cmd = b >> 4; data_ct = 0; packet_size = MIDI_PACKET_SIZE[current_cmd]; MIDIpacket.Event = current_cmd; MIDIpacket.Data1 = b; } } } else { //New Data byte if (current_cmd == 0x00)
void midi_stream_sysex (const uint8_t length, uint8_t* data) { // Assign this MIDI event to cable 0. const uint8_t midi_virtual_cable = 0; // 0x2 = 2-byte System Common // 0x3 = 3-byte System Common // 0x4 = 3-byte Sysex starts or continues // 0x5 = 1-byte System Common or Sysex ends // 0x6 = 2-byte Sysex ends // 0x7 = 3-byte Sysex ends midi_event.CableNumber = midi_virtual_cable << 4; uint8_t num = length;// + 1; bool first = true; while (num > 3) { midi_event.Command = 0x4; if (first) { first = false; midi_event.Data1 = *data++; } else { midi_event.Data1 = *data++; } midi_event.Data2 = *data++; midi_event.Data3 = *data++; MIDI_Device_SendEventPacket(g_midi_interface_info, &midi_event); num -= 3; } if (num) { midi_event.Command = 0x5; midi_event.Data1 = *data++; midi_event.Data2 = 0; midi_event.Data3 = 0; if (num == 2) { midi_event.Command = 0x6; midi_event.Data2 = *data++; } else if (num == 3) { if (first) { midi_event.Command = 0x3; } else { midi_event.Command = 0x7; } midi_event.Data2 = *data++; midi_event.Data3 = *data++; } MIDI_Device_SendEventPacket(g_midi_interface_info, &midi_event); } }
void MIDI_OUT(void) { if (complete == 1) { complete = 0; LEDs_TurnOnLEDs(LEDMASK_TX); uint8_t Channel = 0; MIDI_EventPacket_t MIDIEvent = (MIDI_EventPacket_t) { .CableNumber = 0, .Command = MIDI_FROM_ARDUINO.Data1 >> 4, .Data1 = MIDI_FROM_ARDUINO.Data1 | Channel, .Data2 = MIDI_FROM_ARDUINO.Data2, .Data3 = MIDI_FROM_ARDUINO.Data3, }; MIDI_Device_SendEventPacket(&MIDI_Interface, &MIDIEvent); MIDI_Device_Flush(&MIDI_Interface); } else {
void sendMidiNote(int button, bool on) { int command = (on) ? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF; MIDI_EventPacket_t MIDIEvent = (MIDI_EventPacket_t) { .Event = MIDI_EVENT(0, command), .Data1 = command | MIDI_CHANNEL(1), .Data2 = 60 + button, .Data3 = MIDI_STANDARD_VELOCITY, }; MIDI_Device_SendEventPacket(&tbase8_MIDI_Interface, &MIDIEvent); MIDI_Device_Flush(&tbase8_MIDI_Interface); } /** Configures the board hardware and chip peripherals for the demo's functionality. */ void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); wdt_disable(); /* Disable clock division */ clock_prescale_set(clock_div_1); /* Set the port directions for port b and d */ DDRD = 0xFF; DDRB = 0xFF; PORTD = 0b01010101; PORTB = 0b01010101; /* Hardware Initialization */ USB_Init(); }
void usb_send_func(MidiDevice * device, uint8_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { MIDI_EventPacket_t event; event.CableNumber = 0; event.Data1 = byte0; event.Data2 = byte1; event.Data3 = byte2; //if the length is undefined we assume it is a SYSEX message if (midi_packet_length(byte0) == UNDEFINED) { switch(cnt) { case 3: if (byte2 == SYSEX_END) event.Command = SYSEX_ENDS_IN_3; else event.Command = SYSEX_START_OR_CONT; break; case 2: if (byte1 == SYSEX_END) event.Command = SYSEX_ENDS_IN_2; else event.Command = SYSEX_START_OR_CONT; break; case 1: if (byte0 == SYSEX_END) event.Command = SYSEX_ENDS_IN_1; else event.Command = SYSEX_START_OR_CONT; break; default: return; //invalid cnt } } else { //deal with 'system common' messages //TODO are there any more? switch(byte0 & 0xF0){ case MIDI_SONGPOSITION: event.Command = SYS_COMMON_3; break; case MIDI_SONGSELECT: case MIDI_TC_QUATERFRAME: event.Command = SYS_COMMON_2; break; default: event.Command = byte0 >> 4; break; } } MIDI_Device_SendEventPacket(&USB_MIDI_Interface, &event); MIDI_Device_Flush(&USB_MIDI_Interface); MIDI_Device_USBTask(&USB_MIDI_Interface); USB_USBTask(); }
void midi_stream_raw_cc(const uint8_t channel, const uint8_t cc, const uint8_t value) { const uint8_t command = 0xb0; // the Channel Change command. MIDI_EventPacket_t midi_event; midi_event.CableNumber = 0x0; // USB-MIDI virtual cable (0..15) midi_event.Command = command >> 4; midi_event.Data1 = command | (channel & 0x0f); // 0..15 midi_event.Data2 = cc & 0x7f; // 0..127 midi_event.Data3 = value & 0x7f; // 0..127 MIDI_Device_SendEventPacket(g_midi_interface_info, &midi_event); }
// Append a Control Change Event to the currently selected USB Endpoint. If // the endpoint is full it will be flushed. // // controller Number of the controller to alter. // value Value to send to the CC. // void midi_stream_cc(const uint8_t controller, const uint8_t value) { // Assign this MIDI event to cable 0. const uint8_t midi_virtual_cable = 0; const uint8_t command = 0xb0; // the Channel Change command. midi_event.CableNumber = midi_virtual_cable << 4; midi_event.Command = command >> 4; midi_event.Data1 = command | (g_midi_channel & 0x0f); // 0..15 midi_event.Data2 = controller & 0x7f; // 0..127 midi_event.Data3 = value & 0x7f; // 0..127 MIDI_Device_SendEventPacket(g_midi_interface_info, &midi_event); }
// Used to send a note on a specific channel void midi_stream_note_ch(const uint8_t channel, const uint8_t pitch, const bool onoff) { // Check if the message should be a NoteOn or NoteOff event. uint8_t command = ((onoff)? 0x90 : 0x80); // Assemble a USB-MIDI event packet, remembering to mask off the values // to the correct bit fields. MIDI_EventPacket_t midi_event; midi_event.CableNumber = 0x0; // USB-MIDI virtual cable (0..15) midi_event.Command = command >> 4; // 0..15 midi_event.Data1 = command | (channel & 0x0f); // 0..15 midi_event.Data2 = pitch & 0x7f; // 0..127 midi_event.Data3 = g_midi_velocity & 0x7f; // 0..127 MIDI_Device_SendEventPacket(g_midi_interface_info, &midi_event); }
// Append a MIDI note change event (note on or off) to the currently // selected USB endpoint. If the endpoint is full it will be flushed. // // pitch Pitch of the note to turn on or off. // onoff True for a NoteOn, false for a NoteOff. // // NOTE: The endpoint can contain 64 bytes and each MIDI-USB message is 4 // bytes giving us just enough space to fit in, for example, 16 keydown // messages. // void midi_stream_note(const uint8_t pitch, const bool onoff) { // Each USB-MIDI endpoint can have up to 16 virtual cables each // with 16 MIDI channels. Assign everything to cable 0 for now. const uint8_t midi_virtual_cable = 0; // Check if the message should be a NoteOn or NoteOff event. uint8_t command = ((onoff)? 0x90 : 0x80); // Assemble a USB-MIDI event packet, remembering to mask off the values // to the correct bit fields. midi_event.CableNumber = midi_virtual_cable & 0x0f; //0..15 midi_event.Command = command >> 4; // 0..15 midi_event.Data1 = command | (g_midi_channel & 0x0f); // 0..15 midi_event.Data2 = pitch & 0x7f; // 0..127 midi_event.Data3 = g_midi_velocity & 0x7f; // 0..127 MIDI_Device_SendEventPacket(g_midi_interface_info, &midi_event); }
/** Checks for changes in the position of the board joystick, sending MIDI events to the host upon each change. */ void CheckJoystickMovement(void) { static uint8_t PrevJoystickStatus; uint8_t MIDICommand = 0; uint8_t MIDIPitch; /* Get current joystick mask, XOR with previous to detect joystick changes */ uint8_t JoystickStatus = Joystick_GetStatus(); uint8_t JoystickChanges = (JoystickStatus ^ PrevJoystickStatus); /* Get board button status - if pressed use second virtual cable, otherwise use the first */ uint8_t VirtualCable = (Buttons_GetStatus() & BUTTONS_BUTTON1) ? 1 : 0; if (JoystickChanges & JOY_LEFT) { MIDICommand = ((JoystickStatus & JOY_LEFT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3C; } if (JoystickChanges & JOY_UP) { MIDICommand = ((JoystickStatus & JOY_UP)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3D; } if (JoystickChanges & JOY_RIGHT) { MIDICommand = ((JoystickStatus & JOY_RIGHT)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3E; } if (JoystickChanges & JOY_DOWN) { MIDICommand = ((JoystickStatus & JOY_DOWN)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3F; } if (JoystickChanges & JOY_PRESS) { MIDICommand = ((JoystickStatus & JOY_PRESS)? MIDI_COMMAND_NOTE_ON : MIDI_COMMAND_NOTE_OFF); MIDIPitch = 0x3B; } if (MIDICommand) { MIDI_EventPacket_t MIDIEvent = (MIDI_EventPacket_t) { .Event = MIDI_EVENT(VirtualCable, MIDICommand), .Data1 = MIDICommand | MIDI_CHANNEL(1), .Data2 = MIDIPitch, .Data3 = MIDI_STANDARD_VELOCITY, }; MIDI_Device_SendEventPacket(&Keyboard_MIDI_Interface, &MIDIEvent); MIDI_Device_Flush(&Keyboard_MIDI_Interface); } PrevJoystickStatus = JoystickStatus; } /** Event handler for the library USB Connection event. */ void EVENT_USB_Device_Connect(void) { LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); }
/** Main program entry point. This routine contains the overall program flow, including initial * setup of all components and the main program loop. */ int main(void) { MIDI_EventPacket_t midiEvent; struct { uint8_t command; uint8_t channel; uint8_t data2; uint8_t data3; } midiMsg; int ind; int led1_ticks = 0; int led2_ticks = 0; SetupHardware(); RingBuffer_InitBuffer(&USBtoUSART_Buffer); RingBuffer_InitBuffer(&USARTtoUSB_Buffer); LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); sei(); for (;;) { RingBuff_Count_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer); /* See if we have a message yet */ if (BufferCount >= 4) { /* Read in the message from the serial buffer */ for (ind=0; ind<4; ind++) { ((uint8_t *)&midiMsg)[ind] = RingBuffer_Remove(&USARTtoUSB_Buffer); } /* Build a midi event to send via USB */ midiEvent.CableNumber = 0; midiEvent.Command = midiMsg.command >> 4; midiEvent.Data1 = (midiMsg.command & 0xF0) | ((midiMsg.channel-1) & 0x0F); midiEvent.Data2 = midiMsg.data2; midiEvent.Data3 = midiMsg.data3; MIDI_Device_SendEventPacket(&Keyboard_MIDI_Interface, &midiEvent); MIDI_Device_Flush(&Keyboard_MIDI_Interface); /* Turn on the TX led and starts its timer */ LEDs_TurnOnLEDs(LEDS_LED1); led1_ticks = LED_ON_TICKS; } /* Turn off the Tx LED when the tick count reaches zero */ if (led1_ticks) { led1_ticks--; if (led1_ticks == 0) { LEDs_TurnOffLEDs(LEDS_LED1); } } if (MIDI_Device_ReceiveEventPacket(&Keyboard_MIDI_Interface, &midiEvent)) { RingBuff_Count_t count = RingBuffer_GetCount(&USBtoUSART_Buffer); /* Room to send a message? */ if ((BUFFER_SIZE - count) >= sizeof(midiMsg)) { midiMsg.command = midiEvent.Command << 4; midiMsg.channel = (midiEvent.Data1 & 0x0F) + 1; midiMsg.data2 = midiEvent.Data2; midiMsg.data3 = midiEvent.Data3; for (ind=0; ind<sizeof(midiMsg); ind++) { RingBuffer_Insert(&USBtoUSART_Buffer, ((uint8_t *)&midiMsg)[ind]); } /* Turn on the RX led and start its timer */ LEDs_TurnOnLEDs(LEDS_LED2); led2_ticks = LED_ON_TICKS; } else { /* Turn on the RX led and leave it on to indicate the * buffer is full and the sketch is not reading it * fast enough. */ LEDs_TurnOnLEDs(LEDS_LED2); } /* if there's no room in the serial buffer the message gets dropped */ } /* Turn off the RX LED when the tick count reaches zero */ if (led2_ticks) { led2_ticks--; if (led2_ticks == 0) { LEDs_TurnOffLEDs(LEDS_LED2); } } /* any data to send to main processor? */ if (!(RingBuffer_IsEmpty(&USBtoUSART_Buffer))) { Serial_TxByte(RingBuffer_Remove(&USBtoUSART_Buffer)); } MIDI_Device_USBTask(&Keyboard_MIDI_Interface); USB_USBTask(); } }