]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/process_keycode/process_midi.c
Document size added by MIDI_ENABLE (~3800 bytes according to my experiments)
[qmk_firmware.git] / quantum / process_keycode / process_midi.c
1 #define MIDI_TONE_KEYCODE_OCTAVES 2
2
3 #include "process_midi.h"
4 #include "timer.h"
5
6 static uint8_t tone_status[MIDI_TONE_COUNT];
7
8 static uint8_t midi_modulation;
9 static int8_t midi_modulation_step;
10 static uint16_t midi_modulation_timer;
11
12 inline uint8_t compute_velocity(uint8_t setting)
13 {
14     return (setting + 1) * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN + 1));
15 }
16
17 void midi_init(void)
18 {
19     midi_config.octave = MI_OCT_2 - MIDI_OCTAVE_MIN;
20     midi_config.transpose = 0;
21     midi_config.velocity = (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN);
22     midi_config.channel = 0;
23     midi_config.modulation_interval = 8;
24
25     for (uint8_t i = 0; i < MIDI_TONE_COUNT; i++)
26     {
27         tone_status[i] = MIDI_INVALID_NOTE;
28     }
29
30     midi_modulation = 0;
31     midi_modulation_step = 0;
32     midi_modulation_timer = 0;
33 }
34
35 void midi_task(void)
36 {
37     if (timer_elapsed(midi_modulation_timer) < midi_config.modulation_interval)
38         return;
39     midi_modulation_timer = timer_read();
40
41     if (midi_modulation_step != 0)
42     {
43         dprintf("midi modulation %d\n", midi_modulation);
44         midi_send_cc(&midi_device, midi_config.channel, 0x1, midi_modulation);
45
46         if (midi_modulation_step < 0 && midi_modulation < -midi_modulation_step) {
47             midi_modulation = 0;
48             midi_modulation_step = 0;
49             return;
50         }
51
52         midi_modulation += midi_modulation_step;
53
54         if (midi_modulation > 127)
55             midi_modulation = 127;
56     }
57 }
58
59 uint8_t midi_compute_note(uint16_t keycode)
60 {
61     return 12 * midi_config.octave + (keycode - MIDI_TONE_MIN) + midi_config.transpose;
62 }
63
64 bool process_midi(uint16_t keycode, keyrecord_t *record)
65 {
66     switch (keycode) {
67         case MIDI_TONE_MIN ... MIDI_TONE_MAX:
68         {
69             uint8_t channel = midi_config.channel;
70             uint8_t tone = keycode - MIDI_TONE_MIN;
71             uint8_t velocity = compute_velocity(midi_config.velocity);
72             if (record->event.pressed) {
73                 uint8_t note = midi_compute_note(keycode);
74                 midi_send_noteon(&midi_device, channel, note, velocity);
75                 dprintf("midi noteon channel:%d note:%d velocity:%d\n", channel, note, velocity);
76                 tone_status[tone] = note;
77             }
78             else {
79                 uint8_t note = tone_status[tone];
80                 if (note != MIDI_INVALID_NOTE)
81                 {
82                     midi_send_noteoff(&midi_device, channel, note, velocity);
83                     dprintf("midi noteoff channel:%d note:%d velocity:%d\n", channel, note, velocity);
84                 }
85                 tone_status[tone] = MIDI_INVALID_NOTE;
86             }
87             return false;
88         }
89         case MIDI_OCTAVE_MIN ... MIDI_OCTAVE_MAX:
90             if (record->event.pressed) {
91                 midi_config.octave = keycode - MIDI_OCTAVE_MIN;
92                 dprintf("midi octave %d\n", midi_config.octave);
93             }
94             return false;
95         case MI_OCTD:
96             if (record->event.pressed && midi_config.octave > 0) {
97                 midi_config.octave--;
98                 dprintf("midi octave %d\n", midi_config.octave);
99             }
100             return false;
101         case MI_OCTU:
102             if (record->event.pressed && midi_config.octave < (MIDI_OCTAVE_MAX - MIDI_OCTAVE_MIN)) {
103                 midi_config.octave++;
104                 dprintf("midi octave %d\n", midi_config.octave);
105             }
106             return false;
107         case MIDI_TRANSPOSE_MIN ... MIDI_TRANSPOSE_MAX:
108             if (record->event.pressed) {
109                 midi_config.transpose = keycode - MI_TRNS_0;
110                 dprintf("midi transpose %d\n", midi_config.transpose);
111             }
112             return false;
113         case MI_TRNSD:
114             if (record->event.pressed && midi_config.transpose > (MIDI_TRANSPOSE_MIN - MI_TRNS_0)) {
115                 midi_config.transpose--;
116                 dprintf("midi transpose %d\n", midi_config.transpose);
117             }
118             return false;
119         case MI_TRNSU:
120             if (record->event.pressed && midi_config.transpose < (MIDI_TRANSPOSE_MAX - MI_TRNS_0)) {
121                 const bool positive = midi_config.transpose > 0;
122                 midi_config.transpose++;
123                 if (positive && midi_config.transpose < 0)
124                     midi_config.transpose--;
125                 dprintf("midi transpose %d\n", midi_config.transpose);
126             }
127             return false;
128         case MIDI_VELOCITY_MIN ... MIDI_VELOCITY_MAX:
129             if (record->event.pressed) {
130                 midi_config.velocity = keycode - MIDI_VELOCITY_MIN;
131                 dprintf("midi velocity %d\n", midi_config.velocity);
132             }
133             return false;
134         case MI_VELD:
135             if (record->event.pressed && midi_config.velocity > 0) {
136                 midi_config.velocity--;
137                 dprintf("midi velocity %d\n", midi_config.velocity);
138             }
139             return false;
140         case MI_VELU:
141             if (record->event.pressed) {
142                 midi_config.velocity++;
143                 dprintf("midi velocity %d\n", midi_config.velocity);
144             }
145             return false;
146         case MIDI_CHANNEL_MIN ... MIDI_CHANNEL_MAX:
147             if (record->event.pressed) {
148                 midi_config.channel = keycode - MIDI_CHANNEL_MIN;
149                 dprintf("midi channel %d\n", midi_config.channel);
150             }
151             return false;
152         case MI_CHD:
153             if (record->event.pressed) {
154                 midi_config.channel--;
155                 dprintf("midi channel %d\n", midi_config.channel);
156             }
157             return false;
158         case MI_CHU:
159             if (record->event.pressed) {
160                 midi_config.channel++;
161                 dprintf("midi channel %d\n", midi_config.channel);
162             }
163             return false;
164         case MI_OFF:
165             if (record->event.pressed) {
166                 midi_send_cc(&midi_device, midi_config.channel, 0x7B, 0);
167                 dprintf("midi off\n");
168             }
169             return false;
170         case MI_SUS:
171             midi_send_cc(&midi_device, midi_config.channel, 0x40, record->event.pressed ? 127 : 0);
172             dprintf("midi sustain %d\n", record->event.pressed);
173             return false;
174         case MI_PORT:
175             midi_send_cc(&midi_device, midi_config.channel, 0x41, record->event.pressed ? 127 : 0);
176             dprintf("midi portamento %d\n", record->event.pressed);
177             return false;
178         case MI_SOST:
179             midi_send_cc(&midi_device, midi_config.channel, 0x42, record->event.pressed ? 127 : 0);
180             dprintf("midi sostenuto %d\n", record->event.pressed);
181             return false;
182         case MI_SOFT:
183             midi_send_cc(&midi_device, midi_config.channel, 0x43, record->event.pressed ? 127 : 0);
184             dprintf("midi soft %d\n", record->event.pressed);
185             return false;
186         case MI_LEG:
187             midi_send_cc(&midi_device, midi_config.channel, 0x43, record->event.pressed ? 127 : 0);
188             dprintf("midi legato %d\n", record->event.pressed);
189             return false;
190         case MI_MOD:
191             midi_modulation_step = record->event.pressed ? 1 : -1;
192             return false;
193         case MI_MODSD:
194             if (record->event.pressed) {
195                 midi_config.modulation_interval++;
196                 // prevent overflow
197                 if (midi_config.modulation_interval == 0)
198                     midi_config.modulation_interval--;
199                 dprintf("midi modulation interval %d\n", midi_config.modulation_interval);
200             }
201             return false;
202         case MI_MODSU:
203             if (record->event.pressed && midi_config.modulation_interval > 0) {
204                 midi_config.modulation_interval--;
205                 dprintf("midi modulation interval %d\n", midi_config.modulation_interval);
206             }
207             return false;
208     };
209
210     return true;
211 }