]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/protocol/midi/qmk_midi.c
Fix Helix ws2812.c listed more than once warning. (#4499)
[qmk_firmware.git] / tmk_core / protocol / midi / qmk_midi.c
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 }