From c9fbc44912f54a0263b6c1514f086cc1b5ef3079 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Sun, 2 May 2021 12:32:15 +0200 Subject: Start work on seq sprite rendering --- src/main.c | 81 ++++----------------- src/sequencer.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+), 69 deletions(-) create mode 100644 src/sequencer.c diff --git a/src/main.c b/src/main.c index b2cd2d2..b3a4d5a 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,7 @@ #include "background-tiles.c" #include "sprites.h" #include "text.h" +#include "sequencer.c" // // Main functions. @@ -13,63 +14,6 @@ // TODO: Cleanup OBJ/OAM memory copying and access. // -typedef struct SeqTrigger { - bool trigger; - Note note; - // TODO: ... -} SeqTrigger; - -static SeqTrigger sequence_synth_1 [] = { - {true, NOTE_D_4}, - {true, NOTE_F_4}, - {true, NOTE_A_4}, - {true, NOTE_C_5}, - - {true, NOTE_D_4}, - {false, NOTE_D_4}, - {false, NOTE_D_4}, - {false, NOTE_D_4}, - - {true, NOTE_D_4}, - {true, NOTE_F_4}, - {true, NOTE_A_4}, - {true, NOTE_C_5}, - - {true, NOTE_D_4}, - {false, NOTE_D_4}, - {true, NOTE_A_4}, - {false, NOTE_A_5}, -}; - -int step_counter = 0; -Note active_note; -void -irq_timer_0(void) { - active_note = sequence_synth_1[step_counter].note; - if (sequence_synth_1[step_counter].trigger) { - SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(13) | SOUND_SQUARE_ENV_TIME(4) | SOUND_SQUARE_DUTY(2); - SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET | sound_rates[active_note]; - } - - step_counter = (step_counter + 1) % 16; -} - -void -set_time(int bpm) { - // TIMER_CTRL_0 = TIMER_CTRL_DISABLE; - - // The number of ticks of a 1024 cycle clock in a step based on the BPM can - // be calculated as: - // X bpm -> 60000 / 4 / bpm = Y ms = Ye-3 s - // Y ms -> Ye-3 / 59.99e-9 /1024 = Z ticks - // We have to operate on integer values, so the numbers have been - // precalculated to `n_ticks = 244181 / bmp` - int n_ticks = -244181 / bpm; - - irs_set(IRQ_TIMER_0, irq_timer_0); - TIMER_DATA_0 = n_ticks; - TIMER_CTRL_0 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_FREQ_3; -} int main(void) { // Configure the display in mode 0 to show OBJs, where tile memory is @@ -79,10 +23,10 @@ int main(void) { // Initialize sprite button overlay. init_sprite_pal(0, COLOR_WHITE); init_sprites(0); - init_button_sprites(); + init_sequencer_sprites(); // Initialize text engine. - txt_init(0, COLOR_RED, 0); + // txt_init(0, COLOR_RED, 0); // Register interrupts. irq_init(); @@ -90,7 +34,7 @@ int main(void) { // turn sound on SOUND_STATUS = SOUND_ENABLE; - SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2, 7); + SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2, 3); SOUND_DSOUND_MASTER = SOUND_DMG100; // Initialize timer. @@ -116,16 +60,15 @@ int main(void) { TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; } - txt_position(1,6); - txt_clear_line(); - txt_printf(" BPM: %d\n\n", bpm); - - txt_clear_line(); - txt_printf(" Step: %d\n", step_counter); - txt_clear_line(); - txt_printf(" Note: %s\n", note_names[active_note]); + // txt_position(1,6); + // txt_clear_line(); + // txt_printf(" BPM: %d\n\n", bpm); - update_button_sprites(); + // txt_clear_line(); + // txt_printf(" Step: %d\n", step_counter); + // txt_clear_line(); + // txt_printf(" Note: %s\n", note_names[active_note]); + render_sequencer_sprites(); }; return 0; diff --git a/src/sequencer.c b/src/sequencer.c new file mode 100644 index 0000000..4231def --- /dev/null +++ b/src/sequencer.c @@ -0,0 +1,218 @@ +#define SPRITE_NOTE_NAMES_W 16 +#define SPRITE_NOTE_NAMES_H 8 + +u32 sprite_note_names[] = { + 0x77417111, 0x77000000, 0x00000000, 0x00000000, + 0x13157555, 0x33000000, 0x07040701, 0x07000000, + 0x73457515, 0x73000000, 0x00000000, 0x00000000, + 0x17117351, 0x37000000, 0x07040701, 0x07000000, + 0x77417311, 0x77000000, 0x00000000, 0x00000000, + 0x77417311, 0x71000000, 0x00000000, 0x00000000, + 0x17117155, 0x37000000, 0x07040701, 0x07000000, + 0x77417115, 0x77000000, 0x00000000, 0x00000000, + 0x17157557, 0x35000000, 0x07040701, 0x07000000, + 0x77457517, 0x75000000, 0x00000000, 0x00000000, + 0x17157355, 0x37000000, 0x07040701, 0x07000000, + 0x77457315, 0x77000000, 0x00000000, 0x00000000, + 0x77416141, 0x77000000, 0x00000000, 0x00000000, + 0x13157555, 0x33000000, 0x07040604, 0x07000000, + 0x73456545, 0x73000000, 0x00000000, 0x00000000, + 0x17117351, 0x37000000, 0x07040604, 0x07000000, + 0x77416341, 0x77000000, 0x00000000, 0x00000000, + 0x77416341, 0x71000000, 0x00000000, 0x00000000, + 0x17117155, 0x37000000, 0x07040604, 0x07000000, + 0x77416145, 0x77000000, 0x00000000, 0x00000000, + 0x17157557, 0x35000000, 0x07040604, 0x07000000, + 0x77456547, 0x75000000, 0x00000000, 0x00000000, + 0x17157355, 0x37000000, 0x07040604, 0x07000000, + 0x77456345, 0x77000000, 0x00000000, 0x00000000, + 0x47615171, 0x47000000, 0x00000000, 0x00000000, + 0x13157555, 0x33000000, 0x04060507, 0x04000000, + 0x43655575, 0x43000000, 0x00000000, 0x00000000, + 0x17117351, 0x37000000, 0x04060507, 0x04000000, + 0x47615371, 0x47000000, 0x00000000, 0x00000000, + 0x47615371, 0x41000000, 0x00000000, 0x00000000, + 0x17117155, 0x37000000, 0x04060507, 0x04000000, + 0x47615175, 0x47000000, 0x00000000, 0x00000000, + 0x17157557, 0x35000000, 0x04060507, 0x04000000, + 0x47655577, 0x45000000, 0x00000000, 0x00000000, + 0x17157355, 0x37000000, 0x04060507, 0x04000000, + 0x47655375, 0x47000000, 0x00000000, 0x00000000, + 0x77117141, 0x77000000, 0x00000000, 0x00000000, + 0x13157555, 0x33000000, 0x07010704, 0x07000000, + 0x73157545, 0x73000000, 0x00000000, 0x00000000, + 0x17117351, 0x37000000, 0x07010704, 0x07000000, + 0x77117341, 0x77000000, 0x00000000, 0x00000000, + 0x77117341, 0x71000000, 0x00000000, 0x00000000, + 0x17117155, 0x37000000, 0x07010704, 0x07000000, + 0x77117145, 0x77000000, 0x00000000, 0x00000000, + 0x17157557, 0x35000000, 0x07010704, 0x07000000, + 0x77157547, 0x75000000, 0x00000000, 0x00000000, + 0x17157355, 0x37000000, 0x07010704, 0x07000000, + 0x77157345, 0x77000000, 0x00000000, 0x00000000, + 0x77117151, 0x77000000, 0x00000000, 0x00000000, + 0x13157555, 0x33000000, 0x07010705, 0x07000000, + 0x73157555, 0x73000000, 0x00000000, 0x00000000, + 0x17117351, 0x37000000, 0x07010705, 0x07000000, + 0x77117351, 0x77000000, 0x00000000, 0x00000000, + 0x77117351, 0x71000000, 0x00000000, 0x00000000, + 0x17117155, 0x37000000, 0x07010705, 0x07000000, + 0x77117155, 0x77000000, 0x00000000, 0x00000000, + 0x17157557, 0x35000000, 0x07010705, 0x07000000, + 0x77157557, 0x75000000, 0x00000000, 0x00000000, + 0x17157355, 0x37000000, 0x07010705, 0x07000000, + 0x77157355, 0x77000000, 0x00000000, 0x00000000, + 0x77412111, 0x17000000, 0x00000000, 0x00000000, + 0x13157555, 0x33000000, 0x07040201, 0x01000000, + 0x73452515, 0x13000000, 0x00000000, 0x00000000, + 0x17117351, 0x37000000, 0x07040201, 0x01000000, + 0x77412311, 0x17000000, 0x00000000, 0x00000000, + 0x77412311, 0x11000000, 0x00000000, 0x00000000, + 0x17117155, 0x37000000, 0x07040201, 0x01000000, + 0x77412115, 0x17000000, 0x00000000, 0x00000000, + 0x17157557, 0x35000000, 0x07040201, 0x01000000, + 0x77452517, 0x15000000, 0x00000000, 0x00000000, + 0x17157355, 0x37000000, 0x07040201, 0x01000000, + 0x77452315, 0x17000000, 0x00000000, 0x00000000, + 0x77517151, 0x77000000, 0x00000000, 0x00000000, +}; + +typedef struct SeqTrigger { + bool trigger; + Note note; + // TODO: ... +} SeqTrigger; + +static SeqTrigger sequence_synth[] = { + {true, NOTE_D_4}, + {true, NOTE_F_4}, + {true, NOTE_A_4}, + {true, NOTE_C_5}, + + {true, NOTE_D_4}, + {false, NOTE_D_4}, + {false, NOTE_D_4}, + {false, NOTE_D_4}, + + {true, NOTE_D_4}, + {true, NOTE_F_4}, + {true, NOTE_A_4}, + {true, NOTE_C_5}, + + {true, NOTE_D_4}, + {false, NOTE_D_4}, + {true, NOTE_A_4}, + {false, NOTE_A_5}, +}; + +static int step_counter = 0; +static Note active_note; + +void +irq_timer_0(void) { + active_note = sequence_synth[step_counter].note; + if (sequence_synth[step_counter].trigger) { + SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(13) | SOUND_SQUARE_ENV_TIME(4) | SOUND_SQUARE_DUTY(2); + SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET | sound_rates[active_note]; + } + step_counter = (step_counter + 1) % 16; +} + +void +set_time(int bpm) { + // The number of ticks of a 1024 cycle clock in a step based on the BPM can + // be calculated as: + // X bpm -> 60000 / 4 / bpm = Y ms = Ye-3 s + // Y ms -> Ye-3 / 59.99e-9 /1024 = Z ticks + // We have to operate on integer values, so the numbers have been + // precalculated to `n_ticks = 244181 / bmp` + int n_ticks = -244181 / bpm; + + irs_set(IRQ_TIMER_0, irq_timer_0); + TIMER_DATA_0 = n_ticks; + TIMER_CTRL_0 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_FREQ_3; +} + +static size_t note_sprites_id = 0; + +// +// Sequencer sprite memory. +// +// Currently we load all sequencer sprite memory in the VRAM: +// +// - Note names: 0-73x2 tiles +// - ... +// +// The order of OBJs correspond to: +// +// - 000-015 step note names. +// - 015-029 step trigger steps. +// - 030-045 step duration indicators. +// - 046-046 current step marker. +// - 047-047 trigger selection indicator. +// + +size_t obj_counter = 0; + +typedef struct SeqSprite { + u8 id; + int x; + int y; + u16 obj_attr_0; + u16 obj_attr_1; + u16 obj_attr_2; +} SeqSprite; + +#define SEQ_POS_X 20 +#define SEQ_POS_Y 20 + +// SeqSprite seq_sprites[] = { +// // 000-015: Step note names. +// { +// .x = SEQ_POS_X, +// .y = SEQ_POS_Y, +// .obj_attr_0 = OBJ_SHAPE_WIDE, +// .obj_attr_1 = OBJ_SHAPE_SMALL, +// .obj_attr_2 = 0, +// }, +// }; + +SeqSprite seq_sprites[16] = {0}; + +void +init_sequencer_sprites() { + // Load note sprites. + note_sprites_id = load_packed_sprite_data(&sprite_note_names, 2, 73); + + for (size_t i = 0; i < 16; ++i) { + int x = SEQ_POS_X + i * 16; + int y = SEQ_POS_Y; + if (i >= 8) { + y += 32; + x -= 8 * 16; + } + seq_sprites[i].x = x; + seq_sprites[i].y = y; + + seq_sprites[i].id = obj_counter++; + seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y); + // TODO: They should start hidden until the update function changes that. + // seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_HIDDEN; + seq_sprites[i].obj_attr_1 = OBJ_SIZE_SMALL | OBJ_X_COORD(x); + } +} + +void +render_sequencer_sprites() { + size_t len = sizeof(seq_sprites) / sizeof(SeqSprite); + for (size_t i = 0; i < len; ++i) { + size_t id = seq_sprites[i].id; + // TODO: This needs to be done in an update function, not here. + size_t base_tile = sequence_synth[i].note; + seq_sprites[i].obj_attr_2 = base_tile; + + OBJ_ATTR_0(id) = seq_sprites[i].obj_attr_0; + OBJ_ATTR_1(id) = seq_sprites[i].obj_attr_1; + OBJ_ATTR_2(id) = seq_sprites[i].obj_attr_2; + } +} -- cgit v1.2.1