summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-05-02 12:32:15 +0200
committerBad Diode <bd@badd10de.dev>2021-05-02 12:32:15 +0200
commitc9fbc44912f54a0263b6c1514f086cc1b5ef3079 (patch)
treee0fd4ae540ef86f22dc36f7cff673decf5aaab98
parent01e6349dfb76abaf9d87d94369b17c14b678e416 (diff)
downloadgba-experiments-c9fbc44912f54a0263b6c1514f086cc1b5ef3079.tar.gz
gba-experiments-c9fbc44912f54a0263b6c1514f086cc1b5ef3079.zip
Start work on seq sprite rendering
-rw-r--r--src/main.c81
-rw-r--r--src/sequencer.c218
2 files changed, 230 insertions, 69 deletions
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 @@
5#include "background-tiles.c" 5#include "background-tiles.c"
6#include "sprites.h" 6#include "sprites.h"
7#include "text.h" 7#include "text.h"
8#include "sequencer.c"
8 9
9// 10//
10// Main functions. 11// Main functions.
@@ -13,63 +14,6 @@
13// TODO: Cleanup OBJ/OAM memory copying and access. 14// TODO: Cleanup OBJ/OAM memory copying and access.
14// 15//
15 16
16typedef struct SeqTrigger {
17 bool trigger;
18 Note note;
19 // TODO: ...
20} SeqTrigger;
21
22static SeqTrigger sequence_synth_1 [] = {
23 {true, NOTE_D_4},
24 {true, NOTE_F_4},
25 {true, NOTE_A_4},
26 {true, NOTE_C_5},
27
28 {true, NOTE_D_4},
29 {false, NOTE_D_4},
30 {false, NOTE_D_4},
31 {false, NOTE_D_4},
32
33 {true, NOTE_D_4},
34 {true, NOTE_F_4},
35 {true, NOTE_A_4},
36 {true, NOTE_C_5},
37
38 {true, NOTE_D_4},
39 {false, NOTE_D_4},
40 {true, NOTE_A_4},
41 {false, NOTE_A_5},
42};
43
44int step_counter = 0;
45Note active_note;
46void
47irq_timer_0(void) {
48 active_note = sequence_synth_1[step_counter].note;
49 if (sequence_synth_1[step_counter].trigger) {
50 SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(13) | SOUND_SQUARE_ENV_TIME(4) | SOUND_SQUARE_DUTY(2);
51 SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET | sound_rates[active_note];
52 }
53
54 step_counter = (step_counter + 1) % 16;
55}
56
57void
58set_time(int bpm) {
59 // TIMER_CTRL_0 = TIMER_CTRL_DISABLE;
60
61 // The number of ticks of a 1024 cycle clock in a step based on the BPM can
62 // be calculated as:
63 // X bpm -> 60000 / 4 / bpm = Y ms = Ye-3 s
64 // Y ms -> Ye-3 / 59.99e-9 /1024 = Z ticks
65 // We have to operate on integer values, so the numbers have been
66 // precalculated to `n_ticks = 244181 / bmp`
67 int n_ticks = -244181 / bpm;
68
69 irs_set(IRQ_TIMER_0, irq_timer_0);
70 TIMER_DATA_0 = n_ticks;
71 TIMER_CTRL_0 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_FREQ_3;
72}
73 17
74int main(void) { 18int main(void) {
75 // Configure the display in mode 0 to show OBJs, where tile memory is 19 // Configure the display in mode 0 to show OBJs, where tile memory is
@@ -79,10 +23,10 @@ int main(void) {
79 // Initialize sprite button overlay. 23 // Initialize sprite button overlay.
80 init_sprite_pal(0, COLOR_WHITE); 24 init_sprite_pal(0, COLOR_WHITE);
81 init_sprites(0); 25 init_sprites(0);
82 init_button_sprites(); 26 init_sequencer_sprites();
83 27
84 // Initialize text engine. 28 // Initialize text engine.
85 txt_init(0, COLOR_RED, 0); 29 // txt_init(0, COLOR_RED, 0);
86 30
87 // Register interrupts. 31 // Register interrupts.
88 irq_init(); 32 irq_init();
@@ -90,7 +34,7 @@ int main(void) {
90 34
91 // turn sound on 35 // turn sound on
92 SOUND_STATUS = SOUND_ENABLE; 36 SOUND_STATUS = SOUND_ENABLE;
93 SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2, 7); 37 SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1 | SOUND_SQUARE2, 3);
94 SOUND_DSOUND_MASTER = SOUND_DMG100; 38 SOUND_DSOUND_MASTER = SOUND_DMG100;
95 39
96 // Initialize timer. 40 // Initialize timer.
@@ -116,16 +60,15 @@ int main(void) {
116 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE; 60 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE;
117 } 61 }
118 62
119 txt_position(1,6); 63 // txt_position(1,6);
120 txt_clear_line(); 64 // txt_clear_line();
121 txt_printf(" BPM: %d\n\n", bpm); 65 // txt_printf(" BPM: %d\n\n", bpm);
122
123 txt_clear_line();
124 txt_printf(" Step: %d\n", step_counter);
125 txt_clear_line();
126 txt_printf(" Note: %s\n", note_names[active_note]);
127 66
128 update_button_sprites(); 67 // txt_clear_line();
68 // txt_printf(" Step: %d\n", step_counter);
69 // txt_clear_line();
70 // txt_printf(" Note: %s\n", note_names[active_note]);
71 render_sequencer_sprites();
129 }; 72 };
130 73
131 return 0; 74 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 @@
1#define SPRITE_NOTE_NAMES_W 16
2#define SPRITE_NOTE_NAMES_H 8
3
4u32 sprite_note_names[] = {
5 0x77417111, 0x77000000, 0x00000000, 0x00000000,
6 0x13157555, 0x33000000, 0x07040701, 0x07000000,
7 0x73457515, 0x73000000, 0x00000000, 0x00000000,
8 0x17117351, 0x37000000, 0x07040701, 0x07000000,
9 0x77417311, 0x77000000, 0x00000000, 0x00000000,
10 0x77417311, 0x71000000, 0x00000000, 0x00000000,
11 0x17117155, 0x37000000, 0x07040701, 0x07000000,
12 0x77417115, 0x77000000, 0x00000000, 0x00000000,
13 0x17157557, 0x35000000, 0x07040701, 0x07000000,
14 0x77457517, 0x75000000, 0x00000000, 0x00000000,
15 0x17157355, 0x37000000, 0x07040701, 0x07000000,
16 0x77457315, 0x77000000, 0x00000000, 0x00000000,
17 0x77416141, 0x77000000, 0x00000000, 0x00000000,
18 0x13157555, 0x33000000, 0x07040604, 0x07000000,
19 0x73456545, 0x73000000, 0x00000000, 0x00000000,
20 0x17117351, 0x37000000, 0x07040604, 0x07000000,
21 0x77416341, 0x77000000, 0x00000000, 0x00000000,
22 0x77416341, 0x71000000, 0x00000000, 0x00000000,
23 0x17117155, 0x37000000, 0x07040604, 0x07000000,
24 0x77416145, 0x77000000, 0x00000000, 0x00000000,
25 0x17157557, 0x35000000, 0x07040604, 0x07000000,
26 0x77456547, 0x75000000, 0x00000000, 0x00000000,
27 0x17157355, 0x37000000, 0x07040604, 0x07000000,
28 0x77456345, 0x77000000, 0x00000000, 0x00000000,
29 0x47615171, 0x47000000, 0x00000000, 0x00000000,
30 0x13157555, 0x33000000, 0x04060507, 0x04000000,
31 0x43655575, 0x43000000, 0x00000000, 0x00000000,
32 0x17117351, 0x37000000, 0x04060507, 0x04000000,
33 0x47615371, 0x47000000, 0x00000000, 0x00000000,
34 0x47615371, 0x41000000, 0x00000000, 0x00000000,
35 0x17117155, 0x37000000, 0x04060507, 0x04000000,
36 0x47615175, 0x47000000, 0x00000000, 0x00000000,
37 0x17157557, 0x35000000, 0x04060507, 0x04000000,
38 0x47655577, 0x45000000, 0x00000000, 0x00000000,
39 0x17157355, 0x37000000, 0x04060507, 0x04000000,
40 0x47655375, 0x47000000, 0x00000000, 0x00000000,
41 0x77117141, 0x77000000, 0x00000000, 0x00000000,
42 0x13157555, 0x33000000, 0x07010704, 0x07000000,
43 0x73157545, 0x73000000, 0x00000000, 0x00000000,
44 0x17117351, 0x37000000, 0x07010704, 0x07000000,
45 0x77117341, 0x77000000, 0x00000000, 0x00000000,
46 0x77117341, 0x71000000, 0x00000000, 0x00000000,
47 0x17117155, 0x37000000, 0x07010704, 0x07000000,
48 0x77117145, 0x77000000, 0x00000000, 0x00000000,
49 0x17157557, 0x35000000, 0x07010704, 0x07000000,
50 0x77157547, 0x75000000, 0x00000000, 0x00000000,
51 0x17157355, 0x37000000, 0x07010704, 0x07000000,
52 0x77157345, 0x77000000, 0x00000000, 0x00000000,
53 0x77117151, 0x77000000, 0x00000000, 0x00000000,
54 0x13157555, 0x33000000, 0x07010705, 0x07000000,
55 0x73157555, 0x73000000, 0x00000000, 0x00000000,
56 0x17117351, 0x37000000, 0x07010705, 0x07000000,
57 0x77117351, 0x77000000, 0x00000000, 0x00000000,
58 0x77117351, 0x71000000, 0x00000000, 0x00000000,
59 0x17117155, 0x37000000, 0x07010705, 0x07000000,
60 0x77117155, 0x77000000, 0x00000000, 0x00000000,
61 0x17157557, 0x35000000, 0x07010705, 0x07000000,
62 0x77157557, 0x75000000, 0x00000000, 0x00000000,
63 0x17157355, 0x37000000, 0x07010705, 0x07000000,
64 0x77157355, 0x77000000, 0x00000000, 0x00000000,
65 0x77412111, 0x17000000, 0x00000000, 0x00000000,
66 0x13157555, 0x33000000, 0x07040201, 0x01000000,
67 0x73452515, 0x13000000, 0x00000000, 0x00000000,
68 0x17117351, 0x37000000, 0x07040201, 0x01000000,
69 0x77412311, 0x17000000, 0x00000000, 0x00000000,
70 0x77412311, 0x11000000, 0x00000000, 0x00000000,
71 0x17117155, 0x37000000, 0x07040201, 0x01000000,
72 0x77412115, 0x17000000, 0x00000000, 0x00000000,
73 0x17157557, 0x35000000, 0x07040201, 0x01000000,
74 0x77452517, 0x15000000, 0x00000000, 0x00000000,
75 0x17157355, 0x37000000, 0x07040201, 0x01000000,
76 0x77452315, 0x17000000, 0x00000000, 0x00000000,
77 0x77517151, 0x77000000, 0x00000000, 0x00000000,
78};
79
80typedef struct SeqTrigger {
81 bool trigger;
82 Note note;
83 // TODO: ...
84} SeqTrigger;
85
86static SeqTrigger sequence_synth[] = {
87 {true, NOTE_D_4},
88 {true, NOTE_F_4},
89 {true, NOTE_A_4},
90 {true, NOTE_C_5},
91
92 {true, NOTE_D_4},
93 {false, NOTE_D_4},
94 {false, NOTE_D_4},
95 {false, NOTE_D_4},
96
97 {true, NOTE_D_4},
98 {true, NOTE_F_4},
99 {true, NOTE_A_4},
100 {true, NOTE_C_5},
101
102 {true, NOTE_D_4},
103 {false, NOTE_D_4},
104 {true, NOTE_A_4},
105 {false, NOTE_A_5},
106};
107
108static int step_counter = 0;
109static Note active_note;
110
111void
112irq_timer_0(void) {
113 active_note = sequence_synth[step_counter].note;
114 if (sequence_synth[step_counter].trigger) {
115 SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(13) | SOUND_SQUARE_ENV_TIME(4) | SOUND_SQUARE_DUTY(2);
116 SOUND_SQUARE1_FREQ = SOUND_SQUARE_RESET | sound_rates[active_note];
117 }
118 step_counter = (step_counter + 1) % 16;
119}
120
121void
122set_time(int bpm) {
123 // The number of ticks of a 1024 cycle clock in a step based on the BPM can
124 // be calculated as:
125 // X bpm -> 60000 / 4 / bpm = Y ms = Ye-3 s
126 // Y ms -> Ye-3 / 59.99e-9 /1024 = Z ticks
127 // We have to operate on integer values, so the numbers have been
128 // precalculated to `n_ticks = 244181 / bmp`
129 int n_ticks = -244181 / bpm;
130
131 irs_set(IRQ_TIMER_0, irq_timer_0);
132 TIMER_DATA_0 = n_ticks;
133 TIMER_CTRL_0 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_FREQ_3;
134}
135
136static size_t note_sprites_id = 0;
137
138//
139// Sequencer sprite memory.
140//
141// Currently we load all sequencer sprite memory in the VRAM:
142//
143// - Note names: 0-73x2 tiles
144// - ...
145//
146// The order of OBJs correspond to:
147//
148// - 000-015 step note names.
149// - 015-029 step trigger steps.
150// - 030-045 step duration indicators.
151// - 046-046 current step marker.
152// - 047-047 trigger selection indicator.
153//
154
155size_t obj_counter = 0;
156
157typedef struct SeqSprite {
158 u8 id;
159 int x;
160 int y;
161 u16 obj_attr_0;
162 u16 obj_attr_1;
163 u16 obj_attr_2;
164} SeqSprite;
165
166#define SEQ_POS_X 20
167#define SEQ_POS_Y 20
168
169// SeqSprite seq_sprites[] = {
170// // 000-015: Step note names.
171// {
172// .x = SEQ_POS_X,
173// .y = SEQ_POS_Y,
174// .obj_attr_0 = OBJ_SHAPE_WIDE,
175// .obj_attr_1 = OBJ_SHAPE_SMALL,
176// .obj_attr_2 = 0,
177// },
178// };
179
180SeqSprite seq_sprites[16] = {0};
181
182void
183init_sequencer_sprites() {
184 // Load note sprites.
185 note_sprites_id = load_packed_sprite_data(&sprite_note_names, 2, 73);
186
187 for (size_t i = 0; i < 16; ++i) {
188 int x = SEQ_POS_X + i * 16;
189 int y = SEQ_POS_Y;
190 if (i >= 8) {
191 y += 32;
192 x -= 8 * 16;
193 }
194 seq_sprites[i].x = x;
195 seq_sprites[i].y = y;
196
197 seq_sprites[i].id = obj_counter++;
198 seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_Y_COORD(y);
199 // TODO: They should start hidden until the update function changes that.
200 // seq_sprites[i].obj_attr_0 = OBJ_SHAPE_WIDE | OBJ_HIDDEN;
201 seq_sprites[i].obj_attr_1 = OBJ_SIZE_SMALL | OBJ_X_COORD(x);
202 }
203}
204
205void
206render_sequencer_sprites() {
207 size_t len = sizeof(seq_sprites) / sizeof(SeqSprite);
208 for (size_t i = 0; i < len; ++i) {
209 size_t id = seq_sprites[i].id;
210 // TODO: This needs to be done in an update function, not here.
211 size_t base_tile = sequence_synth[i].note;
212 seq_sprites[i].obj_attr_2 = base_tile;
213
214 OBJ_ATTR_0(id) = seq_sprites[i].obj_attr_0;
215 OBJ_ATTR_1(id) = seq_sprites[i].obj_attr_1;
216 OBJ_ATTR_2(id) = seq_sprites[i].obj_attr_2;
217 }
218}