]> git.donarmstrong.com Git - qmk_firmware.git/commitdiff
midi
authorJack Humbert <jack.humb@gmail.com>
Thu, 20 Aug 2015 04:42:08 +0000 (00:42 -0400)
committerJack Humbert <jack.humb@gmail.com>
Thu, 20 Aug 2015 04:42:08 +0000 (00:42 -0400)
keyboard/planck/Makefile
keyboard/planck/config.h
keyboard/planck/extended_keymap_common.h
keyboard/planck/extended_keymaps/extended_keymap_default.c
keyboard/planck/matrix_pcb.c
protocol/lufa.mk
protocol/lufa/descriptor.c
protocol/lufa/descriptor.h
protocol/lufa/lufa.c
protocol/lufa/lufa.h

index cd67c711bcbacc200bb9b67e300c14f3e620c282..7ea71af512c2f73e08722d6212a6e5fcd6a99246 100644 (file)
@@ -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)
index 7e95afddeabaedae4292af7e92ad115aa022dc19..4ac9f766e62ff05cf2fff6e79b282abb86ca0e89 100644 (file)
@@ -24,7 +24,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #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 */
index 2dce4a2fac9292789351cc3017cd747ac85507af..e6a7dac5b5a2ef9764de0d40f696fcab285586e2 100644 (file)
@@ -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);
 
index 1d5ac4321b039e04ed618b1772a57126f4f94fad..710611c3cbd5a0e05cfe9a014a85609358167a85 100644 (file)
@@ -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;
       } 
index 6f6ccd5c1cd8b545265f9cd2c55d922000f4c7fb..2a9ec8fcde3d2be20bfbfecf0066106b19af3f62 100644 (file)
@@ -78,6 +78,7 @@ void matrix_init(void)
     }
 }
 
+
 uint8_t matrix_scan(void)
 {
     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
index ac70ac03916639b906f562c6cc9a5d8f3d263a26..74a8bef3c6b639cef2c721a71cb28aadbcf727c4 100644 (file)
@@ -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)
 
index c13a81bda8cd6f68f14207f09ebabff6c991d36b..6eedd57000dbc3f7d08e078342903d26d33ced85 100644 (file)
@@ -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}
+        }
+
 };
 
 
index 42af07917c33f5795e538c40e7bf19c6d01d5269..58a7df44070278d3d1c3ed074103ef107e920617 100644 (file)
@@ -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,
index cdfc7bc6ad990bfd5a0031cb71dec93bbf99067c..d4c8eb1692af65d4aeacad024fc971873e49b13a 100644 (file)
@@ -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));
+}
index 195123c0f974f55a534ce716769e4358c0129554..505cb3279edcdaeb6e70e84cefff7839731d3bf9 100644 (file)
@@ -48,7 +48,7 @@
 #include <LUFA/Version.h>
 #include <LUFA/Drivers/USB/USB.h>
 #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 */