diff options
| author | fredizzimo <fsundvik@gmail.com> | 2018-02-08 22:07:46 +0200 |
|---|---|---|
| committer | Jack Humbert <jack.humb@gmail.com> | 2018-02-08 15:07:46 -0500 |
| commit | 53ff8a31b61952d9675558149d927f7942071df9 (patch) | |
| tree | a57b9e6f7d6494c9ef903f886a660dd43f4e5044 /tmk_core/protocol/midi | |
| parent | 63c16f4b632a2a82a775f51a3ad0cc690cca1fc9 (diff) | |
| download | qmk_firmware-53ff8a31b61952d9675558149d927f7942071df9.tar.gz qmk_firmware-53ff8a31b61952d9675558149d927f7942071df9.zip | |
Merge ChibiOS and LUFA descriptor support (#2362)
* Move lufa descriptor to protocol/usb_descriptor
* Try to compile usb_descriptor on ChibiOS
* Add lufa_utils for ChibiOS
Lufa USB descriptors for ChibiOS
* More lufa_util compatibility fixes
* First compiling version of shared USB descriptor
* Send the usb descriptors
* Fix the CONSOLE output on ChibiOS
* Add errors for unsupported interfaces
* Enable support for vitual serial port USB descriptors
* Implement virtual serial port for ChibiOS
* Cleanup the lufa_utils
Use the default lufa header files
* Add raw hid support for ChibiOS
This is completely untested
* Enable midi compilation on ChibiOS
* Move midi functionality out of lufa.c
* Don't register sysex callback when not needed
* ChibiOS compilation fixes
* Update ChibiOS submodule
* Fix the Midi USB descriptor
It didn't work properly when both Midi and Virtual serial port was enabled.
* Add MIDI support for ChibiOS
* Fix USB descriptor strings on ChibiOS
* Use serial usb driver for raw hid
* Generalize the ChibiOS stream like drivers
This makes the initialization much more simple and eliminates a lot of
the code duplication.
* Convert console output to chibios stream driver
* Fixes for ChibiOS update
* Update the ChibiOS contrib submodule
To include the usb data toggle synchronization fixes
* Fix duplicate reset enumeration on ChibiOS
* Add missing include
* Add number of endpoints check for ChibiOS
* Enable serial USB driver on all keyboards
* Add missing includes when API is enabled withot midi
* Add another missing inlcude
Diffstat (limited to 'tmk_core/protocol/midi')
| -rwxr-xr-x | tmk_core/protocol/midi/bytequeue/interrupt_setting.c | 15 | ||||
| -rw-r--r-- | tmk_core/protocol/midi/qmk_midi.c | 184 | ||||
| -rw-r--r-- | tmk_core/protocol/midi/qmk_midi.h | 9 |
3 files changed, 207 insertions, 1 deletions
diff --git a/tmk_core/protocol/midi/bytequeue/interrupt_setting.c b/tmk_core/protocol/midi/bytequeue/interrupt_setting.c index eafef527c..0ab8b5462 100755 --- a/tmk_core/protocol/midi/bytequeue/interrupt_setting.c +++ b/tmk_core/protocol/midi/bytequeue/interrupt_setting.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | //Copyright 20010 Alex Norman | 1 | //Copyright 20010 Alex Norman |
| 2 | //writen by Alex Norman | 2 | //writen by Alex Norman |
| 3 | // | 3 | // |
| 4 | //This file is part of avr-bytequeue. | 4 | //This file is part of avr-bytequeue. |
| 5 | // | 5 | // |
| @@ -22,6 +22,7 @@ | |||
| 22 | //implementations of the typedef and these functions | 22 | //implementations of the typedef and these functions |
| 23 | 23 | ||
| 24 | #include "interrupt_setting.h" | 24 | #include "interrupt_setting.h" |
| 25 | #if defined(__AVR__) | ||
| 25 | #include <avr/interrupt.h> | 26 | #include <avr/interrupt.h> |
| 26 | 27 | ||
| 27 | interrupt_setting_t store_and_clear_interrupt(void) { | 28 | interrupt_setting_t store_and_clear_interrupt(void) { |
| @@ -33,4 +34,16 @@ interrupt_setting_t store_and_clear_interrupt(void) { | |||
| 33 | void restore_interrupt_setting(interrupt_setting_t setting) { | 34 | void restore_interrupt_setting(interrupt_setting_t setting) { |
| 34 | SREG = setting; | 35 | SREG = setting; |
| 35 | } | 36 | } |
| 37 | #elif defined(__arm__) | ||
| 38 | #include "ch.h" | ||
| 39 | |||
| 40 | interrupt_setting_t store_and_clear_interrupt(void) { | ||
| 41 | chSysLock(); | ||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | void restore_interrupt_setting(interrupt_setting_t setting) { | ||
| 46 | chSysUnlock(); | ||
| 47 | } | ||
| 48 | #endif | ||
| 36 | 49 | ||
diff --git a/tmk_core/protocol/midi/qmk_midi.c b/tmk_core/protocol/midi/qmk_midi.c new file mode 100644 index 000000000..d4de6caa7 --- /dev/null +++ b/tmk_core/protocol/midi/qmk_midi.c | |||
| @@ -0,0 +1,184 @@ | |||
| 1 | #include <LUFA/Drivers/USB/USB.h> | ||
| 2 | #include "qmk_midi.h" | ||
| 3 | #include "sysex_tools.h" | ||
| 4 | #include "midi.h" | ||
| 5 | #include "usb_descriptor.h" | ||
| 6 | #include "process_midi.h" | ||
| 7 | #if API_SYSEX_ENABLE | ||
| 8 | #include "api.h" | ||
| 9 | #endif | ||
| 10 | |||
| 11 | /******************************************************************************* | ||
| 12 | * MIDI | ||
| 13 | ******************************************************************************/ | ||
| 14 | |||
| 15 | MidiDevice midi_device; | ||
| 16 | |||
| 17 | #define SYSEX_START_OR_CONT 0x40 | ||
| 18 | #define SYSEX_ENDS_IN_1 0x50 | ||
| 19 | #define SYSEX_ENDS_IN_2 0x60 | ||
| 20 | #define SYSEX_ENDS_IN_3 0x70 | ||
| 21 | |||
| 22 | #define SYS_COMMON_1 0x50 | ||
| 23 | #define SYS_COMMON_2 0x20 | ||
| 24 | #define SYS_COMMON_3 0x30 | ||
| 25 | |||
| 26 | static void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { | ||
| 27 | MIDI_EventPacket_t event; | ||
| 28 | event.Data1 = byte0; | ||
| 29 | event.Data2 = byte1; | ||
| 30 | event.Data3 = byte2; | ||
| 31 | |||
| 32 | uint8_t cable = 0; | ||
| 33 | |||
| 34 | //if the length is undefined we assume it is a SYSEX message | ||
| 35 | if (midi_packet_length(byte0) == UNDEFINED) { | ||
| 36 | switch(cnt) { | ||
| 37 | case 3: | ||
| 38 | if (byte2 == SYSEX_END) | ||
| 39 | event.Event = MIDI_EVENT(cable, SYSEX_ENDS_IN_3); | ||
| 40 | else | ||
| 41 | event.Event = MIDI_EVENT(cable, SYSEX_START_OR_CONT); | ||
| 42 | break; | ||
| 43 | case 2: | ||
| 44 | if (byte1 == SYSEX_END) | ||
| 45 | event.Event = MIDI_EVENT(cable, SYSEX_ENDS_IN_2); | ||
| 46 | else | ||
| 47 | event.Event = MIDI_EVENT(cable, SYSEX_START_OR_CONT); | ||
| 48 | break; | ||
| 49 | case 1: | ||
| 50 | if (byte0 == SYSEX_END) | ||
| 51 | event.Event = MIDI_EVENT(cable, SYSEX_ENDS_IN_1); | ||
| 52 | else | ||
| 53 | event.Event = MIDI_EVENT(cable, SYSEX_START_OR_CONT); | ||
| 54 | break; | ||
| 55 | default: | ||
| 56 | return; //invalid cnt | ||
| 57 | } | ||
| 58 | } else { | ||
| 59 | //deal with 'system common' messages | ||
| 60 | //TODO are there any more? | ||
| 61 | switch(byte0 & 0xF0){ | ||
| 62 | case MIDI_SONGPOSITION: | ||
| 63 | event.Event = MIDI_EVENT(cable, SYS_COMMON_3); | ||
| 64 | break; | ||
| 65 | case MIDI_SONGSELECT: | ||
| 66 | case MIDI_TC_QUARTERFRAME: | ||
| 67 | event.Event = MIDI_EVENT(cable, SYS_COMMON_2); | ||
| 68 | break; | ||
| 69 | default: | ||
| 70 | event.Event = MIDI_EVENT(cable, byte0); | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | send_midi_packet(&event); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void usb_get_midi(MidiDevice * device) { | ||
| 79 | MIDI_EventPacket_t event; | ||
| 80 | while (recv_midi_packet(&event)) { | ||
| 81 | |||
| 82 | midi_packet_length_t length = midi_packet_length(event.Data1); | ||
| 83 | uint8_t input[3]; | ||
| 84 | input[0] = event.Data1; | ||
| 85 | input[1] = event.Data2; | ||
| 86 | input[2] = event.Data3; | ||
| 87 | if (length == UNDEFINED) { | ||
| 88 | //sysex | ||
| 89 | if (event.Event == MIDI_EVENT(0, SYSEX_START_OR_CONT) || event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_3)) { | ||
| 90 | length = 3; | ||
| 91 | } else if (event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_2)) { | ||
| 92 | length = 2; | ||
| 93 | } else if(event.Event == MIDI_EVENT(0, SYSEX_ENDS_IN_1)) { | ||
| 94 | length = 1; | ||
| 95 | } else { | ||
| 96 | //XXX what to do? | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | //pass the data to the device input function | ||
| 101 | if (length != UNDEFINED) | ||
| 102 | midi_device_input(device, length, input); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | static void fallthrough_callback(MidiDevice * device, | ||
| 107 | uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2){ | ||
| 108 | |||
| 109 | #ifdef AUDIO_ENABLE | ||
| 110 | if (cnt == 3) { | ||
| 111 | switch (byte0 & 0xF0) { | ||
| 112 | case MIDI_NOTEON: | ||
| 113 | play_note(((double)261.6)*pow(2.0, -4.0)*pow(2.0,(byte1 & 0x7F)/12.0), (byte2 & 0x7F) / 8); | ||
| 114 | break; | ||
| 115 | case MIDI_NOTEOFF: | ||
| 116 | stop_note(((double)261.6)*pow(2.0, -4.0)*pow(2.0,(byte1 & 0x7F)/12.0)); | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | if (byte0 == MIDI_STOP) { | ||
| 121 | stop_all_notes(); | ||
| 122 | } | ||
| 123 | #endif | ||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 127 | static void cc_callback(MidiDevice * device, | ||
| 128 | uint8_t chan, uint8_t num, uint8_t val) { | ||
| 129 | //sending it back on the next channel | ||
| 130 | // midi_send_cc(device, (chan + 1) % 16, num, val); | ||
| 131 | } | ||
| 132 | |||
| 133 | #ifdef API_SYSEX_ENABLE | ||
| 134 | uint8_t midi_buffer[MIDI_SYSEX_BUFFER] = {0}; | ||
| 135 | |||
| 136 | static void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data) { | ||
| 137 | // SEND_STRING("\n"); | ||
| 138 | // send_word(start); | ||
| 139 | // SEND_STRING(": "); | ||
| 140 | // Don't store the header | ||
| 141 | int16_t pos = start - 4; | ||
| 142 | for (uint8_t place = 0; place < length; place++) { | ||
| 143 | // send_byte(*data); | ||
| 144 | if (pos >= 0) { | ||
| 145 | if (*data == 0xF7) { | ||
| 146 | // SEND_STRING("\nRD: "); | ||
| 147 | // for (uint8_t i = 0; i < start + place + 1; i++){ | ||
| 148 | // send_byte(midi_buffer[i]); | ||
| 149 | // SEND_STRING(" "); | ||
| 150 | // } | ||
| 151 | const unsigned decoded_length = sysex_decoded_length(pos); | ||
| 152 | uint8_t decoded[API_SYSEX_MAX_SIZE]; | ||
| 153 | sysex_decode(decoded, midi_buffer, pos); | ||
| 154 | process_api(decoded_length, decoded); | ||
| 155 | return; | ||
| 156 | } | ||
| 157 | else if (pos >= MIDI_SYSEX_BUFFER) { | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | midi_buffer[pos] = *data; | ||
| 161 | } | ||
| 162 | // SEND_STRING(" "); | ||
| 163 | data++; | ||
| 164 | pos++; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | #endif | ||
| 168 | |||
| 169 | void midi_init(void); | ||
| 170 | |||
| 171 | void setup_midi(void) | ||
| 172 | { | ||
| 173 | #ifdef MIDI_ADVANCED | ||
| 174 | midi_init(); | ||
| 175 | #endif | ||
| 176 | midi_device_init(&midi_device); | ||
| 177 | midi_device_set_send_func(&midi_device, usb_send_func); | ||
| 178 | midi_device_set_pre_input_process_func(&midi_device, usb_get_midi); | ||
| 179 | midi_register_fallthrough_callback(&midi_device, fallthrough_callback); | ||
| 180 | midi_register_cc_callback(&midi_device, cc_callback); | ||
| 181 | #ifdef API_SYSEX_ENABLE | ||
| 182 | midi_register_sysex_callback(&midi_device, sysex_callback); | ||
| 183 | #endif | ||
| 184 | } | ||
diff --git a/tmk_core/protocol/midi/qmk_midi.h b/tmk_core/protocol/midi/qmk_midi.h new file mode 100644 index 000000000..7282a19d4 --- /dev/null +++ b/tmk_core/protocol/midi/qmk_midi.h | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #ifdef MIDI_ENABLE | ||
| 4 | #include "midi.h" | ||
| 5 | extern MidiDevice midi_device; | ||
| 6 | void setup_midi(void); | ||
| 7 | void send_midi_packet(MIDI_EventPacket_t* event); | ||
| 8 | bool recv_midi_packet(MIDI_EventPacket_t* const event); | ||
| 9 | #endif | ||
