summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2023-06-28 10:31:18 +0200
committerBad Diode <bd@badd10de.dev>2023-06-28 10:31:18 +0200
commit9bb91b5496b5a1bc730bdc70b3352a789c35d995 (patch)
tree0c0082fe97980756c667fe25fab9d0a8afb35365
parent10513f80a94bde633922862db9ca71337889f0e5 (diff)
downloadlaunchpad-polymaker-9bb91b5496b5a1bc730bdc70b3352a789c35d995.tar.gz
launchpad-polymaker-9bb91b5496b5a1bc730bdc70b3352a789c35d995.zip
Initial kbd implementation
-rw-r--r--Makefile2
-rw-r--r--src/app.c219
2 files changed, 210 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 42763b3..c758581 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ ELF = $(BUILDDIR)/launchpad_pro.elf
16HEX = $(BUILDDIR)/launchpad_pro.hex 16HEX = $(BUILDDIR)/launchpad_pro.hex
17HEXTOSYX = $(BUILDDIR)/hextosyx 17HEXTOSYX = $(BUILDDIR)/hextosyx
18SIMULATOR = $(BUILDDIR)/simulator 18SIMULATOR = $(BUILDDIR)/simulator
19PORT = hw:4,0,0 19PORT = hw:3,0,0
20 20
21# tools 21# tools
22HOST_GPP = g++ 22HOST_GPP = g++
diff --git a/src/app.c b/src/app.c
index 21f376a..a5c187a 100644
--- a/src/app.c
+++ b/src/app.c
@@ -117,6 +117,29 @@ u16 font_numbers[10] = {
117}; 117};
118 118
119// Enums and structs. 119// Enums and structs.
120typedef enum Pads {
121 POLY_PAD_ROW_0 = 11 + 10 * 7 + 0,
122 POLY_PAD_ROW_1 = 11 + 10 * 6 + 0,
123 POLY_PAD_ROW_2 = 11 + 10 * 5 + 0,
124 POLY_PAD_ROW_3 = 11 + 10 * 4 + 0,
125 POLY_PAD_ROW_4 = 11 + 10 * 3 + 0,
126 POLY_PAD_ROW_5 = 11 + 10 * 2 + 0,
127 POLY_PAD_ROW_6 = 11 + 10 * 1 + 0,
128 POLY_PAD_ROW_7 = 11 + 10 * 0 + 0,
129 POLY_TOP_ROW = 11 + 10 * 8 + 0,
130} Pads;
131
132Pads row_idx[] = {
133 POLY_PAD_ROW_0,
134 POLY_PAD_ROW_1,
135 POLY_PAD_ROW_2,
136 POLY_PAD_ROW_3,
137 POLY_PAD_ROW_4,
138 POLY_PAD_ROW_5,
139 POLY_PAD_ROW_6,
140 POLY_PAD_ROW_7,
141};
142
120typedef enum Button { 143typedef enum Button {
121 POLY_PAD_ACTIVE = 11, 144 POLY_PAD_ACTIVE = 11,
122 POLY_PAD_STEAL = 11 + 7, 145 POLY_PAD_STEAL = 11 + 7,
@@ -173,6 +196,7 @@ typedef enum Button {
173typedef enum Mode { 196typedef enum Mode {
174 MOD_POLY_MAIN = 0, 197 MOD_POLY_MAIN = 0,
175 MOD_POLY_SETUP = 1, 198 MOD_POLY_SETUP = 1,
199 MOD_POLY_KBD = 2,
176} Mode; 200} Mode;
177 201
178typedef enum Stealing { 202typedef enum Stealing {
@@ -182,6 +206,19 @@ typedef enum Stealing {
182 POLY_STEAL_LOW = 3, 206 POLY_STEAL_LOW = 3,
183} Stealing; 207} Stealing;
184 208
209typedef struct Color {
210 int r;
211 int g;
212 int b;
213} Color;
214
215Color colors[] = {
216 { MAXLED, MAXLED, MAXLED }, // White
217 { MAXLED, 0, 0 }, // Red
218 { 0, MAXLED, 0 }, // Green
219 { 0, 0, MAXLED }, // Blue
220};
221
185typedef struct Voice { 222typedef struct Voice {
186 u8 active; 223 u8 active;
187 u8 channel; 224 u8 channel;
@@ -192,6 +229,8 @@ typedef struct Voice {
192} Voice; 229} Voice;
193 230
194typedef struct State { 231typedef struct State {
232 // Magic.
233 u32 magic;
195 // Polyphony. 234 // Polyphony.
196 u8 active; 235 u8 active;
197 u8 stealing; 236 u8 stealing;
@@ -199,6 +238,8 @@ typedef struct State {
199 u8 ch_max; 238 u8 ch_max;
200 u8 ch_listen[16]; 239 u8 ch_listen[16];
201 Mode mode; 240 Mode mode;
241 // Keyboard.
242 u8 kbd_octave;
202} State; 243} State;
203 244
204// Globals. 245// Globals.
@@ -265,6 +306,87 @@ select_ch_sel(u8 target) {
265 state.ch_listen[target] = !state.ch_listen[target]; 306 state.ch_listen[target] = !state.ch_listen[target];
266} 307}
267 308
309int
310kbd_find_note(int index) {
311 int note = -1;
312 int black = 0;
313 int row = 0;
314
315 // A
316 if (index >= POLY_PAD_ROW_0 && index <= (POLY_PAD_ROW_0 + 7)) {
317 row = POLY_PAD_ROW_0;
318 black = 1;
319 note = 12 * (state.kbd_octave + 5);
320 }
321 if (index >= POLY_PAD_ROW_1 && index <= (POLY_PAD_ROW_1 + 7)) {
322 row = POLY_PAD_ROW_1;
323 note = 12 * (state.kbd_octave + 5);
324 }
325
326 // B
327 if (index >= POLY_PAD_ROW_2 && index <= (POLY_PAD_ROW_2 + 7)) {
328 row = POLY_PAD_ROW_2;
329 black = 1;
330 note = 12 * (state.kbd_octave + 4);
331 }
332 if (index >= POLY_PAD_ROW_3 && index <= (POLY_PAD_ROW_3 + 7)) {
333 row = POLY_PAD_ROW_3;
334 note = 12 * (state.kbd_octave + 4);
335 }
336
337 // C
338 if (index >= POLY_PAD_ROW_4 && index <= (POLY_PAD_ROW_4 + 7)) {
339 row = POLY_PAD_ROW_4;
340 black = 1;
341 note = 12 * (state.kbd_octave + 3);
342 }
343 if (index >= POLY_PAD_ROW_5 && index <= (POLY_PAD_ROW_5 + 7)) {
344 row = POLY_PAD_ROW_5;
345 note = 12 * (state.kbd_octave + 3);
346 }
347
348 // D
349 if (index >= POLY_PAD_ROW_6 && index <= (POLY_PAD_ROW_6 + 7)) {
350 row = POLY_PAD_ROW_6;
351 black = 1;
352 note = 12 * (state.kbd_octave + 2);
353 }
354 if (index >= POLY_PAD_ROW_7 && index <= (POLY_PAD_ROW_7 + 7)) {
355 row = POLY_PAD_ROW_7;
356 note = 12 * (state.kbd_octave + 2);
357 }
358
359 // Invalid pad index.
360 if (note < 0) {
361 return -1;
362 }
363
364 // Find note offset.
365 if (black) {
366 switch (index - row) {
367 case 1: { return note + 1; } break;
368 case 2: { return note + 3; } break;
369 case 4: { return note + 6; } break;
370 case 5: { return note + 8; } break;
371 case 6: { return note + 10; } break;
372 default: { return -1; } break;
373 }
374 } else {
375 switch (index - row) {
376 case 0: { return note + 0; } break;
377 case 1: { return note + 2; } break;
378 case 2: { return note + 4; } break;
379 case 3: { return note + 5; } break;
380 case 4: { return note + 7; } break;
381 case 5: { return note + 9; } break;
382 case 6: { return note + 11; } break;
383 case 7: { return note + 12; } break;
384 default: { return -1; } break;
385 }
386 }
387 return -1;
388}
389
268void 390void
269app_surface_event(u8 type, u8 index, u8 value) { 391app_surface_event(u8 type, u8 index, u8 value) {
270 switch (type) { 392 switch (type) {
@@ -340,18 +462,57 @@ app_surface_event(u8 type, u8 index, u8 value) {
340 } 462 }
341 } 463 }
342 } break; 464 } break;
465 case MOD_POLY_KBD: {
466 // Transposition.
467 if (index >= POLY_TOP_ROW && index <= (POLY_TOP_ROW + 7)) {
468 switch (index - POLY_TOP_ROW) {
469 case 0: {
470 if (state.kbd_octave < 3) {
471 state.kbd_octave++;
472 }
473 } break;
474 case 1: {
475 if (state.kbd_octave > 0) {
476 state.kbd_octave--;
477 }
478 } break;
479 default: {} break;
480 }
481 return;
482 }
483 u8 channel = 0;
484 // TODO: Velocity on/off configuration.
485 // TODO: Velocity curve adjustment.
486 // TODO: Aftertouch?
487 // TODO: Different colors for different octaves.
488 // TODO: Per KBD channel selection.
489 int note = kbd_find_note(index);
490 if (note == -1) {
491 return;
492 }
493
494 if (value) {
495 hal_send_midi(USBSTANDALONE, NOTEON | channel, note, value);
496 hal_send_midi(USBMIDI, NOTEON | channel, note, value);
497 hal_send_midi(DINMIDI, NOTEON | channel, note, value);
498 } else {
499 hal_send_midi(USBSTANDALONE, NOTEOFF | channel, note, value);
500 hal_send_midi(USBMIDI, NOTEOFF | channel, note, value);
501 hal_send_midi(DINMIDI, NOTEOFF | channel, note, value);
502 }
503 } break;
343 } 504 }
344 } break; 505 } break;
345 case TYPESETUP: { 506 case TYPESETUP: {
346 if (value) { 507 if (value) {
347 switch (state.mode) { 508 switch (state.mode) {
509 case MOD_POLY_KBD:
348 case MOD_POLY_MAIN: { 510 case MOD_POLY_MAIN: {
349 state.mode = MOD_POLY_SETUP; 511 state.mode = MOD_POLY_SETUP;
350 } break; 512 } break;
351 case MOD_POLY_SETUP: { 513 case MOD_POLY_SETUP: {
352 state.mode = MOD_POLY_MAIN; 514 state.mode = MOD_POLY_KBD;
353 hal_write_flash(0, (u8*)&state, sizeof(State)); 515 hal_write_flash(0, (u8*)&state, sizeof(State));
354
355 } break; 516 } break;
356 } 517 }
357 } 518 }
@@ -575,6 +736,14 @@ draw_poly_main(void) {
575 736
576void 737void
577draw_min_channel(void) { 738draw_min_channel(void) {
739 // for (u8 i = 0; i < 8; i++) {
740 // if (state.ch_max < 8 && i > state.ch_max) {
741 // clr = colors[1];
742 // } else if (i != state.ch_min){
743 // clr = colors[2];
744 // }
745 // hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, clr.r, clr.g, clr.b);
746 // }
578 for (u8 i = 0; i < 8; i++) { 747 for (u8 i = 0; i < 8; i++) {
579 if (i == state.ch_min) { 748 if (i == state.ch_min) {
580 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, MAXLED, MAXLED, MAXLED); 749 hal_plot_led(TYPEPAD, POLY_PAD_MIN_CH_0 + i, MAXLED, MAXLED, MAXLED);
@@ -653,6 +822,25 @@ draw_poly_setup(void) {
653} 822}
654 823
655void 824void
825draw_kbd(int loc, Color clr) {
826 if (loc < 0 || loc >= 7) {
827 return;
828 }
829 Color clr_top = clr;
830 Color clr_bot = (Color){clr_top.r / 4, clr_top.g / 4, clr_top.b / 4 };
831 int idx_top = row_idx[loc];
832 int idx_bot = row_idx[loc + 1];
833 hal_plot_led(TYPEPAD, idx_top + 1, clr_bot.r, clr_bot.g, clr_bot.b);
834 hal_plot_led(TYPEPAD, idx_top + 2, clr_bot.r, clr_bot.g, clr_bot.b);
835 hal_plot_led(TYPEPAD, idx_top + 4, clr_bot.r, clr_bot.g, clr_bot.b);
836 hal_plot_led(TYPEPAD, idx_top + 5, clr_bot.r, clr_bot.g, clr_bot.b);
837 hal_plot_led(TYPEPAD, idx_top + 6, clr_bot.r, clr_bot.g, clr_bot.b);
838 for (u8 i = 0; i < 8; i++) {
839 hal_plot_led(TYPEPAD, idx_bot + i, clr_top.r, clr_top.g, clr_top.b);
840 }
841}
842
843void
656draw_scene(void) { 844draw_scene(void) {
657 switch (state.mode) { 845 switch (state.mode) {
658 case MOD_POLY_MAIN: { 846 case MOD_POLY_MAIN: {
@@ -661,6 +849,12 @@ draw_scene(void) {
661 case MOD_POLY_SETUP: { 849 case MOD_POLY_SETUP: {
662 draw_poly_setup(); 850 draw_poly_setup();
663 } break; 851 } break;
852 case MOD_POLY_KBD: {
853 draw_kbd(0, colors[0]);
854 draw_kbd(2, colors[1]);
855 draw_kbd(4, colors[2]);
856 draw_kbd(6, colors[3]);
857 } break;
664 } 858 }
665} 859}
666 860
@@ -682,15 +876,20 @@ app_timer_event() {
682void 876void
683app_init(const u16 *adc_raw) { 877app_init(const u16 *adc_raw) {
684 // example - load button states from flash 878 // example - load button states from flash
685 state = (State){
686 .active = 1,
687 .stealing = POLY_STEAL_OFF,
688 .ch_min = 0,
689 .ch_max = 7,
690 .ch_listen = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
691 .mode = MOD_POLY_MAIN,
692 };
693 hal_read_flash(0, (u8*)&state, sizeof(State)); 879 hal_read_flash(0, (u8*)&state, sizeof(State));
880 if (state.magic != 0xbadd10de) {
881 state = (State){
882 .magic = 0xbadd10de,
883 .active = 1,
884 .stealing = POLY_STEAL_OFF,
885 .ch_min = 0,
886 .ch_max = 7,
887 .ch_listen = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
888 .mode = MOD_POLY_MAIN,
889 .kbd_octave = 0,
890 };
891 }
892 state.mode = MOD_POLY_KBD; // DEBUG:
694 893
695 // store off the raw ADC frame pointer for later use 894 // store off the raw ADC frame pointer for later use
696 g_ADC = adc_raw; 895 g_ADC = adc_raw;