From 59966e7639c4ad3ffdd6dc3566e1b5aae003e3cd Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Tue, 4 May 2021 14:55:42 +0200 Subject: Enable sequencing on both square wave channels --- src/sequencer.c | 178 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 71 deletions(-) diff --git a/src/sequencer.c b/src/sequencer.c index ae06031..6837b1e 100644 --- a/src/sequencer.c +++ b/src/sequencer.c @@ -273,23 +273,45 @@ typedef struct SeqTrigger { // TODO: Do we need other fields? } SeqTrigger; -static SeqTrigger sequence_synth[16] = { - {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}, - {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}, - {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}, - {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}, +static SeqTrigger sequences[2][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}, + {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}, + {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}, + {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}, + }, + // 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}, + {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_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}, + }, }; // TODO: Support for copy paste anything, contextual. If we are on trigger @@ -302,24 +324,38 @@ static SeqTrigger sequence_synth[16] = { // TODO: Allow muting and unmuting channels. Show in grey when muted. // TODO: Show channel beat indicator if a note is being played. -static int bpm = 180; +static int bpm = 115; static int step_counter = 0; static Note active_note; void irq_timer_0(void) { - SeqTrigger *trig = &sequence_synth[step_counter]; - active_note = trig->note; - if (trig->trigger) { - SOUND_SQUARE1_SWEEP = SOUND_SWEEP_NUMBER(trig->sweep_number) - | SOUND_SWEEP_DIR(trig->sweep_direction) - | SOUND_SWEEP_TIME(trig->sweep_time); - SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume) - | SOUND_SQUARE_ENV_TIME(trig->env_time) - | SOUND_SQUARE_ENV_DIR(trig->env_direction) - | SOUND_SQUARE_DUTY(trig->duty_cycle); - SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET - | sound_rates[active_note]; + { + SeqTrigger *trig = &sequences[0][step_counter]; + active_note = trig->note; + if (trig->trigger) { + SOUND_SQUARE1_SWEEP = SOUND_SWEEP_NUMBER(trig->sweep_number) + | SOUND_SWEEP_DIR(trig->sweep_direction) + | SOUND_SWEEP_TIME(trig->sweep_time); + SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume) + | SOUND_SQUARE_ENV_TIME(trig->env_time) + | SOUND_SQUARE_ENV_DIR(trig->env_direction) + | SOUND_SQUARE_DUTY(trig->duty_cycle); + SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET + | sound_rates[active_note]; + } + } + SeqTrigger *trig = &sequences[1][step_counter]; + { + active_note = trig->note; + if (trig->trigger) { + SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume) + | SOUND_SQUARE_ENV_TIME(trig->env_time) + | SOUND_SQUARE_ENV_DIR(trig->env_direction) + | SOUND_SQUARE_DUTY(trig->duty_cycle); + SOUND_SQUARE2_FREQ = SOUND_SQUARE_RESET + | sound_rates[active_note]; + } } step_counter = (step_counter + 1) % 16; } @@ -755,12 +791,12 @@ update_sequencer_sprites(void) { // 000-015: Step note names. for (size_t i = 0; i < 16; ++i) { // Each note name is made of 2 8x8 tiles (16x8). - size_t base_tile = sequence_synth[i].note * 2; + size_t base_tile = sequences[channel_selection_loc][i].note * 2; // TODO: Show the note name if is within the duration, hide when trigger // is off or duration of previous note was cut short. If not triggered // but note name appears, needs to be on a different palette bank. - if (!sequence_synth[i].trigger) { + if (!sequences[channel_selection_loc][i].trigger) { seq_sprites[i].obj_attr_0 |= OBJ_HIDDEN; } else { seq_sprites[i].obj_attr_0 &= ~OBJ_HIDDEN; @@ -808,7 +844,7 @@ update_sequencer_sprites(void) { // 36: Envelope initial volume. { - size_t tile_diff = sequence_synth[trig_selection_loc].env_volume * 4; + size_t tile_diff = sequences[channel_selection_loc][trig_selection_loc].env_volume * 4; size_t base_tile = seq_sprites[35].base_tile; size_t tile = base_tile + tile_diff; seq_sprites[35].obj_attr_2 = tile; @@ -816,7 +852,7 @@ update_sequencer_sprites(void) { // 38: Envelope time. { - size_t tile_diff = sequence_synth[trig_selection_loc].env_time * 4; + size_t tile_diff = sequences[channel_selection_loc][trig_selection_loc].env_time * 4; size_t base_tile = seq_sprites[37].base_tile; size_t tile = base_tile + tile_diff; seq_sprites[37].obj_attr_2 = tile; @@ -825,7 +861,7 @@ update_sequencer_sprites(void) { // 40: Envelope direction. { size_t tile_diff = 0; - if (sequence_synth[trig_selection_loc].env_direction == 0) { + if (sequences[channel_selection_loc][trig_selection_loc].env_direction == 0) { tile_diff = 4; } size_t base_tile = seq_sprites[39].base_tile; @@ -835,7 +871,7 @@ update_sequencer_sprites(void) { // 43: Duty cycle. { - size_t tile_diff = sequence_synth[trig_selection_loc].duty_cycle * 4; + size_t tile_diff = sequences[channel_selection_loc][trig_selection_loc].duty_cycle * 4; size_t base_tile = seq_sprites[42].base_tile; size_t tile = base_tile + tile_diff; seq_sprites[42].obj_attr_2 = tile; @@ -843,7 +879,7 @@ update_sequencer_sprites(void) { // 45: Sweep number. { - size_t tile_diff = sequence_synth[trig_selection_loc].sweep_number; + size_t tile_diff = sequences[channel_selection_loc][trig_selection_loc].sweep_number; size_t base_tile = seq_sprites[44].base_tile; size_t tile = base_tile + tile_diff; seq_sprites[44].obj_attr_2 = tile; @@ -851,7 +887,7 @@ update_sequencer_sprites(void) { // 47: Sweep time. { - size_t tile_diff = sequence_synth[trig_selection_loc].sweep_time; + size_t tile_diff = sequences[channel_selection_loc][trig_selection_loc].sweep_time; size_t base_tile = seq_sprites[46].base_tile; size_t tile = base_tile + tile_diff; seq_sprites[46].obj_attr_2 = tile; @@ -859,7 +895,7 @@ update_sequencer_sprites(void) { // 49: Sweep direction. { - size_t tile_diff = sequence_synth[trig_selection_loc].sweep_direction * 4; + size_t tile_diff = sequences[channel_selection_loc][trig_selection_loc].sweep_direction * 4; size_t base_tile = seq_sprites[48].base_tile; size_t tile = base_tile + tile_diff; seq_sprites[48].obj_attr_2 = tile; @@ -911,14 +947,14 @@ handle_sequencer_input(void) { } else if (key_pressed(KEY_UP) || key_pressed(KEY_DOWN)) { trig_selection_loc = (trig_selection_loc + 8) % 16; } else if (key_pressed(KEY_B)) { - sequence_synth[trig_selection_loc].trigger ^= 1; + sequences[channel_selection_loc][trig_selection_loc].trigger ^= 1; } else if (key_pressed(KEY_L)) { - sequence_synth[trig_selection_loc].note = CLAMP( - sequence_synth[trig_selection_loc].note - 1, + sequences[channel_selection_loc][trig_selection_loc].note = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].note - 1, NOTE_C_2, NOTE_C_8); } else if (key_pressed(KEY_R)) { - sequence_synth[trig_selection_loc].note = CLAMP( - sequence_synth[trig_selection_loc].note + 1, + sequences[channel_selection_loc][trig_selection_loc].note = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].note + 1, NOTE_C_2, NOTE_C_8); } else if (key_pressed(KEY_A)) { // Switch to parameter selection. @@ -945,33 +981,33 @@ handle_sequencer_input(void) { if (key_pressed(KEY_L)) { switch (param_selection_loc) { case 0: { - sequence_synth[trig_selection_loc].env_volume = CLAMP( - sequence_synth[trig_selection_loc].env_volume - 1, 0, 15); + sequences[channel_selection_loc][trig_selection_loc].env_volume = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].env_volume - 1, 0, 15); } break; case 1: { - sequence_synth[trig_selection_loc].env_time = CLAMP( - sequence_synth[trig_selection_loc].env_time - 1, 0, 7); + sequences[channel_selection_loc][trig_selection_loc].env_time = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].env_time - 1, 0, 7); } break; case 2: { - sequence_synth[trig_selection_loc].env_direction ^= 1; + sequences[channel_selection_loc][trig_selection_loc].env_direction ^= 1; } break; case 3: { - sequence_synth[trig_selection_loc].duty_cycle = CLAMP( - sequence_synth[trig_selection_loc].duty_cycle - 1, 0, 3); + sequences[channel_selection_loc][trig_selection_loc].duty_cycle = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].duty_cycle - 1, 0, 3); } break; case 4: { - sequence_synth[trig_selection_loc].sweep_number = CLAMP( - sequence_synth[trig_selection_loc].sweep_number - 1, 0, 7); + sequences[channel_selection_loc][trig_selection_loc].sweep_number = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].sweep_number - 1, 0, 7); } break; case 5: { - sequence_synth[trig_selection_loc].sweep_time = CLAMP( - sequence_synth[trig_selection_loc].sweep_time - 1, 0, 7); + sequences[channel_selection_loc][trig_selection_loc].sweep_time = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].sweep_time - 1, 0, 7); } break; case 6: { - if (sequence_synth[trig_selection_loc].sweep_direction == 0) { - sequence_synth[trig_selection_loc].sweep_direction = 1; + if (sequences[channel_selection_loc][trig_selection_loc].sweep_direction == 0) { + sequences[channel_selection_loc][trig_selection_loc].sweep_direction = 1; } else { - sequence_synth[trig_selection_loc].sweep_direction = 0; + sequences[channel_selection_loc][trig_selection_loc].sweep_direction = 0; } } break; } @@ -979,30 +1015,30 @@ handle_sequencer_input(void) { if (key_pressed(KEY_R)) { switch (param_selection_loc) { case 0: { - sequence_synth[trig_selection_loc].env_volume = CLAMP( - sequence_synth[trig_selection_loc].env_volume + 1, 0, 15); + sequences[channel_selection_loc][trig_selection_loc].env_volume = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].env_volume + 1, 0, 15); } break; case 1: { - sequence_synth[trig_selection_loc].env_time = CLAMP( - sequence_synth[trig_selection_loc].env_time + 1, 0, 7); + sequences[channel_selection_loc][trig_selection_loc].env_time = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].env_time + 1, 0, 7); } break; case 2: { - sequence_synth[trig_selection_loc].env_direction ^= 1; + sequences[channel_selection_loc][trig_selection_loc].env_direction ^= 1; } break; case 3: { - sequence_synth[trig_selection_loc].duty_cycle = CLAMP( - sequence_synth[trig_selection_loc].duty_cycle + 1, 0, 3); + sequences[channel_selection_loc][trig_selection_loc].duty_cycle = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].duty_cycle + 1, 0, 3); } break; case 4: { - sequence_synth[trig_selection_loc].sweep_number = CLAMP( - sequence_synth[trig_selection_loc].sweep_number + 1, 0, 7); + sequences[channel_selection_loc][trig_selection_loc].sweep_number = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].sweep_number + 1, 0, 7); } break; case 5: { - sequence_synth[trig_selection_loc].sweep_time = CLAMP( - sequence_synth[trig_selection_loc].sweep_time + 1, 0, 7); + sequences[channel_selection_loc][trig_selection_loc].sweep_time = CLAMP( + sequences[channel_selection_loc][trig_selection_loc].sweep_time + 1, 0, 7); } break; case 6: { - sequence_synth[trig_selection_loc].sweep_direction ^= 1; + sequences[channel_selection_loc][trig_selection_loc].sweep_direction ^= 1; } break; } } @@ -1014,7 +1050,7 @@ handle_sequencer_input(void) { // Enable disable trigger. if (key_pressed(KEY_B)) { - sequence_synth[trig_selection_loc].trigger ^= 1; + sequences[channel_selection_loc][trig_selection_loc].trigger ^= 1; } } else if (current_selection == SEQ_SELECT_CHANNEL) { if (key_pressed(KEY_RIGHT)) { -- cgit v1.2.1