summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2023-02-09 15:11:22 +0100
committerBad Diode <bd@badd10de.dev>2023-02-09 15:11:22 +0100
commit6e331bd4b16b17cb9a5d0b38aab0099b9cd23d06 (patch)
treea3d482a86ea9aacf5707c705f3a2a8b00256957f
parent79b116d19fa4de2f7b5450acfe77a54524505b7d (diff)
downloadlaunchpad-polymaker-6e331bd4b16b17cb9a5d0b38aab0099b9cd23d06.tar.gz
launchpad-polymaker-6e331bd4b16b17cb9a5d0b38aab0099b9cd23d06.zip
Add midi range selection
-rw-r--r--src/app.c311
1 files changed, 252 insertions, 59 deletions
diff --git a/src/app.c b/src/app.c
index 7917a54..466a1a3 100644
--- a/src/app.c
+++ b/src/app.c
@@ -32,29 +32,7 @@
32 32
33#include "app.h" 33#include "app.h"
34 34
35// Housekeeping and debugging. 35// Font.
36u16 frame = 0;
37u16 n_voices = 0;
38u8 active = 1;
39u8 ch_min = 4;
40u8 ch_max = 8;
41
42typedef struct Voice {
43 u8 active;
44 u8 channel;
45 u8 d1;
46 u8 d2;
47 u8 port;
48} Voice;
49
50Voice voices[16] = {0};
51
52// store ADC frame pointer
53static const u16 *g_ADC = 0;
54
55// buffer to store pad states for flash save
56#define BUTTON_COUNT 100
57u8 buttons[BUTTON_COUNT] = {0};
58u16 font_numbers[10] = { 36u16 font_numbers[10] = {
59 /* 37 /*
60 * 0: 111 | 1111 0110 1101 1110 38 * 0: 111 | 1111 0110 1101 1110
@@ -138,42 +116,168 @@ u16 font_numbers[10] = {
138 0xF792, 116 0xF792,
139}; 117};
140 118
141enum Buttons { 119// Enums and structs.
120typedef enum Button {
142 POLY_PAD_ACTIVE = 11, 121 POLY_PAD_ACTIVE = 11,
143}; 122 POLY_PAD_MIN_CH_0 = 11 + 10 * 7 + 0,
123 POLY_PAD_MIN_CH_1 = 11 + 10 * 7 + 1,
124 POLY_PAD_MIN_CH_2 = 11 + 10 * 7 + 2,
125 POLY_PAD_MIN_CH_3 = 11 + 10 * 7 + 3,
126 POLY_PAD_MIN_CH_4 = 11 + 10 * 7 + 4,
127 POLY_PAD_MIN_CH_5 = 11 + 10 * 7 + 5,
128 POLY_PAD_MIN_CH_6 = 11 + 10 * 7 + 6,
129 POLY_PAD_MIN_CH_7 = 11 + 10 * 7 + 7,
130 POLY_PAD_MIN_CH_8 = 11 + 10 * 6 + 0,
131 POLY_PAD_MIN_CH_9 = 11 + 10 * 6 + 1,
132 POLY_PAD_MIN_CH_A = 11 + 10 * 6 + 2,
133 POLY_PAD_MIN_CH_B = 11 + 10 * 6 + 3,
134 POLY_PAD_MIN_CH_C = 11 + 10 * 6 + 4,
135 POLY_PAD_MIN_CH_D = 11 + 10 * 6 + 5,
136 POLY_PAD_MIN_CH_E = 11 + 10 * 6 + 6,
137 POLY_PAD_MIN_CH_F = 11 + 10 * 6 + 7,
138 POLY_PAD_MAX_CH_0 = 11 + 10 * 5 + 0,
139 POLY_PAD_MAX_CH_1 = 11 + 10 * 5 + 1,
140 POLY_PAD_MAX_CH_2 = 11 + 10 * 5 + 2,
141 POLY_PAD_MAX_CH_3 = 11 + 10 * 5 + 3,
142 POLY_PAD_MAX_CH_4 = 11 + 10 * 5 + 4,
143 POLY_PAD_MAX_CH_5 = 11 + 10 * 5 + 5,
144 POLY_PAD_MAX_CH_6 = 11 + 10 * 5 + 6,
145 POLY_PAD_MAX_CH_7 = 11 + 10 * 5 + 7,
146 POLY_PAD_MAX_CH_8 = 11 + 10 * 4 + 0,
147 POLY_PAD_MAX_CH_9 = 11 + 10 * 4 + 1,
148 POLY_PAD_MAX_CH_A = 11 + 10 * 4 + 2,
149 POLY_PAD_MAX_CH_B = 11 + 10 * 4 + 3,
150 POLY_PAD_MAX_CH_C = 11 + 10 * 4 + 4,
151 POLY_PAD_MAX_CH_D = 11 + 10 * 4 + 5,
152 POLY_PAD_MAX_CH_E = 11 + 10 * 4 + 6,
153 POLY_PAD_MAX_CH_F = 11 + 10 * 4 + 7,
154} Button;
155
156typedef enum Mode {
157 MOD_POLY_MAIN = 0,
158 MOD_POLY_SETUP = 1,
159} Mode;
160
161typedef struct Voice {
162 u8 active;
163 u8 channel;
164 u8 d1;
165 u8 d2;
166 u8 port;
167} Voice;
168
169// Globals.
170u16 frame = 0;
171u16 n_voices = 0;
172u8 active = 1;
173u8 ch_min = 0;
174u8 ch_max = 4;
175Mode mode = MOD_POLY_SETUP;
176Voice voices[16] = {0};
177
178// store ADC frame pointer
179static const u16 *g_ADC = 0;
180
181void
182poly_active_toggle(void) {
183 // Stop existing playing notes.
184 for (u8 i = 0; i < 16; i++) {
185 Voice *voice = &voices[i];
186 if (voice->active) {
187 voice->active = 0;
188 hal_send_midi(
189 voice->port,
190 NOTEOFF | voice->channel,
191 voice->d1,
192 voice->d2);
193 }
194 }
195 n_voices = 0;
196 active = !active;
197}
198
199void
200select_ch_min(u8 target) {
201 if (target <= ch_max) {
202 ch_min = target;
203 }
204}
205
206void
207select_ch_max(u8 target) {
208 if (target >= ch_min) {
209 ch_max = target;
210 }
211}
144 212
145void 213void
146app_surface_event(u8 type, u8 index, u8 value) { 214app_surface_event(u8 type, u8 index, u8 value) {
147 switch (type) { 215 switch (type) {
148 case TYPEPAD: { 216 case TYPEPAD: {
149 if (value && index == POLY_PAD_ACTIVE) { 217 switch (mode) {
150 // Stop existing playing notes. 218 case MOD_POLY_MAIN: {
151 for (u8 i = 0; i < 16; i++) { 219 if (value && index == POLY_PAD_ACTIVE) {
152 Voice *voice = &voices[i]; 220 poly_active_toggle();
153 if (voice->active) {
154 voice->active = 0;
155 hal_send_midi(
156 voice->port,
157 NOTEOFF | voice->channel,
158 voice->d1,
159 voice->d2);
160 } 221 }
161 } 222 } break;
162 n_voices = 0; 223 case MOD_POLY_SETUP: {
163 active = !active; 224 if (value) {
225 switch (index) {
226 // Handle min channel selection.
227 case POLY_PAD_MIN_CH_0: { select_ch_min(0); } break;
228 case POLY_PAD_MIN_CH_1: { select_ch_min(1); } break;
229 case POLY_PAD_MIN_CH_2: { select_ch_min(2); } break;
230 case POLY_PAD_MIN_CH_3: { select_ch_min(3); } break;
231 case POLY_PAD_MIN_CH_4: { select_ch_min(4); } break;
232 case POLY_PAD_MIN_CH_5: { select_ch_min(5); } break;
233 case POLY_PAD_MIN_CH_6: { select_ch_min(6); } break;
234 case POLY_PAD_MIN_CH_7: { select_ch_min(7); } break;
235 case POLY_PAD_MIN_CH_8: { select_ch_min(8); } break;
236 case POLY_PAD_MIN_CH_9: { select_ch_min(9); } break;
237 case POLY_PAD_MIN_CH_A: { select_ch_min(10); } break;
238 case POLY_PAD_MIN_CH_B: { select_ch_min(11); } break;
239 case POLY_PAD_MIN_CH_C: { select_ch_min(12); } break;
240 case POLY_PAD_MIN_CH_D: { select_ch_min(13); } break;
241 case POLY_PAD_MIN_CH_E: { select_ch_min(14); } break;
242 case POLY_PAD_MIN_CH_F: { select_ch_min(15); } break;
243 // Handle max channel selection.
244 case POLY_PAD_MAX_CH_0: { select_ch_max(0); } break;
245 case POLY_PAD_MAX_CH_1: { select_ch_max(1); } break;
246 case POLY_PAD_MAX_CH_2: { select_ch_max(2); } break;
247 case POLY_PAD_MAX_CH_3: { select_ch_max(3); } break;
248 case POLY_PAD_MAX_CH_4: { select_ch_max(4); } break;
249 case POLY_PAD_MAX_CH_5: { select_ch_max(5); } break;
250 case POLY_PAD_MAX_CH_6: { select_ch_max(6); } break;
251 case POLY_PAD_MAX_CH_7: { select_ch_max(7); } break;
252 case POLY_PAD_MAX_CH_8: { select_ch_max(8); } break;
253 case POLY_PAD_MAX_CH_9: { select_ch_max(9); } break;
254 case POLY_PAD_MAX_CH_A: { select_ch_max(10); } break;
255 case POLY_PAD_MAX_CH_B: { select_ch_max(11); } break;
256 case POLY_PAD_MAX_CH_C: { select_ch_max(12); } break;
257 case POLY_PAD_MAX_CH_D: { select_ch_max(13); } break;
258 case POLY_PAD_MAX_CH_E: { select_ch_max(14); } break;
259 case POLY_PAD_MAX_CH_F: { select_ch_max(15); } break;
260 // TODO: Handle listen channel selection.
261 // Handle active toggle.
262 case POLY_PAD_ACTIVE: { poly_active_toggle(); } break;
263 default: break;
264 }
265 }
266 } break;
164 } 267 }
165 // // toggle it and store it off, so we can save to flash if we want to
166 // if (value) {
167 // buttons[index] = MAXLED * !buttons[index];
168 // }
169
170 // // example - light / extinguish pad LEDs
171 // hal_plot_led(TYPEPAD, index, 0, 0, buttons[index]);
172
173 // // example - send MIDI
174 // hal_send_midi(DINMIDI, NOTEON | 0, index, value);
175 } break; 268 } break;
176 case TYPESETUP: { 269 case TYPESETUP: {
270 if (value) {
271 switch (mode) {
272 case MOD_POLY_MAIN: {
273 mode = MOD_POLY_SETUP;
274 } break;
275 case MOD_POLY_SETUP: {
276 mode = MOD_POLY_MAIN;
277 // TODO: save to flash.
278 } break;
279 }
280 }
177 // if (value) { 281 // if (value) {
178 // // Pressing the setup button will save the current buttons/pad 282 // // Pressing the setup button will save the current buttons/pad
179 // // state to the flash. The flash memory is USER_AREA_SIZE bytes 283 // // state to the flash. The flash memory is USER_AREA_SIZE bytes
@@ -192,12 +296,12 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) {
192 } 296 }
193 u8 channel = status & 0x0F; 297 u8 channel = status & 0x0F;
194 if ((status & 0xF0) == NOTEON) { 298 if ((status & 0xF0) == NOTEON) {
195 if (n_voices == (ch_max - ch_min)) { 299 if (n_voices == (ch_max - ch_min + 1)) {
196 return; 300 return;
197 } 301 }
198 302
199 // Find if the note was already pressed. 303 // Find if the note was already pressed.
200 for (u8 i = ch_min; i < ch_max; i++) { 304 for (u8 i = ch_min; i <= ch_max; i++) {
201 Voice *voice = &voices[i]; 305 Voice *voice = &voices[i];
202 // Stop voice if needed. 306 // Stop voice if needed.
203 if (voice->active && voice->d1 == d1) { 307 if (voice->active && voice->d1 == d1) {
@@ -211,7 +315,7 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) {
211 } 315 }
212 316
213 // Find next free voice slot. 317 // Find next free voice slot.
214 for (u8 i = ch_min; i < ch_max; i++) { 318 for (u8 i = ch_min; i <= ch_max; i++) {
215 Voice *voice = &voices[i]; 319 Voice *voice = &voices[i];
216 // Register voice. 320 // Register voice.
217 if (!voice->active) { 321 if (!voice->active) {
@@ -234,7 +338,7 @@ app_midi_event(u8 port, u8 status, u8 d1, u8 d2) {
234 // TODO: Round robin scheduling? 338 // TODO: Round robin scheduling?
235 n_voices++; 339 n_voices++;
236 } else if ((status & 0xF0) == NOTEOFF) { 340 } else if ((status & 0xF0) == NOTEOFF) {
237 for (u8 i = ch_min; i < ch_max; i++) { 341 for (u8 i = ch_min; i <= ch_max; i++) {
238 Voice *voice = &voices[i]; 342 Voice *voice = &voices[i];
239 // Register voice. 343 // Register voice.
240 if (voice->active && voice->d1 == d1) { 344 if (voice->active && voice->d1 == d1) {
@@ -303,10 +407,7 @@ clear_pads(void) {
303} 407}
304 408
305void 409void
306draw_poly_scene(void) { 410draw_poly_active_button(void) {
307 print_number((n_voices / 10) % 10, MAXLED, MAXLED, MAXLED, 0, 0);
308 print_number( n_voices % 10, MAXLED, MAXLED, MAXLED, 4, 0);
309
310 if (active) { 411 if (active) {
311 hal_plot_led(TYPEPAD, 11, 0, MAXLED, 0); 412 hal_plot_led(TYPEPAD, 11, 0, MAXLED, 0);
312 } else { 413 } else {
@@ -315,10 +416,102 @@ draw_poly_scene(void) {
315} 416}
316 417
317void 418void
419draw_poly_main(void) {
420 print_number((n_voices / 10) % 10, MAXLED, MAXLED, MAXLED, 0, 0);
421 print_number( n_voices % 10, MAXLED, MAXLED, MAXLED, 4, 0);
422 draw_poly_active_button();
423}
424
425void
426draw_min_channel(void) {
427 for (u8 i = 0; i < 8; i++) {
428 if (i == ch_min) {
429 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, MAXLED, MAXLED, MAXLED);
430 continue;
431 }
432 if (ch_max < 8 && i > ch_max) {
433 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, 0, 0, 5);
434 continue;
435 }
436 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, 0, 0, MAXLED / 2);
437 }
438 for (u8 i = 0; i < 8; i++) {
439 if ((i + 8) == ch_min) {
440 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, MAXLED, MAXLED, MAXLED);
441 continue;
442 }
443 if (ch_max < 16 && (i + 8) > ch_max) {
444 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, 0, 0, 5);
445 continue;
446 }
447 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_8 + i, 0, 0, MAXLED / 2);
448 }
449}
450
451void
452draw_max_channel(void) {
453 // for (u8 i = 0; i < 8; i++) {
454 // u8 color = 5;
455 // if (i == ch_max) {
456 // color = MAXLED;
457 // }
458 // hal_plot_led(TYPEPAD, 11 + 10 * 5 + i, color, 10, 10);
459 // color = 5;
460 // if (i + 8 == ch_max) {
461 // color = MAXLED;
462 // }
463 // hal_plot_led(TYPEPAD, 11 + 10 * 4 + i, color, 10, 10);
464 // }
465 for (u8 i = 0; i < 8; i++) {
466 if (i == ch_max) {
467 hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, MAXLED, MAXLED, MAXLED);
468 continue;
469 }
470 if (i < ch_min) {
471 hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, 5, 0, 0);
472 continue;
473 }
474 hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_0 + i, MAXLED / 2, 0, 0);
475 }
476 for (u8 i = 0; i < 8; i++) {
477 if ((i + 8) == ch_max) {
478 hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, MAXLED, MAXLED, MAXLED);
479 continue;
480 }
481 if (ch_min >= 8 && (i + 8) < ch_min) {
482 hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, 5, 0, 0);
483 continue;
484 }
485 hal_plot_led(TYPEPAD, POLY_PAD_MAX_CH_8 + i, MAXLED / 2, 0, 0);
486 }
487}
488
489void
490draw_poly_setup(void) {
491 // TODO: ...
492 draw_min_channel();
493 draw_max_channel();
494 // draw_listen_channel();
495 draw_poly_active_button();
496}
497
498void
499draw_scene(void) {
500 switch (mode) {
501 case MOD_POLY_MAIN: {
502 draw_poly_main();
503 } break;
504 case MOD_POLY_SETUP: {
505 draw_poly_setup();
506 } break;
507 }
508}
509
510void
318render(void) { 511render(void) {
319 if (frame++ == 1000 / 10) { 512 if (frame++ == 1000 / 10) {
320 clear_pads(); 513 clear_pads();
321 draw_poly_scene(); 514 draw_scene();
322 frame = 0; 515 frame = 0;
323 } 516 }
324} 517}
@@ -332,7 +525,7 @@ app_timer_event() {
332void 525void
333app_init(const u16 *adc_raw) { 526app_init(const u16 *adc_raw) {
334 // example - load button states from flash 527 // example - load button states from flash
335 hal_read_flash(0, buttons, BUTTON_COUNT); 528 // hal_read_flash(0, buttons, BUTTON_COUNT);
336 529
337 // store off the raw ADC frame pointer for later use 530 // store off the raw ADC frame pointer for later use
338 g_ADC = adc_raw; 531 g_ADC = adc_raw;