diff options
author | Bad Diode <bd@badd10de.dev> | 2021-05-05 15:25:04 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-05-05 15:25:04 +0200 |
commit | 089f9ec86e90368c391c1c89e45301310cc7725a (patch) | |
tree | 5e99a6c7550433d403cb9c57d8fb496b2a541219 | |
parent | e1c4894a016682aed8a0fbd3837711c6f2781876 (diff) | |
download | gba-experiments-089f9ec86e90368c391c1c89e45301310cc7725a.tar.gz gba-experiments-089f9ec86e90368c391c1c89e45301310cc7725a.zip |
Add control for wave synth (channel 3)
-rw-r--r-- | src/common.h | 34 | ||||
-rw-r--r-- | src/main.c | 7 | ||||
-rw-r--r-- | 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); | |||
561 | typedef enum { | 561 | typedef enum { |
562 | SOUND_SQUARE1 = (0x1 << 0), | 562 | SOUND_SQUARE1 = (0x1 << 0), |
563 | SOUND_SQUARE2 = (0x1 << 1), | 563 | SOUND_SQUARE2 = (0x1 << 1), |
564 | SOUND_WAVE = (0x4 << 2), | 564 | SOUND_WAVE = (0x1 << 2), |
565 | SOUND_NOISE = (0x8 << 3), | 565 | SOUND_NOISE = (0x1 << 3), |
566 | } SoundChannel; | 566 | } SoundChannel; |
567 | 567 | ||
568 | u16 | 568 | u16 |
@@ -602,9 +602,33 @@ sound_volume(SoundChannel channels, u8 volume) { | |||
602 | #define SOUND_SWEEP_DIR(N) ((N) << 0x3) | 602 | #define SOUND_SWEEP_DIR(N) ((N) << 0x3) |
603 | #define SOUND_SWEEP_TIME(N) ((N) << 0x4) | 603 | #define SOUND_SWEEP_TIME(N) ((N) << 0x4) |
604 | 604 | ||
605 | // DMG square frequency bits. | 605 | // DMG frequency bits (Square/Wave). |
606 | #define SOUND_SQUARE_TIMED (1 << 0xE) | 606 | #define SOUND_FREQ_TIMED (1 << 0xE) |
607 | #define SOUND_SQUARE_RESET (1 << 0xF) | 607 | #define SOUND_FREQ_RESET (1 << 0xF) |
608 | |||
609 | // DMG wave ram. | ||
610 | #define SOUND_WAVE_RAM_0 *((vu32*)(MEM_IO + 0x90)) | ||
611 | #define SOUND_WAVE_RAM_1 *((vu32*)(MEM_IO + 0x94)) | ||
612 | #define SOUND_WAVE_RAM_2 *((vu32*)(MEM_IO + 0x98)) | ||
613 | #define SOUND_WAVE_RAM_3 *((vu32*)(MEM_IO + 0x9C)) | ||
614 | |||
615 | // DMG wave control bits. | ||
616 | #define SOUND_WAVE_LENGTH(N) (N) | ||
617 | #define SOUND_WAVE_MUTE 0x0 | ||
618 | #define SOUND_WAVE_VOL_100 (0x1 << 0xD) | ||
619 | #define SOUND_WAVE_VOL_75 (0x4 << 0xD) | ||
620 | #define SOUND_WAVE_VOL_50 (0x2 << 0xD) | ||
621 | #define SOUND_WAVE_VOL_25 (0x3 << 0xD) | ||
622 | |||
623 | // DMG wave mode bits. | ||
624 | #define SOUND_WAVE_BANK_MODE(N) ((N) << 0x5) | ||
625 | #define SOUND_WAVE_BANK_SELECT(N) ((N) << 0x6) | ||
626 | #define SOUND_WAVE_ENABLE (1 << 0x7) | ||
627 | |||
628 | typedef u8 WaveBank[32]; | ||
629 | |||
630 | // typedef u32 WaveBank[4]; | ||
631 | #define SOUND_WAVE_RAM ((WaveBank*)(MEM_IO + 0x90)) | ||
608 | 632 | ||
609 | typedef enum { | 633 | typedef enum { |
610 | NOTE_C_2 , NOTE_C_SHARP_2 , NOTE_D_2 , NOTE_D_SHARP_2 , | 634 | NOTE_C_2 , NOTE_C_SHARP_2 , NOTE_D_2 , NOTE_D_SHARP_2 , |
@@ -20,8 +20,6 @@ int main(void) { | |||
20 | // sequential. | 20 | // sequential. |
21 | DISP_CTRL = DISP_ENABLE_SPRITES | DISP_MODE_0 | DISP_BG_0; | 21 | DISP_CTRL = DISP_ENABLE_SPRITES | DISP_MODE_0 | DISP_BG_0; |
22 | 22 | ||
23 | init_sequencer_sprites(); | ||
24 | |||
25 | // Initialize text engine. | 23 | // Initialize text engine. |
26 | // txt_init(0, COLOR_RED, 0); | 24 | // txt_init(0, COLOR_RED, 0); |
27 | 25 | ||
@@ -29,10 +27,7 @@ int main(void) { | |||
29 | irq_init(); | 27 | irq_init(); |
30 | irs_set(IRQ_VBLANK, irs_stub); | 28 | irs_set(IRQ_VBLANK, irs_stub); |
31 | 29 | ||
32 | // turn sound on | 30 | init_sequencer(); |
33 | SOUND_STATUS = SOUND_ENABLE; | ||
34 | SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2, 3); | ||
35 | SOUND_DSOUND_MASTER = SOUND_DMG100; | ||
36 | 31 | ||
37 | // Initialize timer. | 32 | // Initialize timer. |
38 | while(true) { | 33 | 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 @@ | |||
13 | #define SEQ_DUTYCYCLE_POS_Y 10 - 8 | 13 | #define SEQ_DUTYCYCLE_POS_Y 10 - 8 |
14 | #define SEQ_SWEEP_POS_X SEQ_DUTYCYCLE_POS_X + SEQ_ENV_DIST | 14 | #define SEQ_SWEEP_POS_X SEQ_DUTYCYCLE_POS_X + SEQ_ENV_DIST |
15 | #define SEQ_SWEEP_POS_Y SEQ_ENV_POS_Y | 15 | #define SEQ_SWEEP_POS_Y SEQ_ENV_POS_Y |
16 | #define SEQ_N_CHANNELS 2 | 16 | #define SEQ_N_CHANNELS 3 |
17 | 17 | ||
18 | u32 sprite_note_names[] = { | 18 | u32 sprite_note_names[] = { |
19 | 0x000000e0, 0x202020e0, 0x0000000e, 0x080e020e, | 19 | 0x000000e0, 0x202020e0, 0x0000000e, 0x080e020e, |
@@ -273,7 +273,7 @@ typedef struct SeqTrigger { | |||
273 | // TODO: Do we need other fields? | 273 | // TODO: Do we need other fields? |
274 | } SeqTrigger; | 274 | } SeqTrigger; |
275 | 275 | ||
276 | static SeqTrigger sequences[2][16] = { | 276 | static SeqTrigger sequences[3][16] = { |
277 | // Synth 1 | 277 | // Synth 1 |
278 | { | 278 | { |
279 | {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, | 279 | {true, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0}, |
@@ -312,6 +312,25 @@ static SeqTrigger sequences[2][16] = { | |||
312 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | 312 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, |
313 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | 313 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, |
314 | }, | 314 | }, |
315 | // Synth 3 | ||
316 | { | ||
317 | {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
318 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
319 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
320 | {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0}, | ||
321 | {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0}, | ||
322 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
323 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
324 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
325 | {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
326 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
327 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
328 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
329 | {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0}, | ||
330 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
331 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
332 | {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0}, | ||
333 | }, | ||
315 | }; | 334 | }; |
316 | 335 | ||
317 | // TODO: Support for copy paste anything, contextual. If we are on trigger | 336 | // TODO: Support for copy paste anything, contextual. If we are on trigger |
@@ -346,19 +365,31 @@ irq_timer_0(void) { | |||
346 | | SOUND_SQUARE_ENV_TIME(trig->env_time) | 365 | | SOUND_SQUARE_ENV_TIME(trig->env_time) |
347 | | SOUND_SQUARE_ENV_DIR(trig->env_direction) | 366 | | SOUND_SQUARE_ENV_DIR(trig->env_direction) |
348 | | SOUND_SQUARE_DUTY(trig->duty_cycle); | 367 | | SOUND_SQUARE_DUTY(trig->duty_cycle); |
349 | SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET | 368 | SOUND_SQUARE1_FREQ = SOUND_FREQ_RESET |
350 | | sound_rates[active_note]; | 369 | | sound_rates[active_note]; |
351 | } | 370 | } |
352 | } | 371 | } |
353 | SeqTrigger *trig = &sequences[1][step_counter]; | ||
354 | { | 372 | { |
373 | SeqTrigger *trig = &sequences[1][step_counter]; | ||
355 | active_note = trig->note; | 374 | active_note = trig->note; |
356 | if (trig->trigger) { | 375 | if (trig->trigger) { |
357 | SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume) | 376 | SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume) |
358 | | SOUND_SQUARE_ENV_TIME(trig->env_time) | 377 | | SOUND_SQUARE_ENV_TIME(trig->env_time) |
359 | | SOUND_SQUARE_ENV_DIR(trig->env_direction) | 378 | | SOUND_SQUARE_ENV_DIR(trig->env_direction) |
360 | | SOUND_SQUARE_DUTY(trig->duty_cycle); | 379 | | SOUND_SQUARE_DUTY(trig->duty_cycle); |
361 | SOUND_SQUARE2_FREQ = SOUND_SQUARE_RESET | 380 | SOUND_SQUARE2_FREQ = SOUND_FREQ_RESET |
381 | | sound_rates[active_note]; | ||
382 | } | ||
383 | } | ||
384 | { | ||
385 | SeqTrigger *trig = &sequences[2][step_counter]; | ||
386 | active_note = trig->note; | ||
387 | if (trig->trigger) { | ||
388 | SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) | ||
389 | | SOUND_WAVE_BANK_SELECT(0) | ||
390 | | SOUND_WAVE_ENABLE; | ||
391 | SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100; | ||
392 | SOUND_WAVE_FREQ = SOUND_FREQ_RESET | ||
362 | | sound_rates[active_note]; | 393 | | sound_rates[active_note]; |
363 | } | 394 | } |
364 | } | 395 | } |
@@ -752,7 +783,7 @@ init_sequencer_sprites(void) { | |||
752 | int base_tile = sprites[sprite_id].tile_start + 8; | 783 | int base_tile = sprites[sprite_id].tile_start + 8; |
753 | seq_sprites[53].id = obj_counter++; | 784 | seq_sprites[53].id = obj_counter++; |
754 | seq_sprites[53].base_tile = base_tile; | 785 | seq_sprites[53].base_tile = base_tile; |
755 | seq_sprites[53].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y) | OBJ_HIDDEN; | 786 | seq_sprites[53].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y); |
756 | seq_sprites[53].obj_attr_1 = OBJ_SIZE_MID | OBJ_X_COORD(x); | 787 | seq_sprites[53].obj_attr_1 = OBJ_SIZE_MID | OBJ_X_COORD(x); |
757 | seq_sprites[53].obj_attr_2 = base_tile | OBJ_PAL_BANK(0); | 788 | seq_sprites[53].obj_attr_2 = base_tile | OBJ_PAL_BANK(0); |
758 | } | 789 | } |
@@ -1084,11 +1115,15 @@ handle_sequencer_input(void) { | |||
1084 | } else { | 1115 | } else { |
1085 | TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; | 1116 | TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; |
1086 | SOUND_SQUARE1_CTRL = 0; | 1117 | SOUND_SQUARE1_CTRL = 0; |
1118 | SOUND_SQUARE2_CTRL = 0; | ||
1119 | SOUND_WAVE_CTRL = 0; | ||
1087 | } | 1120 | } |
1088 | } | 1121 | } |
1089 | if (key_pressed(KEY_SELECT)) { | 1122 | if (key_pressed(KEY_SELECT)) { |
1090 | TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; | 1123 | TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; |
1091 | SOUND_SQUARE1_CTRL = 0; | 1124 | SOUND_SQUARE1_CTRL = 0; |
1125 | SOUND_SQUARE2_CTRL = 0; | ||
1126 | SOUND_WAVE_CTRL = 0; | ||
1092 | } | 1127 | } |
1093 | } | 1128 | } |
1094 | 1129 | ||
@@ -1102,3 +1137,29 @@ render_sequencer_sprites(void) { | |||
1102 | OBJ_ATTR_2(id) = seq_sprites[i].obj_attr_2; | 1137 | OBJ_ATTR_2(id) = seq_sprites[i].obj_attr_2; |
1103 | } | 1138 | } |
1104 | } | 1139 | } |
1140 | |||
1141 | void init_sequencer() { | ||
1142 | init_sequencer_sprites(); | ||
1143 | SOUND_STATUS = SOUND_ENABLE; | ||
1144 | SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2 | SOUND_WAVE, 3); | ||
1145 | SOUND_DSOUND_MASTER = SOUND_DMG100; | ||
1146 | |||
1147 | // TODO: Currently static, need to figure out a way of controlling these | ||
1148 | // parameters. | ||
1149 | // Select bank 0 for writing (bank 1 playing). | ||
1150 | SOUND_WAVE_RAM_0 = 0xEFDEBC89; | ||
1151 | SOUND_WAVE_RAM_1 = 0x98CBEDFE; | ||
1152 | SOUND_WAVE_RAM_2 = 0x10214376; | ||
1153 | SOUND_WAVE_RAM_3 = 0x67341201; | ||
1154 | SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1) | SOUND_WAVE_BANK_SELECT(1); | ||
1155 | |||
1156 | // SINE WAVE | ||
1157 | SOUND_WAVE_RAM_0 = 0xEFDEBC89; | ||
1158 | SOUND_WAVE_RAM_1 = 0x98CBEDFE; | ||
1159 | SOUND_WAVE_RAM_2 = 0x10214376; | ||
1160 | SOUND_WAVE_RAM_3 = 0x67341201; | ||
1161 | |||
1162 | // Select bank 0 for playing. | ||
1163 | SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0) | SOUND_WAVE_BANK_SELECT(0); | ||
1164 | SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE; | ||
1165 | } | ||