#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; } }