From 089f9ec86e90368c391c1c89e45301310cc7725a Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 5 May 2021 15:25:04 +0200 Subject: Add control for wave synth (channel 3) --- src/common.h | 34 +++++++++++++++++++++++---- src/main.c | 7 +----- src/sequencer.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 97 insertions(+), 17 deletions(-) diff --git a/src/common.h b/src/common.h index d78f11a..f0c0886 100644 --- a/src/common.h +++ b/src/common.h @@ -561,8 +561,8 @@ int bios_div(int num, int denom); typedef enum { SOUND_SQUARE1 = (0x1 << 0), SOUND_SQUARE2 = (0x1 << 1), - SOUND_WAVE = (0x4 << 2), - SOUND_NOISE = (0x8 << 3), + SOUND_WAVE = (0x1 << 2), + SOUND_NOISE = (0x1 << 3), } SoundChannel; u16 @@ -602,9 +602,33 @@ sound_volume(SoundChannel channels, u8 volume) { #define SOUND_SWEEP_DIR(N) ((N) << 0x3) #define SOUND_SWEEP_TIME(N) ((N) << 0x4) -// DMG square frequency bits. -#define SOUND_SQUARE_TIMED (1 << 0xE) -#define SOUND_SQUARE_RESET (1 << 0xF) +// DMG frequency bits (Square/Wave). +#define SOUND_FREQ_TIMED (1 << 0xE) +#define SOUND_FREQ_RESET (1 << 0xF) + +// DMG wave ram. +#define SOUND_WAVE_RAM_0 *((vu32*)(MEM_IO + 0x90)) +#define SOUND_WAVE_RAM_1 *((vu32*)(MEM_IO + 0x94)) +#define SOUND_WAVE_RAM_2 *((vu32*)(MEM_IO + 0x98)) +#define SOUND_WAVE_RAM_3 *((vu32*)(MEM_IO + 0x9C)) + +// DMG wave control bits. +#define SOUND_WAVE_LENGTH(N) (N) +#define SOUND_WAVE_MUTE 0x0 +#define SOUND_WAVE_VOL_100 (0x1 << 0xD) +#define SOUND_WAVE_VOL_75 (0x4 << 0xD) +#define SOUND_WAVE_VOL_50 (0x2 << 0xD) +#define SOUND_WAVE_VOL_25 (0x3 << 0xD) + +// DMG wave mode bits. +#define SOUND_WAVE_BANK_MODE(N) ((N) << 0x5) +#define SOUND_WAVE_BANK_SELECT(N) ((N) << 0x6) +#define SOUND_WAVE_ENABLE (1 << 0x7) + +typedef u8 WaveBank[32]; + +// typedef u32 WaveBank[4]; +#define SOUND_WAVE_RAM ((WaveBank*)(MEM_IO + 0x90)) typedef enum { NOTE_C_2 , NOTE_C_SHARP_2 , NOTE_D_2 , NOTE_D_SHARP_2 , diff --git a/src/main.c b/src/main.c index b93abe6..48538fb 100644 --- a/src/main.c +++ b/src/main.c @@ -20,8 +20,6 @@ int main(void) { // sequential. DISP_CTRL = DISP_ENABLE_SPRITES | DISP_MODE_0 | DISP_BG_0; - init_sequencer_sprites(); - // Initialize text engine. // txt_init(0, COLOR_RED, 0); @@ -29,10 +27,7 @@ int main(void) { irq_init(); irs_set(IRQ_VBLANK, irs_stub); - // turn sound on - SOUND_STATUS = SOUND_ENABLE; - SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2, 3); - SOUND_DSOUND_MASTER = SOUND_DMG100; + init_sequencer(); // Initialize timer. while(true) { diff --git a/src/sequencer.c b/src/sequencer.c index f4006c4..1447056 100644 --- a/src/sequencer.c +++ b/src/sequencer.c @@ -13,7 +13,7 @@ #define SEQ_DUTYCYCLE_POS_Y 10 - 8 #define SEQ_SWEEP_POS_X SEQ_DUTYCYCLE_POS_X + SEQ_ENV_DIST #define SEQ_SWEEP_POS_Y SEQ_ENV_POS_Y -#define SEQ_N_CHANNELS 2 +#define SEQ_N_CHANNELS 3 u32 sprite_note_names[] = { 0x000000e0, 0x202020e0, 0x0000000e, 0x080e020e, @@ -273,7 +273,7 @@ typedef struct SeqTrigger { // TODO: Do we need other fields? } SeqTrigger; -static SeqTrigger sequences[2][16] = { +static SeqTrigger sequences[3][16] = { // Synth 1 { {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, @@ -312,6 +312,25 @@ static SeqTrigger sequences[2][16] = { {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}, + }, }; // TODO: Support for copy paste anything, contextual. If we are on trigger @@ -346,19 +365,31 @@ irq_timer_0(void) { | 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_SQUARE1_FREQ = SOUND_FREQ_RESET | sound_rates[active_note]; } } - SeqTrigger *trig = &sequences[1][step_counter]; { + 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_SQUARE2_FREQ = SOUND_FREQ_RESET + | sound_rates[active_note]; + } + } + { + 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; + SOUND_WAVE_FREQ = SOUND_FREQ_RESET | sound_rates[active_note]; } } @@ -752,7 +783,7 @@ init_sequencer_sprites(void) { int base_tile = sprites[sprite_id].tile_start + 8; seq_sprites[53].id = obj_counter++; seq_sprites[53].base_tile = base_tile; - seq_sprites[53].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y) | OBJ_HIDDEN; + seq_sprites[53].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y); seq_sprites[53].obj_attr_1 = OBJ_SIZE_MID | OBJ_X_COORD(x); seq_sprites[53].obj_attr_2 = base_tile | OBJ_PAL_BANK(0); } @@ -1084,11 +1115,15 @@ handle_sequencer_input(void) { } else { TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; SOUND_SQUARE1_CTRL = 0; + SOUND_SQUARE2_CTRL = 0; + SOUND_WAVE_CTRL = 0; } } if (key_pressed(KEY_SELECT)) { TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; SOUND_SQUARE1_CTRL = 0; + SOUND_SQUARE2_CTRL = 0; + SOUND_WAVE_CTRL = 0; } } @@ -1102,3 +1137,29 @@ render_sequencer_sprites(void) { OBJ_ATTR_2(id) = seq_sprites[i].obj_attr_2; } } + +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; +} -- cgit v1.2.1