summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-05-06 14:54:27 +0200
committerBad Diode <bd@badd10de.dev>2021-05-06 14:54:27 +0200
commitfb00cfba1c80f64be48fa543b94d626c958e20e6 (patch)
tree935482e9f6f27f805e697bc6ebf9f3873f48cb2f
parenta170d44a34b03a4d0d475c38aac9651fbe666b33 (diff)
downloadgba-experiments-fb00cfba1c80f64be48fa543b94d626c958e20e6.tar.gz
gba-experiments-fb00cfba1c80f64be48fa543b94d626c958e20e6.zip
Hook up triggers to wave synth
-rw-r--r--src/sequencer.c224
1 files changed, 128 insertions, 96 deletions
diff --git a/src/sequencer.c b/src/sequencer.c
index fccc42a..b95a94a 100644
--- a/src/sequencer.c
+++ b/src/sequencer.c
@@ -262,6 +262,22 @@ u32 sprite_channels_selector[] = {
262 0x00000000, 0x00000000, 0x0008080e, 0x00000000, 262 0x00000000, 0x00000000, 0x0008080e, 0x00000000,
263}; 263};
264 264
265static u8 sine_wave[] = {
266 0x89, 0xBC, 0xDE, 0xEF,
267 0xFE, 0xED, 0xCB, 0x98,
268 0x76, 0x43, 0x21, 0x10,
269 0x01, 0x12, 0x34, 0x67,
270};
271
272static u8 saw_wave[16] = {
273 0x01, 0x23, 0x45, 0x67,
274 0x89, 0xab, 0xcd, 0xef,
275 0x01, 0x23, 0x45, 0x67,
276 0x89, 0xab, 0xcd, 0xef,
277};
278
279// TODO: Should we split this up in individual trigger structs depending on the
280// channel?
265typedef struct SeqTrigger { 281typedef struct SeqTrigger {
266 bool trigger; 282 bool trigger;
267 Note note; 283 Note note;
@@ -272,66 +288,70 @@ typedef struct SeqTrigger {
272 u8 sweep_number; 288 u8 sweep_number;
273 u8 sweep_time; 289 u8 sweep_time;
274 u8 sweep_direction; 290 u8 sweep_direction;
291 u8 wave_volume;
292 u8 wave_mode;
293 u8 *wave_a;
294 u8 *wave_b;
275 // TODO: Do we need other fields? 295 // TODO: Do we need other fields?
276} SeqTrigger; 296} SeqTrigger;
277 297
278static SeqTrigger sequences[3][16] = { 298static SeqTrigger sequences[3][16] = {
279 // Synth 1 299 // Synth 1
280 { 300 {
281 {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 301 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
282 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 302 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
283 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 303 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
284 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 304 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
285 {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 305 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
286 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 306 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
287 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 307 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
288 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 308 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
289 {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 309 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
290 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 310 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
291 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 311 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
292 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 312 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
293 {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 313 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
294 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 314 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
295 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 315 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
296 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, 316 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0},
297 }, 317 },
298 // Synth 2 318 // Synth 2
299 { 319 {
300 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 320 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
301 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 321 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
302 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 322 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
303 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 323 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
304 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 324 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
305 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 325 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
306 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 326 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
307 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 327 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
308 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 328 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
309 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 329 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
310 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 330 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
311 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 331 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
312 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 332 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
313 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 333 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
314 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 334 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
315 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 335 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0},
316 }, 336 },
317 // Synth 3 337 // Synth 3
318 { 338 {
319 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 339 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &saw_wave},
320 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 340 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &saw_wave},
321 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 341 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave},
322 {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0}, 342 {false, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &sine_wave},
323 {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0}, 343 {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave},
324 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 344 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &saw_wave},
325 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 345 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &saw_wave},
326 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 346 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave},
327 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 347 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &sine_wave},
328 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 348 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave},
329 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 349 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &saw_wave},
330 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 350 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &saw_wave},
331 {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0}, 351 {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave},
332 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 352 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &sine_wave},
333 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 353 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave},
334 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, 354 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave},
335 }, 355 },
336}; 356};
337 357
@@ -387,10 +407,53 @@ irq_timer_0(void) {
387 SeqTrigger *trig = &sequences[2][step_counter]; 407 SeqTrigger *trig = &sequences[2][step_counter];
388 active_note = trig->note; 408 active_note = trig->note;
389 if (trig->trigger) { 409 if (trig->trigger) {
390 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) 410 // Update both banks.
391 | SOUND_WAVE_BANK_SELECT(0) 411 // TODO: Actually depends on which bank is selected, no need to
392 | SOUND_WAVE_ENABLE; 412 // update both if only one is playing.
393 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100; 413 // TODO: Should we compare if previous and current wave are the
414 // same before updating?
415 SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1);
416 memcpy(SOUND_WAVE_RAM, trig->wave_a, 32);
417 SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0);
418 memcpy(SOUND_WAVE_RAM, trig->wave_b, 32);
419
420 switch (trig->wave_mode) {
421 case 0: {
422 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0)
423 | SOUND_WAVE_BANK_SELECT(0);
424 } break;
425 case 1: {
426 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0)
427 | SOUND_WAVE_BANK_SELECT(1);
428 } break;
429 case 2: {
430 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1)
431 | SOUND_WAVE_BANK_SELECT(0);
432 } break;
433 case 3: {
434 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1)
435 | SOUND_WAVE_BANK_SELECT(1);
436 } break;
437 }
438 SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE;
439
440 switch (trig->wave_volume) {
441 case 0: {
442 SOUND_WAVE_CTRL = SOUND_WAVE_MUTE;
443 } break;
444 case 1: {
445 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_25;
446 } break;
447 case 2: {
448 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_50;
449 } break;
450 case 3: {
451 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_75;
452 } break;
453 case 4: {
454 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100;
455 } break;
456 }
394 SOUND_WAVE_FREQ = SOUND_FREQ_RESET 457 SOUND_WAVE_FREQ = SOUND_FREQ_RESET
395 | sound_rates[active_note]; 458 | sound_rates[active_note];
396 } 459 }
@@ -483,12 +546,25 @@ typedef enum {
483 546
484int trig_selection_loc = 0; 547int trig_selection_loc = 0;
485int param_selection_loc = 0; 548int param_selection_loc = 0;
486int channel_selection_loc = 0; 549int channel_selection_loc = 2;
487SeqSelect current_selection = SEQ_SELECT_TRIGGER; 550SeqSelect current_selection = SEQ_SELECT_TRIGGER;
488 551
489SeqSprite seq_sprites[57] = {0}; 552SeqSprite seq_sprites[57] = {0};
490 553
491void 554void
555draw_wave_pattern(u8 *pattern, int x, int y, Color clr) {
556 for (size_t i = 0; i < 16; ++i) {
557 u8 byte = pattern[i];
558 u8 first = (byte >> 4) & 0xF;
559 u8 second = byte & 0xF;
560 FRAMEBUFFER[y + 16 - first][x + i * 4] = clr;
561 FRAMEBUFFER[y + 16 - first][x + i * 4 + 1] = clr;
562 FRAMEBUFFER[y + 16 - second][x + i * 4 + 2] = clr;
563 FRAMEBUFFER[y + 16 - second][x + i * 4 + 3] = clr;
564 }
565}
566
567void
492init_sequencer_sprites(void) { 568init_sequencer_sprites(void) {
493 // Load palette. 569 // Load palette.
494 init_sprite_pal(0, COLOR_WHITE); 570 init_sprite_pal(0, COLOR_WHITE);
@@ -497,52 +573,6 @@ init_sequencer_sprites(void) {
497 init_sprite_pal(48, COLOR_GREY); 573 init_sprite_pal(48, COLOR_GREY);
498 init_sprites(512); 574 init_sprites(512);
499 575
500 // draw_rect(SEQ_ENV_POS_X-1,
501 // SEQ_ENV_POS_Y-1,
502 // SEQ_ENV_POS_X + 62 + 1,
503 // SEQ_ENV_POS_Y + 16 + 1,
504 // COLOR_WHITE);
505
506 // Clear wave drawing
507 draw_fill_rect(SEQ_ENV_POS_X,
508 SEQ_ENV_POS_Y,
509 SEQ_ENV_POS_X + 62,
510 SEQ_ENV_POS_Y + 16,
511 COLOR_BLACK);
512
513 // DEBUG: Testing line drawing
514 // draw_line(
515 // SEQ_ENV_POS_X,
516 // SEQ_ENV_POS_Y,
517 // SEQ_ENV_POS_X + 62,
518 // SEQ_ENV_POS_Y + 16,
519 // COLOR_RED);
520
521 // NOTE: Trying to draw this pattern.
522 // 0xEFDEBC89
523 // 0x98CBEDFE
524 // 0x10214376
525 // 0x67341201
526 u8 sine_wave[] = {
527 0x89, 0xBC, 0xDE, 0xEF,
528 0xFE, 0xED, 0xCB, 0x98,
529 0x76, 0x43, 0x21, 0x10,
530 0x01, 0x12, 0x34, 0x67,
531 };
532 // DEBUG: Drawing each byte.
533 int x = SEQ_ENV_POS_X;
534 int y = SEQ_ENV_POS_Y + 16;
535 for (size_t i = 0; i < 16; ++i) {
536 u8 byte = sine_wave[i];
537 u8 first = (byte >> 4) & 0xF;
538 u8 second = byte & 0xF;
539 FRAMEBUFFER[y - first][x + i * 4] = COLOR_RED;
540 FRAMEBUFFER[y - first][x + i * 4 + 1] = COLOR_RED;
541 FRAMEBUFFER[y - second][x + i * 4 + 2] = COLOR_RED;
542 FRAMEBUFFER[y - second][x + i * 4 + 3] = COLOR_RED;
543 }
544
545
546 // Sprite note names. 576 // Sprite note names.
547 size_t sprite_id = load_packed_sprite_data(&sprite_note_names, 2, 73); 577 size_t sprite_id = load_packed_sprite_data(&sprite_note_names, 2, 73);
548 for (size_t i = 0; i < 16; ++i) { 578 for (size_t i = 0; i < 16; ++i) {
@@ -1015,7 +1045,28 @@ update_sequencer_sprites(void) {
1015 1045
1016 // DEBUG: Hide all parameter control sprites for now. 1046 // DEBUG: Hide all parameter control sprites for now.
1017 for (size_t i = 34; i <= 50; ++i) { 1047 for (size_t i = 34; i <= 50; ++i) {
1018 seq_sprites[i].obj_attr_0 = seq_sprites[i].obj_attr_0 | OBJ_HIDDEN; 1048 seq_sprites[i].obj_attr_0 |= OBJ_HIDDEN;
1049 }
1050
1051 if (channel_selection_loc == 2) {
1052 u8 *wave_a = sequences[channel_selection_loc][trig_selection_loc].wave_a;
1053 u8 *wave_b = sequences[channel_selection_loc][trig_selection_loc].wave_b;
1054
1055 // Draw wave patterns for this trig.
1056 int x = SEQ_ENV_POS_X + 8;
1057 int y = SEQ_ENV_POS_Y;
1058
1059 // Clear wave A and draw.
1060 draw_fill_rect(x, y, x + 64, y + 16, COLOR_BLACK);
1061 draw_wave_pattern(wave_a, x, y, COLOR_RED);
1062 // Clear wave B and draw.
1063 draw_fill_rect(x + 64 + 16, y, x + 64 * 2 + 16, y + 16, COLOR_BLACK);
1064 draw_wave_pattern(wave_b, x + 64 + 16, y, COLOR_CYAN);
1065 } else {
1066 int x = SEQ_ENV_POS_X + 8;
1067 int y = SEQ_ENV_POS_Y;
1068 draw_fill_rect(x, y, x + 64, y + 16, COLOR_BLACK);
1069 draw_fill_rect(x + 64 + 16, y, x + 64 * 2 + 16, y + 16, COLOR_BLACK);
1019 } 1070 }
1020} 1071}
1021 1072
@@ -1195,24 +1246,5 @@ void init_sequencer() {
1195 init_sequencer_sprites(); 1246 init_sequencer_sprites();
1196 SOUND_STATUS = SOUND_ENABLE; 1247 SOUND_STATUS = SOUND_ENABLE;
1197 SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2 | SOUND_WAVE, 3); 1248 SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2 | SOUND_WAVE, 3);
1198 SOUND_DSOUND_MASTER = SOUND_DMG100; 1249 SOUND_DSOUND_MASTER = SOUND_DMG25;
1199
1200 // TODO: Currently static, need to figure out a way of controlling these
1201 // parameters.
1202 // Select bank 0 for writing (bank 1 playing).
1203 SOUND_WAVE_RAM_0 = 0xEFDEBC89;
1204 SOUND_WAVE_RAM_1 = 0x98CBEDFE;
1205 SOUND_WAVE_RAM_2 = 0x10214376;
1206 SOUND_WAVE_RAM_3 = 0x67341201;
1207 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1) | SOUND_WAVE_BANK_SELECT(1);
1208
1209 // SINE WAVE
1210 SOUND_WAVE_RAM_0 = 0xEFDEBC89;
1211 SOUND_WAVE_RAM_1 = 0x98CBEDFE;
1212 SOUND_WAVE_RAM_2 = 0x10214376;
1213 SOUND_WAVE_RAM_3 = 0x67341201;
1214
1215 // Select bank 0 for playing.
1216 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) | SOUND_WAVE_BANK_SELECT(0);
1217 SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE;
1218} 1250}