diff options
author | Bad Diode <bd@badd10de.dev> | 2021-05-02 17:06:03 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-05-02 17:06:03 +0200 |
commit | 53c1e688f2b2f559a2bde556c9762519efa66f03 (patch) | |
tree | bc5c58c3953594c103e1da1118e8a9899b51e8f6 | |
parent | 685cc9d6bfb1c376f1231ce7c271c6ab6900b3d9 (diff) | |
download | gba-experiments-53c1e688f2b2f559a2bde556c9762519efa66f03.tar.gz gba-experiments-53c1e688f2b2f559a2bde556c9762519efa66f03.zip |
Add sprites for envelope volume control
-rw-r--r-- | src/sequencer.c | 198 |
1 files changed, 145 insertions, 53 deletions
diff --git a/src/sequencer.c b/src/sequencer.c index f459d0f..39f083f 100644 --- a/src/sequencer.c +++ b/src/sequencer.c | |||
@@ -99,32 +99,74 @@ u32 sprite_trigger_selection[] = { | |||
99 | 0x04040407, 0x00000000, 0x00000000, 0x00000000, | 99 | 0x04040407, 0x00000000, 0x00000000, 0x00000000, |
100 | }; | 100 | }; |
101 | 101 | ||
102 | u32 sprite_env_labels[] = { | ||
103 | // Volume. | ||
104 | 0xa0a0a0a0, 0xc0000000, 0x262a2a2a, 0xee000000, | ||
105 | 0xaaeaaaaa, 0xae000000, 0x0e020602, 0x0e000000, | ||
106 | }; | ||
107 | |||
108 | u32 sprite_env_volume[] = { | ||
109 | 0x80808080, 0x80808000, 0x0f0c0c0c, 0x0c6c6f00, | ||
110 | 0x1f999919, 0x19999f00, 0x00090d06, 0x030d0c00, | ||
111 | 0x80808080, 0x80808000, 0x0f01010f, 0x09696f00, | ||
112 | 0x1f83831f, 0x13939f00, 0x00090d06, 0x030d0c00, | ||
113 | 0x60606060, 0x60606000, 0x1f18181e, 0x18d8df00, | ||
114 | 0x3e30303c, 0x30303e00, 0x00131b0c, 0x061b1900, | ||
115 | 0xf8c0c0f8, 0x1818f800, 0x3e06063e, 0x26a6be00, | ||
116 | 0x7c0c0c7c, 0x4c4d7d00, 0x00263618, 0x0c363200, | ||
117 | 0xf8c0c0f8, 0x1818f800, 0x3e323232, 0x32b2be00, | ||
118 | 0x7c646464, 0x64657d00, 0x00263618, 0x0c363200, | ||
119 | 0xf8c0c0f0, 0xc0c0f800, 0x3e30303c, 0x30b0be00, | ||
120 | 0x7c606078, 0x60617d00, 0x00263618, 0x0c363200, | ||
121 | 0xc0e0d0c8, 0xf8c0c000, 0x3e323232, 0x32b2be00, | ||
122 | 0x7c646464, 0x64657d00, 0x00263618, 0x0c363200, | ||
123 | 0xc0e0d0c8, 0xf8c0c000, 0x3e06063e, 0x26a6be00, | ||
124 | 0x7c0c0c7c, 0x4c4d7d00, 0x00263618, 0x0c363200, | ||
125 | 0xf81818f8, 0xc0c0f800, 0x3e30303c, 0x30b0be00, | ||
126 | 0x7c606078, 0x60617d00, 0x00263618, 0x0c363200, | ||
127 | 0xf81818f8, 0x9898f800, 0x3e323232, 0x32b2be00, | ||
128 | 0x7c646464, 0x64657d00, 0x00263618, 0x0c363200, | ||
129 | 0xf81818f8, 0x9898f800, 0x3e06063e, 0x26a6be00, | ||
130 | 0x7c0c0c7c, 0x4c4d7d00, 0x00263618, 0x0c363200, | ||
131 | 0xf8c0c060, 0x30181800, 0x3e30303c, 0x30b0be00, | ||
132 | 0x7c606078, 0x60617d00, 0x00263618, 0x0c363200, | ||
133 | 0xf8c8c8f8, 0xc8c8f800, 0x3e323232, 0x32b2be00, | ||
134 | 0x7c646464, 0x64657d00, 0x00263618, 0x0c363200, | ||
135 | 0xf8c8c8f8, 0xc8c8f800, 0x3e06063e, 0x26a6be00, | ||
136 | 0x7c0c0c7c, 0x4c4d7d00, 0x00263618, 0x0c363200, | ||
137 | 0xf8c8c8f8, 0xc0c0f800, 0x3e30303c, 0x30b0be00, | ||
138 | 0x7c606078, 0x60617d00, 0x00263618, 0x0c363200, | ||
139 | 0xec2c2c2c, 0x2c2cec00, 0xfbcbcbcb, 0xcbcbfb00, | ||
140 | 0xf0909090, 0x9096f600, 0x0199d961, 0x31d9c900, | ||
141 | }; | ||
142 | |||
102 | typedef struct SeqTrigger { | 143 | typedef struct SeqTrigger { |
103 | bool trigger; | 144 | bool trigger; |
104 | Note note; | 145 | Note note; |
146 | u8 env_volume; | ||
105 | // TODO: ... | 147 | // TODO: ... |
106 | } SeqTrigger; | 148 | } SeqTrigger; |
107 | 149 | ||
108 | static SeqTrigger sequence_synth[] = { | 150 | static SeqTrigger sequence_synth[] = { |
109 | {true, NOTE_D_4}, | 151 | {true, NOTE_D_4, 0}, |
110 | {true, NOTE_F_4}, | 152 | {true, NOTE_F_4, 1}, |
111 | {true, NOTE_A_4}, | 153 | {true, NOTE_A_4, 2}, |
112 | {true, NOTE_C_5}, | 154 | {true, NOTE_C_5, 3}, |
113 | 155 | ||
114 | {true, NOTE_D_4}, | 156 | {true, NOTE_D_4, 4}, |
115 | {false, NOTE_C_SHARP_4}, | 157 | {false, NOTE_C_SHARP_4, 5}, |
116 | {false, NOTE_D_4}, | 158 | {false, NOTE_D_4, 6}, |
117 | {false, NOTE_D_4}, | 159 | {false, NOTE_D_4, 7}, |
118 | 160 | ||
119 | {true, NOTE_D_4}, | 161 | {true, NOTE_D_4, 8}, |
120 | {true, NOTE_F_4}, | 162 | {true, NOTE_F_4, 9}, |
121 | {true, NOTE_A_4}, | 163 | {true, NOTE_A_4, 10}, |
122 | {true, NOTE_C_5}, | 164 | {true, NOTE_C_5, 11}, |
123 | 165 | ||
124 | {true, NOTE_D_4}, | 166 | {true, NOTE_D_4, 12}, |
125 | {false, NOTE_D_4}, | 167 | {false, NOTE_D_4, 13}, |
126 | {true, NOTE_A_4}, | 168 | {true, NOTE_A_4, 14}, |
127 | {false, NOTE_A_5}, | 169 | {false, NOTE_A_5, 15}, |
128 | }; | 170 | }; |
129 | 171 | ||
130 | static int bpm = 120; | 172 | static int bpm = 120; |
@@ -133,9 +175,12 @@ static Note active_note; | |||
133 | 175 | ||
134 | void | 176 | void |
135 | irq_timer_0(void) { | 177 | irq_timer_0(void) { |
136 | active_note = sequence_synth[step_counter].note; | 178 | SeqTrigger *trig = &sequence_synth[step_counter]; |
137 | if (sequence_synth[step_counter].trigger) { | 179 | active_note = trig->note; |
138 | SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(13) | SOUND_SQUARE_ENV_TIME(4) | SOUND_SQUARE_DUTY(2); | 180 | if (trig->trigger) { |
181 | SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume) | ||
182 | | SOUND_SQUARE_ENV_TIME(4) | ||
183 | | SOUND_SQUARE_DUTY(2); | ||
139 | SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET | sound_rates[active_note]; | 184 | SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET | sound_rates[active_note]; |
140 | } | 185 | } |
141 | step_counter = (step_counter + 1) % 16; | 186 | step_counter = (step_counter + 1) % 16; |
@@ -161,46 +206,56 @@ set_time(int bpm) { | |||
161 | // | 206 | // |
162 | // Currently we load all sequencer sprite memory in the VRAM: | 207 | // Currently we load all sequencer sprite memory in the VRAM: |
163 | // | 208 | // |
164 | // - Note names: 73x2 tiles | 209 | // - Note names: 73x2 tiles. |
165 | // - Sprite trigger button: 8 tiles | 210 | // - Sprite trigger button: 8 tiles. |
166 | // - Duration indicator (TODO) | 211 | // - Current step marker: 1 tile. |
167 | // - Current step marker. | 212 | // - Selected trigger marker: 16 tile. |
213 | // - Env: Volume label: 4 tiles. | ||
214 | // - Env: Volume text: 7x4 tiles | ||
215 | // - (TODO) Duration indicator | ||
168 | // | 216 | // |
169 | // The order of OBJs correspond to: | 217 | // The order of OBJs correspond to: |
170 | // | 218 | // |
171 | // - 000-015 step note names. | 219 | // - 000-015 step note names. |
172 | // - 015-029 step trigger steps. | 220 | // - 015-031 step trigger steps. |
173 | // - 030-045 step duration indicators. | 221 | // - 032-032 current step marker. |
174 | // - 046-046 current step marker. | 222 | // - 033-033 trigger selection indicator. |
175 | // - 047-047 trigger selection indicator. | 223 | // - 034-034 envelope: volume label. |
224 | // - 035-0xx envelope: volume indicator. | ||
176 | // | 225 | // |
177 | 226 | ||
227 | |||
228 | // Positioning parameters. | ||
229 | #define SEQ_TRIG_POS_X 45 | ||
230 | #define SEQ_TRIG_POS_Y 50 | ||
231 | #define SEQ_TRIG_DIST 20 | ||
232 | #define SEQ_ENV_POS_X 10 | ||
233 | #define SEQ_ENV_POS_Y 10 | ||
234 | |||
178 | size_t obj_counter = 0; | 235 | size_t obj_counter = 0; |
179 | 236 | ||
180 | typedef struct SeqSprite { | 237 | typedef struct SeqSprite { |
181 | u8 id; | 238 | u8 id; |
182 | int x; | 239 | int x; |
183 | int y; | 240 | int y; |
241 | size_t base_tile; | ||
184 | u16 obj_attr_0; | 242 | u16 obj_attr_0; |
185 | u16 obj_attr_1; | 243 | u16 obj_attr_1; |
186 | u16 obj_attr_2; | 244 | u16 obj_attr_2; |
187 | } SeqSprite; | 245 | } SeqSprite; |
188 | 246 | ||
189 | #define SEQ_POS_X 45 | ||
190 | #define SEQ_POS_Y 50 | ||
191 | #define SEQ_TRIG_DIST 20 | ||
192 | |||
193 | int trig_selection_loc = 1; | 247 | int trig_selection_loc = 1; |
194 | 248 | ||
195 | SeqSprite seq_sprites[34] = {0}; | 249 | SeqSprite seq_sprites[36] = {0}; |
196 | 250 | ||
197 | void | 251 | void |
198 | init_sequencer_sprites(void) { | 252 | init_sequencer_sprites(void) { |
199 | // Sprite note names. | 253 | // Sprite note names. |
200 | size_t sprite_id = load_packed_sprite_data(&sprite_note_names, 2, 73); | 254 | size_t sprite_id = load_packed_sprite_data(&sprite_note_names, 2, 73); |
201 | for (size_t i = 0; i < 16; ++i) { | 255 | for (size_t i = 0; i < 16; ++i) { |
202 | int x = SEQ_POS_X + i * SEQ_TRIG_DIST; | 256 | int x = SEQ_TRIG_POS_X + i * SEQ_TRIG_DIST; |
203 | int y = SEQ_POS_Y; | 257 | int y = SEQ_TRIG_POS_Y; |
258 | int base_tile = sprites[sprite_id].tile_start; | ||
204 | if (i >= 8) { | 259 | if (i >= 8) { |
205 | y += 32; | 260 | y += 32; |
206 | x -= 8 * SEQ_TRIG_DIST; | 261 | x -= 8 * SEQ_TRIG_DIST; |
@@ -209,52 +264,81 @@ init_sequencer_sprites(void) { | |||
209 | seq_sprites[i].y = y; | 264 | seq_sprites[i].y = y; |
210 | 265 | ||
211 | seq_sprites[i].id = obj_counter++; | 266 | seq_sprites[i].id = obj_counter++; |
267 | seq_sprites[i].base_tile = base_tile; | ||
212 | seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y); | 268 | seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y); |
213 | // TODO: They should start hidden until the update function changes that. | 269 | // TODO: They should start hidden until the update function changes that. |
214 | // seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_HIDDEN; | 270 | // seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_HIDDEN; |
215 | seq_sprites[i].obj_attr_1 = OBJ_SIZE_SMALL | OBJ_X_COORD(x); | 271 | seq_sprites[i].obj_attr_1 = OBJ_SIZE_SMALL | OBJ_X_COORD(x); |
216 | seq_sprites[i].obj_attr_2 = sprites[sprite_id].tile_start; | 272 | seq_sprites[i].obj_attr_2 = base_tile; |
217 | } | 273 | } |
218 | 274 | ||
219 | // Trigger boxes. | 275 | // Trigger boxes. |
220 | sprite_id = load_packed_sprite_data(&sprite_trigger_button, 8, 1); | 276 | sprite_id = load_packed_sprite_data(&sprite_trigger_button, 8, 1); |
221 | for (size_t i = 0; i < 16; ++i) { | 277 | for (size_t i = 0; i < 16; ++i) { |
222 | int x = SEQ_POS_X + i * SEQ_TRIG_DIST; | 278 | int x = SEQ_TRIG_POS_X + i * SEQ_TRIG_DIST; |
223 | int y = SEQ_POS_Y; | 279 | int y = SEQ_TRIG_POS_Y; |
280 | int base_tile = sprites[sprite_id].tile_start; | ||
224 | if (i >= 8) { | 281 | if (i >= 8) { |
225 | y += 32; | 282 | y += 32; |
226 | x -= 8 * SEQ_TRIG_DIST; | 283 | x -= 8 * SEQ_TRIG_DIST; |
227 | } | 284 | } |
228 | seq_sprites[i + 16].id = obj_counter++; | 285 | seq_sprites[i + 16].id = obj_counter++; |
286 | seq_sprites[i + 16].base_tile = base_tile; | ||
229 | seq_sprites[i + 16].obj_attr_0 = OBJ_SHAPE_TALL | OBJ_Y_COORD(y); | 287 | seq_sprites[i + 16].obj_attr_0 = OBJ_SHAPE_TALL | OBJ_Y_COORD(y); |
230 | seq_sprites[i + 16].obj_attr_1 = OBJ_SIZE_BIG | OBJ_X_COORD(x); | 288 | seq_sprites[i + 16].obj_attr_1 = OBJ_SIZE_BIG | OBJ_X_COORD(x); |
231 | seq_sprites[i + 16].obj_attr_2 = sprites[sprite_id].tile_start; | 289 | seq_sprites[i + 16].obj_attr_2 = base_tile; |
232 | } | 290 | } |
233 | 291 | ||
234 | sprite_id = load_packed_sprite_data(&sprite_trigger_active_indicator, 1, 1); | 292 | sprite_id = load_packed_sprite_data(&sprite_trigger_active_indicator, 1, 1); |
235 | // TODO: No need for a for loop. | ||
236 | { | 293 | { |
237 | int x = SEQ_POS_X; | 294 | int x = SEQ_TRIG_POS_X; |
238 | int y = SEQ_POS_Y + 15; | 295 | int y = SEQ_TRIG_POS_Y + 15; |
296 | int base_tile = sprites[sprite_id].tile_start; | ||
239 | seq_sprites[32].id = obj_counter++; | 297 | seq_sprites[32].id = obj_counter++; |
298 | seq_sprites[32].base_tile = base_tile; | ||
240 | seq_sprites[32].obj_attr_0 = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(y); | 299 | seq_sprites[32].obj_attr_0 = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(y); |
241 | seq_sprites[32].obj_attr_1 = OBJ_SIZE_SMALL | OBJ_X_COORD(x); | 300 | seq_sprites[32].obj_attr_1 = OBJ_SIZE_SMALL | OBJ_X_COORD(x); |
242 | seq_sprites[32].obj_attr_2 = sprites[sprite_id].tile_start | OBJ_PAL_BANK(1); | 301 | seq_sprites[32].obj_attr_2 = base_tile | OBJ_PAL_BANK(1); |
243 | } | 302 | } |
244 | 303 | ||
245 | sprite_id = load_packed_sprite_data(&sprite_trigger_selection, 16, 1); | 304 | sprite_id = load_packed_sprite_data(&sprite_trigger_selection, 16, 1); |
246 | // TODO: No need for a for loop. | ||
247 | { | 305 | { |
248 | int x = SEQ_POS_X - 1 + trig_selection_loc * SEQ_TRIG_DIST; | 306 | int x = SEQ_TRIG_POS_X - 1 + trig_selection_loc * SEQ_TRIG_DIST; |
249 | int y = SEQ_POS_Y - 2; | 307 | int y = SEQ_TRIG_POS_Y - 2; |
308 | int base_tile = sprites[sprite_id].tile_start; | ||
250 | if (trig_selection_loc >= 8) { | 309 | if (trig_selection_loc >= 8) { |
251 | y += 32; | 310 | y += 32; |
252 | x -= 8 * SEQ_TRIG_DIST; | 311 | x -= 8 * SEQ_TRIG_DIST; |
253 | } | 312 | } |
254 | seq_sprites[33].id = obj_counter++; | 313 | seq_sprites[33].id = obj_counter++; |
314 | seq_sprites[33].base_tile = base_tile; | ||
255 | seq_sprites[33].obj_attr_0 = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(y); | 315 | seq_sprites[33].obj_attr_0 = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(y); |
256 | seq_sprites[33].obj_attr_1 = OBJ_SIZE_BIG | OBJ_X_COORD(x); | 316 | seq_sprites[33].obj_attr_1 = OBJ_SIZE_BIG | OBJ_X_COORD(x); |
257 | seq_sprites[33].obj_attr_2 = sprites[sprite_id].tile_start | OBJ_PAL_BANK(2); | 317 | seq_sprites[33].obj_attr_2 = base_tile | OBJ_PAL_BANK(2); |
318 | } | ||
319 | |||
320 | sprite_id = load_packed_sprite_data(&sprite_env_labels, 4, 1); | ||
321 | { | ||
322 | int x = SEQ_ENV_POS_X; | ||
323 | int y = SEQ_ENV_POS_Y; | ||
324 | int base_tile = sprites[sprite_id].tile_start; | ||
325 | seq_sprites[34].id = obj_counter++; | ||
326 | seq_sprites[34].base_tile = base_tile; | ||
327 | seq_sprites[34].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y); | ||
328 | seq_sprites[34].obj_attr_1 = OBJ_SIZE_MID | OBJ_X_COORD(x); | ||
329 | seq_sprites[34].obj_attr_2 = base_tile | OBJ_PAL_BANK(2); | ||
330 | } | ||
331 | |||
332 | sprite_id = load_packed_sprite_data(&sprite_env_volume, 4, 16); | ||
333 | { | ||
334 | int x = SEQ_ENV_POS_X; | ||
335 | int y = SEQ_ENV_POS_Y + 8; | ||
336 | int base_tile = sprites[sprite_id].tile_start; | ||
337 | seq_sprites[35].id = obj_counter++; | ||
338 | seq_sprites[35].base_tile = base_tile; | ||
339 | seq_sprites[35].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y); | ||
340 | seq_sprites[35].obj_attr_1 = OBJ_SIZE_MID | OBJ_X_COORD(x); | ||
341 | seq_sprites[35].obj_attr_2 = base_tile | OBJ_PAL_BANK(2); | ||
258 | } | 342 | } |
259 | } | 343 | } |
260 | 344 | ||
@@ -279,8 +363,8 @@ update_sequencer_sprites(void) { | |||
279 | 363 | ||
280 | // 33: Sequence indicator. | 364 | // 33: Sequence indicator. |
281 | { | 365 | { |
282 | int x = SEQ_POS_X + step_counter * SEQ_TRIG_DIST + 3; | 366 | int x = SEQ_TRIG_POS_X + step_counter * SEQ_TRIG_DIST + 3; |
283 | int y = SEQ_POS_Y + 15; | 367 | int y = SEQ_TRIG_POS_Y + 15; |
284 | if (step_counter >= 8) { | 368 | if (step_counter >= 8) { |
285 | y += 32; | 369 | y += 32; |
286 | x -= 8 * SEQ_TRIG_DIST; | 370 | x -= 8 * SEQ_TRIG_DIST; |
@@ -291,8 +375,8 @@ update_sequencer_sprites(void) { | |||
291 | 375 | ||
292 | // 34: Trigger selection. | 376 | // 34: Trigger selection. |
293 | { | 377 | { |
294 | int x = SEQ_POS_X - 1 + trig_selection_loc * SEQ_TRIG_DIST; | 378 | int x = SEQ_TRIG_POS_X - 1 + trig_selection_loc * SEQ_TRIG_DIST; |
295 | int y = SEQ_POS_Y - 2; | 379 | int y = SEQ_TRIG_POS_Y - 2; |
296 | if (trig_selection_loc >= 8) { | 380 | if (trig_selection_loc >= 8) { |
297 | y += 32; | 381 | y += 32; |
298 | x -= 8 * SEQ_TRIG_DIST; | 382 | x -= 8 * SEQ_TRIG_DIST; |
@@ -301,6 +385,14 @@ update_sequencer_sprites(void) { | |||
301 | seq_sprites[33].obj_attr_0 = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(y); | 385 | seq_sprites[33].obj_attr_0 = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(y); |
302 | seq_sprites[33].obj_attr_1 = OBJ_SIZE_BIG | OBJ_X_COORD(x); | 386 | seq_sprites[33].obj_attr_1 = OBJ_SIZE_BIG | OBJ_X_COORD(x); |
303 | } | 387 | } |
388 | |||
389 | // 36: Envelope initial volume | ||
390 | { | ||
391 | size_t tile_diff = sequence_synth[trig_selection_loc].env_volume * 4; | ||
392 | size_t base_tile = seq_sprites[35].base_tile; | ||
393 | size_t tile = base_tile + tile_diff; | ||
394 | seq_sprites[35].obj_attr_2 = tile | OBJ_PAL_BANK(2); | ||
395 | } | ||
304 | } | 396 | } |
305 | 397 | ||
306 | void | 398 | void |