From e528087ee539fda2f13795d4a6c03403faef44d5 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Thu, 20 Aug 2015 00:42:08 -0400 Subject: [PATCH] midi --- keyboard/planck/Makefile | 2 +- keyboard/planck/config.h | 2 +- keyboard/planck/extended_keymap_common.h | 1 + .../extended_keymap_default.c | 13 +- keyboard/planck/matrix_pcb.c | 1 + protocol/lufa.mk | 7 +- protocol/lufa/descriptor.c | 158 +++++++++++++++ protocol/lufa/descriptor.h | 23 ++- protocol/lufa/lufa.c | 191 +++++++++++++++++- protocol/lufa/lufa.h | 3 +- 10 files changed, 392 insertions(+), 9 deletions(-) diff --git a/keyboard/planck/Makefile b/keyboard/planck/Makefile index cd67c711b..7ea71af51 100644 --- a/keyboard/planck/Makefile +++ b/keyboard/planck/Makefile @@ -75,7 +75,7 @@ SRC = extended_keymap_common.c \ $(MATRIX) \ led.c \ backlight.c \ - beeps.c + beeps.c ifdef KEYMAP SRC := extended_keymaps/extended_keymap_$(KEYMAP).c $(SRC) diff --git a/keyboard/planck/config.h b/keyboard/planck/config.h index 7e95afdde..4ac9f766e 100644 --- a/keyboard/planck/config.h +++ b/keyboard/planck/config.h @@ -24,7 +24,7 @@ along with this program. If not, see . #define PRODUCT_ID 0x6060 #define DEVICE_VER 0x0001 #define MANUFACTURER Ortholinear Keyboards -#define PRODUCT Planck +#define PRODUCT The Planck Keyboard #define DESCRIPTION A compact ortholinear keyboard /* key matrix size */ diff --git a/keyboard/planck/extended_keymap_common.h b/keyboard/planck/extended_keymap_common.h index 2dce4a2fa..e6a7dac5b 100644 --- a/keyboard/planck/extended_keymap_common.h +++ b/keyboard/planck/extended_keymap_common.h @@ -48,6 +48,7 @@ typedef union { keymap_config_t keymap_config; #endif + /* translates key to keycode */ uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); diff --git a/keyboard/planck/extended_keymaps/extended_keymap_default.c b/keyboard/planck/extended_keymaps/extended_keymap_default.c index 1d5ac4321..710611c3c 100644 --- a/keyboard/planck/extended_keymaps/extended_keymap_default.c +++ b/keyboard/planck/extended_keymaps/extended_keymap_default.c @@ -1,5 +1,6 @@ #include "extended_keymap_common.h" #include "backlight.h" +#include "lufa.h" const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [0] = { /* Qwerty */ @@ -50,10 +51,18 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) switch(id) { case 0: if (record->event.pressed) { - register_code(KC_RSFT); + if (!&midi_device) { + register_code(KC_RSFT); + } else { + midi_send_noteon(&midi_device, 1, 64, 127); + } backlight_step(); } else { - unregister_code(KC_RSFT); + if (!&midi_device) { + unregister_code(KC_RSFT); + } else { + midi_send_noteoff(&midi_device, 1, 64, 127); + } } break; } diff --git a/keyboard/planck/matrix_pcb.c b/keyboard/planck/matrix_pcb.c index 6f6ccd5c1..2a9ec8fcd 100644 --- a/keyboard/planck/matrix_pcb.c +++ b/keyboard/planck/matrix_pcb.c @@ -78,6 +78,7 @@ void matrix_init(void) } } + uint8_t matrix_scan(void) { for (uint8_t i = 0; i < MATRIX_ROWS; i++) { diff --git a/protocol/lufa.mk b/protocol/lufa.mk index ac70ac039..74a8bef3c 100644 --- a/protocol/lufa.mk +++ b/protocol/lufa.mk @@ -19,7 +19,12 @@ endif LUFA_SRC = $(LUFA_DIR)/lufa.c \ $(LUFA_DIR)/descriptor.c \ - $(LUFA_SRC_USB) + $(LUFA_SRC_USB) \ + $(LUFA_DIR)/midi/midi.c \ + $(LUFA_DIR)/midi/midi_device.c \ + $(LUFA_DIR)/midi/bytequeue/bytequeue.c \ + $(LUFA_DIR)/midi/bytequeue/interrupt_setting.c \ + $(LUFA_DIR)/LUFA-git/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c SRC += $(LUFA_SRC) diff --git a/protocol/lufa/descriptor.c b/protocol/lufa/descriptor.c index c13a81bda..6eedd5700 100644 --- a/protocol/lufa/descriptor.c +++ b/protocol/lufa/descriptor.c @@ -486,6 +486,164 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .PollingIntervalMS = 0x01 }, #endif + + .Audio_ControlInterface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = (NKRO_INTERFACE + 1), + .AlternateSetting = 0, + + .TotalEndpoints = 0, + + .Class = AUDIO_CSCP_AudioClass, + .SubClass = AUDIO_CSCP_ControlSubclass, + .Protocol = AUDIO_CSCP_ControlProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .Audio_ControlInterface_SPC = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_Interface_AC_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_Header, + + .ACSpecification = VERSION_BCD(1,1,1), + .TotalLength = sizeof(USB_Audio_Descriptor_Interface_AC_t), + + .InCollection = 1, + .InterfaceNumber = (NKRO_INTERFACE + 2), + }, + + .Audio_StreamInterface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = (NKRO_INTERFACE + 2), + .AlternateSetting = 0, + + .TotalEndpoints = 2, + + .Class = AUDIO_CSCP_AudioClass, + .SubClass = AUDIO_CSCP_MIDIStreamingSubclass, + .Protocol = AUDIO_CSCP_StreamingProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .Audio_StreamInterface_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_AudioInterface_AS_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_General, + + .AudioSpecification = VERSION_BCD(1,1,1), + + .TotalLength = (sizeof(USB_Descriptor_Configuration_t) - + offsetof(USB_Descriptor_Configuration_t, Audio_StreamInterface_SPC)) + }, + + .MIDI_In_Jack_Emb = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal, + + .JackType = MIDI_JACKTYPE_Embedded, + .JackID = 0x01, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_In_Jack_Ext = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_InputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_InputTerminal, + + .JackType = MIDI_JACKTYPE_External, + .JackID = 0x02, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_Out_Jack_Emb = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal, + + .JackType = MIDI_JACKTYPE_Embedded, + .JackID = 0x03, + + .NumberOfPins = 1, + .SourceJackID = {0x02}, + .SourcePinID = {0x01}, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_Out_Jack_Ext = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_OutputJack_t), .Type = DTYPE_CSInterface}, + .Subtype = AUDIO_DSUBTYPE_CSInterface_OutputTerminal, + + .JackType = MIDI_JACKTYPE_External, + .JackID = 0x04, + + .NumberOfPins = 1, + .SourceJackID = {0x01}, + .SourcePinID = {0x01}, + + .JackStrIndex = NO_DESCRIPTOR + }, + + .MIDI_In_Jack_Endpoint = + { + .Endpoint = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM), + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = MIDI_STREAM_EPSIZE, + .PollingIntervalMS = 0x01 + }, + + .Refresh = 0, + .SyncEndpointNumber = 0 + }, + + .MIDI_In_Jack_Endpoint_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint}, + .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, + + .TotalEmbeddedJacks = 0x01, + .AssociatedJackID = {0x01} + }, + + .MIDI_Out_Jack_Endpoint = + { + .Endpoint = + { + .Header = {.Size = sizeof(USB_Audio_Descriptor_StreamEndpoint_Std_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM), + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = MIDI_STREAM_EPSIZE, + .PollingIntervalMS = 0x01 + }, + + .Refresh = 0, + .SyncEndpointNumber = 0 + }, + + .MIDI_Out_Jack_Endpoint_SPC = + { + .Header = {.Size = sizeof(USB_MIDI_Descriptor_Jack_Endpoint_t), .Type = DTYPE_CSEndpoint}, + .Subtype = AUDIO_DSUBTYPE_CSEndpoint_General, + + .TotalEmbeddedJacks = 0x01, + .AssociatedJackID = {0x03} + } + }; diff --git a/protocol/lufa/descriptor.h b/protocol/lufa/descriptor.h index 42af07917..58a7df440 100644 --- a/protocol/lufa/descriptor.h +++ b/protocol/lufa/descriptor.h @@ -85,6 +85,23 @@ typedef struct USB_HID_Descriptor_HID_t NKRO_HID; USB_Descriptor_Endpoint_t NKRO_INEndpoint; #endif + + // MIDI Audio Control Interface + USB_Descriptor_Interface_t Audio_ControlInterface; + USB_Audio_Descriptor_Interface_AC_t Audio_ControlInterface_SPC; + + // MIDI Audio Streaming Interface + USB_Descriptor_Interface_t Audio_StreamInterface; + USB_MIDI_Descriptor_AudioInterface_AS_t Audio_StreamInterface_SPC; + USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Emb; + USB_MIDI_Descriptor_InputJack_t MIDI_In_Jack_Ext; + USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Emb; + USB_MIDI_Descriptor_OutputJack_t MIDI_Out_Jack_Ext; + USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_In_Jack_Endpoint; + USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_In_Jack_Endpoint_SPC; + USB_Audio_Descriptor_StreamEndpoint_Std_t MIDI_Out_Jack_Endpoint; + USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_Out_Jack_Endpoint_SPC; + } USB_Descriptor_Configuration_t; @@ -117,7 +134,7 @@ typedef struct /* nubmer of interfaces */ -#define TOTAL_INTERFACES (NKRO_INTERFACE + 1) +#define TOTAL_INTERFACES (NKRO_INTERFACE + 3) // Endopoint number and size @@ -150,12 +167,16 @@ typedef struct # endif #endif +#define MIDI_STREAM_IN_EPNUM (NKRO_IN_EPNUM + 1) +#define MIDI_STREAM_OUT_EPNUM (NKRO_IN_EPNUM + 1) + #define KEYBOARD_EPSIZE 8 #define MOUSE_EPSIZE 8 #define EXTRAKEY_EPSIZE 8 #define CONSOLE_EPSIZE 32 #define NKRO_EPSIZE 16 +#define MIDI_STREAM_EPSIZE 64 uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c index cdfc7bc6a..d4c8eb169 100644 --- a/protocol/lufa/lufa.c +++ b/protocol/lufa/lufa.c @@ -52,6 +52,7 @@ #include "descriptor.h" #include "lufa.h" + uint8_t keyboard_idle = 0; uint8_t keyboard_protocol = 1; static uint8_t keyboard_led_stats = 0; @@ -65,14 +66,51 @@ static void send_keyboard(report_keyboard_t *report); static void send_mouse(report_mouse_t *report); static void send_system(uint16_t data); static void send_consumer(uint16_t data); +void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); +void usb_get_midi(MidiDevice * device); +void midi_usb_init(MidiDevice * device); host_driver_t lufa_driver = { keyboard_leds, send_keyboard, send_mouse, send_system, - send_consumer + send_consumer, + usb_send_func, + usb_get_midi, + midi_usb_init }; +void SetupHardware(void); + +USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface = +{ + .Config = + { + .StreamingInterfaceNumber = 1, + .DataINEndpoint = + { + .Address = (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM), + .Size = MIDI_STREAM_EPSIZE, + .Banks = 1, + }, + .DataOUTEndpoint = + { + .Address = (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM), + .Size = MIDI_STREAM_EPSIZE, + .Banks = 1, + }, + }, +}; + +#define SYSEX_START_OR_CONT 0x40 +#define SYSEX_ENDS_IN_1 0x50 +#define SYSEX_ENDS_IN_2 0x60 +#define SYSEX_ENDS_IN_3 0x70 + +#define SYS_COMMON_1 0x50 +#define SYS_COMMON_2 0x20 +#define SYS_COMMON_3 0x30 + /******************************************************************************* * Console @@ -240,8 +278,13 @@ void EVENT_USB_Device_ConfigurationChanged(void) ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, NKRO_EPSIZE, ENDPOINT_BANK_SINGLE); #endif + + + ConfigSuccess &= MIDI_Device_ConfigureEndpoints(&USB_MIDI_Interface); } + + /* Appendix G: HID Request Support Requirements @@ -263,6 +306,8 @@ void EVENT_USB_Device_ControlRequest(void) uint8_t* ReportData = NULL; uint8_t ReportSize = 0; + MIDI_Device_ProcessControlRequest(&USB_MIDI_Interface); + /* Handle HID Class specific requests */ switch (USB_ControlRequest.bRequest) { @@ -541,10 +586,109 @@ int8_t sendchar(uint8_t c) #endif + + + +void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { + MIDI_EventPacket_t event; + 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.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_3); + else + event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT); + break; + case 2: + if (byte1 == SYSEX_END) + event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_2); + else + event.Event = MIDI_EVENT(0, SYSEX_START_OR_CONT); + break; + case 1: + if (byte0 == SYSEX_END) + event.Event = MIDI_EVENT(0, SYSEX_ENDS_IN_1); + else + event.Event = MIDI_EVENT(0, 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.Event = MIDI_EVENT(0, SYS_COMMON_3); + break; + case MIDI_SONGSELECT: + case MIDI_TC_QUARTERFRAME: + event.Event = MIDI_EVENT(0, SYS_COMMON_2); + break; + default: + event.Event = MIDI_EVENT(0, byte0); + break; + } + } + + MIDI_Device_SendEventPacket(&USB_MIDI_Interface, &event); + MIDI_Device_Flush(&USB_MIDI_Interface); + MIDI_Device_USBTask(&USB_MIDI_Interface); + USB_USBTask(); +} + +void usb_get_midi(MidiDevice * device) { + MIDI_EventPacket_t event; + while (MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, &event)) { + + midi_packet_length_t length = midi_packet_length(event.Data1); + uint8_t input[3]; + input[0] = event.Data1; + input[1] = event.Data2; + input[2] = event.Data3; + if (length == UNDEFINED) { + //sysex + if (event.Event == MIDI_EVENT(0, SYSEX_START_OR_CONT) || event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_3)) { + length = 3; + } else if (event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_2)) { + length = 2; + } else if(event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_1)) { + length = 1; + } else { + //XXX what to do? + } + } + + //pass the data to the device input function + if (length != UNDEFINED) + midi_device_input(device, length, input); + } + MIDI_Device_USBTask(&USB_MIDI_Interface); + USB_USBTask(); +} + +void midi_usb_init(MidiDevice * device){ + midi_device_init(device); + midi_device_set_send_func(device, usb_send_func); + midi_device_set_pre_input_process_func(device, usb_get_midi); + + SetupHardware(); + sei(); +} + + + + + /******************************************************************************* * main ******************************************************************************/ -static void SetupHardware(void) +void SetupHardware(void) { /* Disable watchdog if enabled by bootloader/fuses */ MCUSR &= ~(1 << WDRF); @@ -563,12 +707,34 @@ static void SetupHardware(void) print_set_sendchar(sendchar); } +void fallthrough_callback(MidiDevice * device, + uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); +void cc_callback(MidiDevice * device, + uint8_t chan, uint8_t num, uint8_t val); +void sysex_callback(MidiDevice * device, + uint16_t start, uint8_t length, uint8_t * data); + int main(void) __attribute__ ((weak)); int main(void) { + //setup the device + + midi_device_init(&midi_device); + midi_device_set_send_func(&midi_device, usb_send_func); + midi_device_set_pre_input_process_func(&midi_device, usb_get_midi); + SetupHardware(); sei(); + midi_register_fallthrough_callback(&midi_device, fallthrough_callback); + midi_register_cc_callback(&midi_device, cc_callback); + midi_register_sysex_callback(&midi_device, sysex_callback); + + midi_send_cc(&midi_device, 0, 1, 2); + midi_send_cc(&midi_device, 15, 1, 0); + midi_send_noteon(&midi_device, 0, 64, 127); + midi_send_noteoff(&midi_device, 0, 64, 127); + /* wait for USB startup & debug output */ while (USB_DeviceState != DEVICE_STATE_Configured) { #if defined(INTERRUPT_CONTROL_ENDPOINT) @@ -598,8 +764,29 @@ int main(void) keyboard_task(); + midi_device_process(&midi_device); + #if !defined(INTERRUPT_CONTROL_ENDPOINT) USB_USBTask(); #endif } } + +//echo data back +void fallthrough_callback(MidiDevice * device, + uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){ + //pass the data back to the device, using the general purpose send data + //function, any bytes after cnt are ignored +} + +void cc_callback(MidiDevice * device, + uint8_t chan, uint8_t num, uint8_t val) { + //sending it back on the next channel + midi_send_cc(device, (chan + 1) % 16, num, val); +} + +void sysex_callback(MidiDevice * device, + uint16_t start, uint8_t length, uint8_t * data) { + for (int i = 0; i < length; i++) + midi_send_cc(device, 15, 0x7F & data[i], 0x7F & (start + i)); +} diff --git a/protocol/lufa/lufa.h b/protocol/lufa/lufa.h index 195123c0f..505cb3279 100644 --- a/protocol/lufa/lufa.h +++ b/protocol/lufa/lufa.h @@ -48,7 +48,7 @@ #include #include #include "host.h" - +#include "midi/midi.h" #ifdef __cplusplus extern "C" { @@ -66,6 +66,7 @@ typedef struct { uint16_t usage; } __attribute__ ((packed)) report_extra_t; +MidiDevice midi_device; #if LUFA_VERSION_INTEGER < 0x120730 /* old API 120219 */