aboutsummaryrefslogtreecommitdiff
path: root/tmk_core/protocol/midi
diff options
context:
space:
mode:
authorfredizzimo <fsundvik@gmail.com>2018-02-08 22:07:46 +0200
committerJack Humbert <jack.humb@gmail.com>2018-02-08 15:07:46 -0500
commit53ff8a31b61952d9675558149d927f7942071df9 (patch)
treea57b9e6f7d6494c9ef903f886a660dd43f4e5044 /tmk_core/protocol/midi
parent63c16f4b632a2a82a775f51a3ad0cc690cca1fc9 (diff)
downloadqmk_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-xtmk_core/protocol/midi/bytequeue/interrupt_setting.c15
-rw-r--r--tmk_core/protocol/midi/qmk_midi.c184
-rw-r--r--tmk_core/protocol/midi/qmk_midi.h9
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
27interrupt_setting_t store_and_clear_interrupt(void) { 28interrupt_setting_t store_and_clear_interrupt(void) {
@@ -33,4 +34,16 @@ interrupt_setting_t store_and_clear_interrupt(void) {
33void restore_interrupt_setting(interrupt_setting_t setting) { 34void restore_interrupt_setting(interrupt_setting_t setting) {
34 SREG = setting; 35 SREG = setting;
35} 36}
37#elif defined(__arm__)
38#include "ch.h"
39
40interrupt_setting_t store_and_clear_interrupt(void) {
41 chSysLock();
42 return 0;
43}
44
45void 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
15MidiDevice 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
26static 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
78static 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
106static 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
127static 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
134uint8_t midi_buffer[MIDI_SYSEX_BUFFER] = {0};
135
136static 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
169void midi_init(void);
170
171void 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