From fb00cfba1c80f64be48fa543b94d626c958e20e6 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 6 May 2021 14:54:27 +0200 Subject: Hook up triggers to wave synth --- src/sequencer.c | 224 ++++++++++++++++++++++++++++++++------------------------ 1 file 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[] = { 0x00000000, 0x00000000, 0x0008080e, 0x00000000, }; +static u8 sine_wave[] = { + 0x89, 0xBC, 0xDE, 0xEF, + 0xFE, 0xED, 0xCB, 0x98, + 0x76, 0x43, 0x21, 0x10, + 0x01, 0x12, 0x34, 0x67, +}; + +static u8 saw_wave[16] = { + 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, 0xcd, 0xef, + 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, 0xcd, 0xef, +}; + +// TODO: Should we split this up in individual trigger structs depending on the +// channel? typedef struct SeqTrigger { bool trigger; Note note; @@ -272,66 +288,70 @@ typedef struct SeqTrigger { u8 sweep_number; u8 sweep_time; u8 sweep_direction; + u8 wave_volume; + u8 wave_mode; + u8 *wave_a; + u8 *wave_b; // TODO: Do we need other fields? } SeqTrigger; static SeqTrigger sequences[3][16] = { // Synth 1 { - {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, }, // Synth 2 { - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, }, // Synth 3 { - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, - {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, + {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &saw_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &saw_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave}, + {false, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &sine_wave}, + {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &saw_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &saw_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave}, + {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &sine_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &saw_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &saw_wave}, + {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &saw_wave, &sine_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave}, + {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, &sine_wave, &sine_wave}, }, }; @@ -387,10 +407,53 @@ irq_timer_0(void) { SeqTrigger *trig = &sequences[2][step_counter]; active_note = trig->note; if (trig->trigger) { - SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) - | SOUND_WAVE_BANK_SELECT(0) - | SOUND_WAVE_ENABLE; - SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100; + // Update both banks. + // TODO: Actually depends on which bank is selected, no need to + // update both if only one is playing. + // TODO: Should we compare if previous and current wave are the + // same before updating? + SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1); + memcpy(SOUND_WAVE_RAM, trig->wave_a, 32); + SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0); + memcpy(SOUND_WAVE_RAM, trig->wave_b, 32); + + switch (trig->wave_mode) { + case 0: { + SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) + | SOUND_WAVE_BANK_SELECT(0); + } break; + case 1: { + SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) + | SOUND_WAVE_BANK_SELECT(1); + } break; + case 2: { + SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1) + | SOUND_WAVE_BANK_SELECT(0); + } break; + case 3: { + SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1) + | SOUND_WAVE_BANK_SELECT(1); + } break; + } + SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE; + + switch (trig->wave_volume) { + case 0: { + SOUND_WAVE_CTRL = SOUND_WAVE_MUTE; + } break; + case 1: { + SOUND_WAVE_CTRL = SOUND_WAVE_VOL_25; + } break; + case 2: { + SOUND_WAVE_CTRL = SOUND_WAVE_VOL_50; + } break; + case 3: { + SOUND_WAVE_CTRL = SOUND_WAVE_VOL_75; + } break; + case 4: { + SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100; + } break; + } SOUND_WAVE_FREQ = SOUND_FREQ_RESET | sound_rates[active_note]; } @@ -483,11 +546,24 @@ typedef enum { int trig_selection_loc = 0; int param_selection_loc = 0; -int channel_selection_loc = 0; +int channel_selection_loc = 2; SeqSelect current_selection = SEQ_SELECT_TRIGGER; SeqSprite seq_sprites[57] = {0}; +void +draw_wave_pattern(u8 *pattern, int x, int y, Color clr) { + for (size_t i = 0; i < 16; ++i) { + u8 byte = pattern[i]; + u8 first = (byte >> 4) & 0xF; + u8 second = byte & 0xF; + FRAMEBUFFER[y + 16 - first][x + i * 4] = clr; + FRAMEBUFFER[y + 16 - first][x + i * 4 + 1] = clr; + FRAMEBUFFER[y + 16 - second][x + i * 4 + 2] = clr; + FRAMEBUFFER[y + 16 - second][x + i * 4 + 3] = clr; + } +} + void init_sequencer_sprites(void) { // Load palette. @@ -497,52 +573,6 @@ init_sequencer_sprites(void) { init_sprite_pal(48, COLOR_GREY); init_sprites(512); - // draw_rect(SEQ_ENV_POS_X-1, - // SEQ_ENV_POS_Y-1, - // SEQ_ENV_POS_X + 62 + 1, - // SEQ_ENV_POS_Y + 16 + 1, - // COLOR_WHITE); - - // Clear wave drawing - draw_fill_rect(SEQ_ENV_POS_X, - SEQ_ENV_POS_Y, - SEQ_ENV_POS_X + 62, - SEQ_ENV_POS_Y + 16, - COLOR_BLACK); - - // DEBUG: Testing line drawing - // draw_line( - // SEQ_ENV_POS_X, - // SEQ_ENV_POS_Y, - // SEQ_ENV_POS_X + 62, - // SEQ_ENV_POS_Y + 16, - // COLOR_RED); - - // NOTE: Trying to draw this pattern. - // 0xEFDEBC89 - // 0x98CBEDFE - // 0x10214376 - // 0x67341201 - u8 sine_wave[] = { - 0x89, 0xBC, 0xDE, 0xEF, - 0xFE, 0xED, 0xCB, 0x98, - 0x76, 0x43, 0x21, 0x10, - 0x01, 0x12, 0x34, 0x67, - }; - // DEBUG: Drawing each byte. - int x = SEQ_ENV_POS_X; - int y = SEQ_ENV_POS_Y + 16; - for (size_t i = 0; i < 16; ++i) { - u8 byte = sine_wave[i]; - u8 first = (byte >> 4) & 0xF; - u8 second = byte & 0xF; - FRAMEBUFFER[y - first][x + i * 4] = COLOR_RED; - FRAMEBUFFER[y - first][x + i * 4 + 1] = COLOR_RED; - FRAMEBUFFER[y - second][x + i * 4 + 2] = COLOR_RED; - FRAMEBUFFER[y - second][x + i * 4 + 3] = COLOR_RED; - } - - // Sprite note names. size_t sprite_id = load_packed_sprite_data(&sprite_note_names, 2, 73); for (size_t i = 0; i < 16; ++i) { @@ -1015,7 +1045,28 @@ update_sequencer_sprites(void) { // DEBUG: Hide all parameter control sprites for now. for (size_t i = 34; i <= 50; ++i) { - seq_sprites[i].obj_attr_0 = seq_sprites[i].obj_attr_0 | OBJ_HIDDEN; + seq_sprites[i].obj_attr_0 |= OBJ_HIDDEN; + } + + if (channel_selection_loc == 2) { + u8 *wave_a = sequences[channel_selection_loc][trig_selection_loc].wave_a; + u8 *wave_b = sequences[channel_selection_loc][trig_selection_loc].wave_b; + + // Draw wave patterns for this trig. + int x = SEQ_ENV_POS_X + 8; + int y = SEQ_ENV_POS_Y; + + // Clear wave A and draw. + draw_fill_rect(x, y, x + 64, y + 16, COLOR_BLACK); + draw_wave_pattern(wave_a, x, y, COLOR_RED); + // Clear wave B and draw. + draw_fill_rect(x + 64 + 16, y, x + 64 * 2 + 16, y + 16, COLOR_BLACK); + draw_wave_pattern(wave_b, x + 64 + 16, y, COLOR_CYAN); + } else { + int x = SEQ_ENV_POS_X + 8; + int y = SEQ_ENV_POS_Y; + draw_fill_rect(x, y, x + 64, y + 16, COLOR_BLACK); + draw_fill_rect(x + 64 + 16, y, x + 64 * 2 + 16, y + 16, COLOR_BLACK); } } @@ -1195,24 +1246,5 @@ void init_sequencer() { init_sequencer_sprites(); SOUND_STATUS = SOUND_ENABLE; SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2 | SOUND_WAVE, 3); - SOUND_DSOUND_MASTER = SOUND_DMG100; - - // TODO: Currently static, need to figure out a way of controlling these - // parameters. - // Select bank 0 for writing (bank 1 playing). - SOUND_WAVE_RAM_0 = 0xEFDEBC89; - SOUND_WAVE_RAM_1 = 0x98CBEDFE; - SOUND_WAVE_RAM_2 = 0x10214376; - SOUND_WAVE_RAM_3 = 0x67341201; - SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1) | SOUND_WAVE_BANK_SELECT(1); - - // SINE WAVE - SOUND_WAVE_RAM_0 = 0xEFDEBC89; - SOUND_WAVE_RAM_1 = 0x98CBEDFE; - SOUND_WAVE_RAM_2 = 0x10214376; - SOUND_WAVE_RAM_3 = 0x67341201; - - // Select bank 0 for playing. - SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) | SOUND_WAVE_BANK_SELECT(0); - SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE; + SOUND_DSOUND_MASTER = SOUND_DMG25; } -- cgit v1.2.1