summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-06-08 11:21:37 +0200
committerBad Diode <bd@badd10de.dev>2021-06-08 11:21:37 +0200
commit404a85e7ab39e26a5ac9d0fba470a53fd5cb959f (patch)
tree53db2099023619d314be8ae35fbcb247d6f84ca8
parent32cd65387f8ba2ea6a92c1c44da7a31b8ceef4b0 (diff)
downloadgba-sequencer-404a85e7ab39e26a5ac9d0fba470a53fd5cb959f.tar.gz
gba-sequencer-404a85e7ab39e26a5ac9d0fba470a53fd5cb959f.zip
Add old sequencer logic and input control
-rw-r--r--src/main.c65
-rw-r--r--src/rng.c15
-rw-r--r--src/sequencer.c566
3 files changed, 586 insertions, 60 deletions
diff --git a/src/main.c b/src/main.c
index b14fbed..a322df2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -13,6 +13,7 @@ WITH REGARD TO THIS SOFTWARE.
13 13
14#include "filesystem.c" 14#include "filesystem.c"
15#include "renderer.c" 15#include "renderer.c"
16#include "sequencer.c"
16 17
17// 18//
18// Config parameters. 19// Config parameters.
@@ -37,11 +38,14 @@ WITH REGARD TO THIS SOFTWARE.
37 txt_position((PROF_SHOW_X), (PROF_SHOW_Y)+1);\ 38 txt_position((PROF_SHOW_X), (PROF_SHOW_Y)+1);\
38 txt_printf("FLIP: %lu ", flip_cycles);\ 39 txt_printf("FLIP: %lu ", flip_cycles);\
39 txt_position((PROF_SHOW_X), (PROF_SHOW_Y)+2);\ 40 txt_position((PROF_SHOW_X), (PROF_SHOW_Y)+2);\
41 txt_printf("INPUT: %lu ", input_cycles);\
42 txt_position((PROF_SHOW_X), (PROF_SHOW_Y)+3);\
40 txt_printf("FRAME: %lu ", frame_counter);\ 43 txt_printf("FRAME: %lu ", frame_counter);\
41 frame_counter++;\ 44 frame_counter++;\
42 } while (0) 45 } while (0)
43#define PROF_INIT() \ 46#define PROF_INIT() \
44 u32 frame_counter = 0;\ 47 u32 frame_counter = 0;\
48 u32 input_cycles = 0;\
45 u32 eval_cycles = 0;\ 49 u32 eval_cycles = 0;\
46 u32 flip_cycles = 0; 50 u32 flip_cycles = 0;
47#else 51#else
@@ -50,66 +54,6 @@ WITH REGARD TO THIS SOFTWARE.
50#define PROF_INIT() 54#define PROF_INIT()
51#endif 55#endif
52 56
53#define TRIG_W 15
54#define TRIG_H 24
55#define TRIG_START_X 66
56#define TRIG_START_Y 90
57#define TRIG_OFFSET_X (TRIG_W + 4)
58#define TRIG_OFFSET_Y (TRIG_H + 7)
59
60void
61draw_triggers(void) {
62 for (size_t i = 0; i < 8; i++) {
63 size_t x0 = TRIG_START_X + TRIG_OFFSET_X * i;
64 size_t x1 = TRIG_START_X + TRIG_W + TRIG_OFFSET_X * i;
65 size_t y0 = TRIG_START_Y;
66 size_t y1 = TRIG_START_Y + TRIG_H;
67 draw_rect(x0, y0, x1, y1, 1);
68 }
69 for (size_t i = 0; i < 8; i++) {
70 size_t x0 = TRIG_START_X + TRIG_OFFSET_X * i;
71 size_t x1 = TRIG_START_X + TRIG_W + TRIG_OFFSET_X * i;
72 size_t y0 = TRIG_START_Y + TRIG_OFFSET_Y;
73 size_t y1 = TRIG_START_Y + TRIG_H + TRIG_OFFSET_Y;
74 draw_rect(x0, y0, x1, y1, 1);
75 }
76}
77
78#define CHAN_START_X 35
79#define CHAN_START_Y 90
80#define CHAN_OFFSET_Y 12
81
82void
83draw_channels(void) {
84 // Contains 5 channel buttons: Ch. 1-4 + FM. We are only drawing the DMG
85 // channels for now, since FM may take some time to develop.
86 u32 channel_buttons[] = {
87 0xff017111, 0x117101ff, 0xff008585, 0x879500ff,
88 0x0f080808, 0x0808080f, 0xff01b989, 0x89b901ff,
89 0xff004242, 0x434a00ff, 0x0f080909, 0x0909080f,
90 0xff015d45, 0xc55d01ff, 0xff00a1a1, 0xa1a500ff,
91 0x0f080a0a, 0x0a0a080f, 0xff015d45, 0xc55d01ff,
92 0xff00a1a1, 0xa12500ff, 0x0f080a0a, 0x0a0b080f,
93 0xff01c141, 0xc14101ff, 0xff00151c, 0x141400ff,
94 0x0f080808, 0x0808080f,
95 };
96 Tile channel_tiles[3 * 4] = {0};
97 unpack_tiles(channel_buttons, channel_tiles, 3 * 4);
98 size_t k = 0;
99 for (size_t i = 0; i < 4; i++) {
100 size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y;
101 draw_tile(CHAN_START_X, y, channel_tiles + k++, false);
102 draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, false);
103 draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, false);
104 }
105}
106
107void
108sequencer_init(void) {
109 draw_triggers();
110 draw_channels();
111}
112
113int main(void) { 57int main(void) {
114 // Adjust system wait times. 58 // Adjust system wait times.
115 SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE; 59 SYSTEM_WAIT = SYSTEM_WAIT_CARTRIDGE;
@@ -132,6 +76,7 @@ int main(void) {
132 while (true) { 76 while (true) {
133 bios_vblank_wait(); 77 bios_vblank_wait();
134 PROF(flip_buffer(), flip_cycles); 78 PROF(flip_buffer(), flip_cycles);
79 PROF(handle_sequencer_input(), input_cycles);
135 PROF_SHOW(); 80 PROF_SHOW();
136 } 81 }
137 82
diff --git a/src/rng.c b/src/rng.c
new file mode 100644
index 0000000..96760b8
--- /dev/null
+++ b/src/rng.c
@@ -0,0 +1,15 @@
1u16 rng_state;
2
3u32 hash16(u32 input, u32 key) {
4 u32 hash = input * key;
5 return ((hash >> 16) ^ hash) & 0xFFFF;
6}
7
8u16 rng16() {
9 rng_state += 0xbadd;
10 return hash16(rng_state, 0x10de);
11}
12
13u32 rng32() {
14 return (rng16() << 16) | rng16();
15}
diff --git a/src/sequencer.c b/src/sequencer.c
new file mode 100644
index 0000000..43e6ffc
--- /dev/null
+++ b/src/sequencer.c
@@ -0,0 +1,566 @@
1#include "rng.c"
2
3//
4// Globals.
5//
6typedef enum {
7 SEQ_SELECT_TRIGGER,
8 SEQ_SELECT_CHANNEL,
9 SEQ_SELECT_PARAMETER,
10} SeqSelect;
11static int bpm = 115;
12static int step_counter = 0;
13int trig_selection_loc = 0;
14int param_selection_loc = 64;
15int channel_selection_loc = 2;
16SeqSelect current_selection = SEQ_SELECT_TRIGGER;
17
18//
19// Wave data.
20//
21
22// TODO: Make them u32.
23static const u8 sine_wave[16] = {
24 0x89, 0xBC, 0xDE, 0xEF,
25 0xFE, 0xED, 0xCB, 0x98,
26 0x76, 0x43, 0x21, 0x10,
27 0x01, 0x12, 0x34, 0x67,
28};
29
30static const u8 saw_wave[16] = {
31 0x01, 0x23, 0x45, 0x67,
32 0x89, 0xab, 0xcd, 0xef,
33 0x01, 0x23, 0x45, 0x67,
34 0x89, 0xab, 0xcd, 0xef,
35};
36
37static const u8 square_wave[16] = {
38 0xff, 0xff, 0xff, 0xff,
39 0xff, 0xff, 0xff, 0xff,
40 0x00, 0x00, 0x00, 0x00,
41 0x00, 0x00, 0x00, 0x00,
42};
43
44// TODO: Split into individual trigger types.
45typedef struct SeqTrigger {
46 bool trigger;
47 Note note;
48 u8 env_volume;
49 u8 env_time;
50 u8 env_direction;
51 u8 duty_cycle;
52 u8 sweep_number;
53 u8 sweep_time;
54 u8 sweep_direction;
55 u8 wave_volume;
56 u8 wave_mode;
57 u8 wave_a[16];
58 u8 wave_b[16];
59} SeqTrigger;
60
61static SeqTrigger sequences[3][16] = {
62 // Synth 1.
63 {
64 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
65 {false, NOTE_D_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
66 {false, NOTE_E_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
67 {false, NOTE_F_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
68 {false, NOTE_G_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
69 {false, NOTE_A_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
70 {false, NOTE_B_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
71 {false, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
72 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
73 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
74 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
75 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
76 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
77 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
78 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
79 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
80 },
81 // Synth 2.
82 {
83 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
84 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
85 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
86 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
87 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
88 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
89 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
90 {false, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
91 {false, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
92 {false, NOTE_B_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
93 {false, NOTE_A_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
94 {false, NOTE_G_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
95 {false, NOTE_F_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
96 {false, NOTE_E_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
97 {false, NOTE_D_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
98 {false, NOTE_C_4, 8, 4, 0, 2, 0, 0, 0, 0, 0, {0}, {0}},
99 },
100 // Synth 3.
101 {
102 {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
103 {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
104 {true, NOTE_E_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
105 {true, NOTE_F_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
106 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
107 {true, NOTE_A_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
108 {true, NOTE_B_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
109 {true, NOTE_C_6, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
110 {true, NOTE_C_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
111 {true, NOTE_D_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
112 {true, NOTE_E_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
113 {true, NOTE_F_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
114 {true, NOTE_G_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
115 {true, NOTE_A_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
116 {true, NOTE_B_5, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
117 {true, NOTE_C_6, 8, 4, 0, 2, 0, 0, 0, 3, 0, {0xffffffff, 0x00000000, 0xffffffff, 0x00000000}, {0}},
118 },
119};
120
121
122#define TRIG_W 15
123#define TRIG_H 24
124#define TRIG_START_X 66
125#define TRIG_START_Y 90
126#define TRIG_OFFSET_X (TRIG_W + 4)
127#define TRIG_OFFSET_Y (TRIG_H + 7)
128
129void
130draw_triggers(void) {
131 for (size_t i = 0; i < 8; i++) {
132 size_t x0 = TRIG_START_X + TRIG_OFFSET_X * i;
133 size_t x1 = TRIG_START_X + TRIG_W + TRIG_OFFSET_X * i;
134 size_t y0 = TRIG_START_Y;
135 size_t y1 = TRIG_START_Y + TRIG_H;
136 draw_rect(x0, y0, x1, y1, 1);
137 }
138 for (size_t i = 0; i < 8; i++) {
139 size_t x0 = TRIG_START_X + TRIG_OFFSET_X * i;
140 size_t x1 = TRIG_START_X + TRIG_W + TRIG_OFFSET_X * i;
141 size_t y0 = TRIG_START_Y + TRIG_OFFSET_Y;
142 size_t y1 = TRIG_START_Y + TRIG_H + TRIG_OFFSET_Y;
143 draw_rect(x0, y0, x1, y1, 1);
144 }
145}
146
147#define CHAN_START_X 35
148#define CHAN_START_Y 90
149#define CHAN_OFFSET_Y 12
150
151void
152draw_channels(void) {
153 // Contains 5 channel buttons: Ch. 1-4 + FM. We are only drawing the DMG
154 // channels for now, since FM may take some time to develop.
155 u32 channel_buttons[] = {
156 0xff017111, 0x117101ff, 0xff008585, 0x879500ff,
157 0x0f080808, 0x0808080f, 0xff01b989, 0x89b901ff,
158 0xff004242, 0x434a00ff, 0x0f080909, 0x0909080f,
159 0xff015d45, 0xc55d01ff, 0xff00a1a1, 0xa1a500ff,
160 0x0f080a0a, 0x0a0a080f, 0xff015d45, 0xc55d01ff,
161 0xff00a1a1, 0xa12500ff, 0x0f080a0a, 0x0a0b080f,
162 0xff01c141, 0xc14101ff, 0xff00151c, 0x141400ff,
163 0x0f080808, 0x0808080f,
164 };
165 Tile channel_tiles[3 * 4] = {0};
166 unpack_tiles(channel_buttons, channel_tiles, 3 * 4);
167 size_t k = 0;
168 for (size_t i = 0; i < 4; i++) {
169 size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y;
170 draw_tile(CHAN_START_X, y, channel_tiles + k++, false);
171 draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, false);
172 draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, false);
173 }
174}
175
176void
177irq_timer_0(void) {
178 Note active_note;
179 {
180 SeqTrigger *trig = &sequences[0][step_counter];
181 active_note = trig->note;
182 if (trig->trigger) {
183 SOUND_SQUARE1_SWEEP = SOUND_SWEEP_NUMBER(trig->sweep_number)
184 | SOUND_SWEEP_DIR(trig->sweep_direction)
185 | SOUND_SWEEP_TIME(trig->sweep_time);
186 SOUND_SQUARE1_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume)
187 | SOUND_SQUARE_ENV_TIME(trig->env_time)
188 | SOUND_SQUARE_ENV_DIR(trig->env_direction)
189 | SOUND_SQUARE_DUTY(trig->duty_cycle);
190 SOUND_SQUARE1_FREQ = SOUND_FREQ_RESET
191 | sound_rates[active_note];
192 }
193 }
194 {
195 SeqTrigger *trig = &sequences[1][step_counter];
196 active_note = trig->note;
197 if (trig->trigger) {
198 SOUND_SQUARE2_CTRL = SOUND_SQUARE_ENV_VOL(trig->env_volume)
199 | SOUND_SQUARE_ENV_TIME(trig->env_time)
200 | SOUND_SQUARE_ENV_DIR(trig->env_direction)
201 | SOUND_SQUARE_DUTY(trig->duty_cycle);
202 SOUND_SQUARE2_FREQ = SOUND_FREQ_RESET
203 | sound_rates[active_note];
204 }
205 }
206 {
207 SeqTrigger *trig = &sequences[2][step_counter];
208 active_note = trig->note;
209 if (trig->trigger) {
210 // Update both banks.
211 // TODO: Actually depends on which bank is selected, no need to
212 // update both if only one is playing.
213 // TODO: Should we compare if previous and current wave are the
214 // same before updating?
215 SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(1);
216 memcpy(SOUND_WAVE_RAM, trig->wave_a, 16);
217 SOUND_WAVE_MODE = SOUND_WAVE_BANK_SELECT(0);
218 memcpy(SOUND_WAVE_RAM, trig->wave_b, 16);
219
220 switch (trig->wave_mode) {
221 case 0: {
222 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0)
223 | SOUND_WAVE_BANK_SELECT(0);
224 } break;
225 case 1: {
226 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(0)
227 | SOUND_WAVE_BANK_SELECT(1);
228 } break;
229 case 2: {
230 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1)
231 | SOUND_WAVE_BANK_SELECT(0);
232 } break;
233 case 3: {
234 SOUND_WAVE_MODE = SOUND_WAVE_BANK_MODE(1)
235 | SOUND_WAVE_BANK_SELECT(1);
236 } break;
237 }
238 SOUND_WAVE_MODE |= SOUND_WAVE_ENABLE;
239
240 switch (trig->wave_volume) {
241 case 0: {
242 SOUND_WAVE_CTRL = SOUND_WAVE_MUTE;
243 } break;
244 case 1: {
245 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_25;
246 } break;
247 case 2: {
248 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_50;
249 } break;
250 case 3: {
251 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_75;
252 } break;
253 case 4: {
254 SOUND_WAVE_CTRL = SOUND_WAVE_VOL_100;
255 } break;
256 }
257 SOUND_WAVE_FREQ = SOUND_FREQ_RESET
258 | sound_rates[active_note];
259 }
260 }
261 step_counter = (step_counter + 1) % 16;
262}
263
264#define SEQ_N_CHANNELS 3
265
266void
267handle_sequencer_input(void) {
268 poll_keys();
269 SeqTrigger *trig = &sequences[channel_selection_loc][trig_selection_loc];
270 if (current_selection == SEQ_SELECT_TRIGGER) {
271 if (key_tap(KEY_LEFT)) {
272 if (trig_selection_loc == 0 || trig_selection_loc == 8) {
273 current_selection = SEQ_SELECT_CHANNEL;
274 } else {
275 trig_selection_loc = MAX(trig_selection_loc - 1, 0);
276 }
277 } else if (key_tap(KEY_RIGHT)) {
278 if (trig_selection_loc != 7) {
279 trig_selection_loc = MIN(trig_selection_loc + 1, 15);
280 }
281 } else if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) {
282 trig_selection_loc = (trig_selection_loc + 8) % 16;
283 } else if (key_tap(KEY_B)) {
284 trig->trigger ^= 1;
285 } else if (key_tap(KEY_L)) {
286 if (trig->trigger) {
287 trig->note = MAX(trig->note - 1, NOTE_C_2);
288 }
289 } else if (key_tap(KEY_R)) {
290 if (trig->trigger) {
291 trig->note = MIN( trig->note + 1, NOTE_C_8);
292 }
293 } else if (key_tap(KEY_A)) {
294 // Switch to parameter selection.
295 current_selection = SEQ_SELECT_PARAMETER;
296 }
297 } else if (current_selection == SEQ_SELECT_PARAMETER) {
298 if (channel_selection_loc < 2) {
299 // Move through the selected synth parameters.
300 if (key_tap(KEY_LEFT)) {
301 int max_param = 6;
302 if (channel_selection_loc == 1) {
303 max_param = 3;
304 }
305 if (param_selection_loc == 0) {
306 param_selection_loc = max_param;
307 } else {
308 param_selection_loc = MAX(param_selection_loc - 1, 0);
309 }
310 }
311 if (key_tap(KEY_RIGHT)) {
312 int max_param = 6;
313 if (channel_selection_loc == 1) {
314 max_param = 3;
315 }
316 if (param_selection_loc == max_param) {
317 param_selection_loc = 0;
318 } else {
319 param_selection_loc = MIN(param_selection_loc + 1, max_param);
320 }
321 }
322
323 // Adjust the parameters up or down.
324 if (key_tap(KEY_L) || key_tap(KEY_R)) {
325 int inc;
326 if (key_tap(KEY_L)) {
327 inc = -1;
328 } else {
329 inc = 1;
330 }
331 switch (param_selection_loc) {
332 case 0: {
333 trig->env_volume = CLAMP(trig->env_volume + inc, 0, 15);
334 } break;
335 case 1: {
336 trig->env_time = CLAMP(trig->env_time + inc, 0, 7);
337 } break;
338 case 2: {
339 trig->env_direction ^= 1;
340 } break;
341 case 3: {
342 trig->duty_cycle = CLAMP(trig->duty_cycle + inc, 0, 3);
343 } break;
344 case 4: {
345 trig->sweep_number = CLAMP(trig->sweep_number + inc, 0, 7);
346 } break;
347 case 5: {
348 trig->sweep_time = CLAMP(trig->sweep_time + inc, 0, 7);
349 } break;
350 case 6: {
351 if (trig->sweep_direction == 0) {
352 trig->sweep_direction = 1;
353 } else {
354 trig->sweep_direction = 0;
355 }
356 } break;
357 }
358 }
359 } else if (channel_selection_loc == 2) {
360 if (key_tap(KEY_LEFT) || key_tap(KEY_RIGHT)) {
361 int inc = 0;
362 int loc = param_selection_loc;
363 if (key_tap(KEY_RIGHT)) {
364 if (loc == 15 || loc == 31) {
365 inc = 17;
366 } else if (loc != 47 && loc != 63){
367 inc = 1;
368 }
369 } else {
370 if (loc == 32 || loc == 48) {
371 inc = -17;
372 } else if (loc != 16 && loc != 64){
373 inc = -1;
374 }
375 }
376 param_selection_loc = CLAMP(loc + inc, 0, 71);
377 }
378 if (key_tap(KEY_UP) || key_tap(KEY_DOWN)) {
379 int inc = 0;
380 int loc = param_selection_loc;
381 if (key_tap(KEY_UP)) {
382 if ((loc >= 16 && loc < 32) || (loc >= 48 && loc < 64)) {
383 inc = -16;
384 } else if (loc == 64) {
385 inc = -48;
386 } else if (loc == 65) {
387 inc = -45;
388 } else if (loc == 66) {
389 inc = -42;
390 } else if (loc == 67) {
391 inc = -39;
392 } else if (loc == 68) {
393 inc = -20;
394 } else if (loc == 69) {
395 inc = -17;
396 } else if (loc == 70) {
397 inc = -14;
398 } else if (loc == 71) {
399 inc = -11;
400 }
401 } else {
402 if (loc < 16 || (loc >= 32 && loc < 48)) {
403 inc = 16;
404 } else if (loc >= 16 && loc <= 19){
405 inc = 48 - (loc - 16);
406 } else if (loc >= 20 && loc <= 23){
407 inc = 45 - (loc - 20);
408 } else if (loc >= 24 && loc <= 27){
409 inc = 42 - (loc - 24);
410 } else if (loc >= 28 && loc <= 31){
411 inc = 39 - (loc - 28);
412 } else if (loc >= 48 && loc <= 51){
413 inc = 20 - (loc - 48);
414 } else if (loc >= 52 && loc <= 55){
415 inc = 17 - (loc - 52);
416 } else if (loc >= 56 && loc <= 59){
417 inc = 14 - (loc - 56);
418 } else if (loc >= 60 && loc <= 63){
419 inc = 11 - (loc - 60);
420 }
421 }
422 param_selection_loc = CLAMP(loc + inc, 0, 71);
423 }
424 if (key_tap(KEY_R) || key_tap(KEY_L)) {
425 int odd = param_selection_loc & 0x1;
426 int inc;
427 if (key_tap(KEY_R)) {
428 inc = 1;
429 } else {
430 inc = -1;
431 }
432 // Wave: AA BB CC DD ...
433 // ^^
434 // |`- odd
435 // `-- even
436 if (param_selection_loc < 32) {
437 u8 byte_number = param_selection_loc >> 1;
438 u8 byte = sequences[2][trig_selection_loc].wave_a[byte_number];
439 if (odd) {
440 byte = (~0xF & byte) | ((byte + inc) & 0xF);
441 } else {
442 byte = (0xF & byte) | (((byte >> 4) + inc) & 0xF) << 4;
443 }
444 sequences[2][trig_selection_loc].wave_a[byte_number] = byte;
445 } else if (param_selection_loc < 64){
446 u8 byte_number = (param_selection_loc - 32) >> 1;
447 u8 byte = sequences[2][trig_selection_loc].wave_b[byte_number];
448 if (odd) {
449 byte = (~0xF & byte) | (byte + inc);
450 } else {
451 byte = (0xF & byte) | ((byte >> 4) + inc) << 4;
452 }
453 sequences[2][trig_selection_loc].wave_b[byte_number] = byte;
454 } else if (param_selection_loc == 64){
455 memcpy(&trig->wave_a, &sine_wave, 16);
456 } else if (param_selection_loc == 65){
457 memcpy(&trig->wave_a, &saw_wave, 16);
458 } else if (param_selection_loc == 66){
459 memcpy(&trig->wave_a, &square_wave, 16);
460 } else if (param_selection_loc == 67){
461 u32 rand_wave[4] = {
462 rng32(), rng32(), rng32(), rng32(),
463 };
464 memcpy(&trig->wave_a, &rand_wave, 16);
465 } else if (param_selection_loc == 68){
466 memcpy(&trig->wave_b, &sine_wave, 16);
467 } else if (param_selection_loc == 69){
468 memcpy(&trig->wave_b, &saw_wave, 16);
469 } else if (param_selection_loc == 70){
470 memcpy(&trig->wave_b, &square_wave, 16);
471 } else if (param_selection_loc == 71){
472 u32 rand_wave[4] = {
473 rng32(), rng32(), rng32(), rng32(),
474 };
475 memcpy(&trig->wave_b, &rand_wave, 16);
476 }
477 }
478 }
479
480 // Go back to trigger selection.
481 if (key_tap(KEY_A)) {
482 current_selection = SEQ_SELECT_TRIGGER;
483 }
484
485 // Enable disable trigger.
486 if (key_tap(KEY_B)) {
487 trig->trigger ^= 1;
488 }
489 } else if (current_selection == SEQ_SELECT_CHANNEL) {
490 if (key_tap(KEY_RIGHT)) {
491 current_selection = SEQ_SELECT_TRIGGER;
492 trig_selection_loc = 0;
493 param_selection_loc = 0;
494 }
495 if (key_tap(KEY_UP)) {
496 if (channel_selection_loc == 0) {
497 channel_selection_loc = SEQ_N_CHANNELS - 1;
498 } else {
499 channel_selection_loc = MAX(channel_selection_loc - 1, 0);
500 }
501 }
502 if (key_tap(KEY_DOWN)) {
503 if (channel_selection_loc == SEQ_N_CHANNELS - 1) {
504 channel_selection_loc = 0;
505 } else {
506 channel_selection_loc = MIN(channel_selection_loc + 1, SEQ_N_CHANNELS);
507 }
508 }
509 }
510
511 if (key_tap(KEY_START)) {
512 step_counter = 0;
513 if ((TIMER_CTRL_0 & TIMER_CTRL_ENABLE) == 0) {
514 set_time(bpm);
515 } else {
516 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE;
517 SOUND_SQUARE1_CTRL = 0;
518 SOUND_SQUARE2_CTRL = 0;
519 SOUND_WAVE_CTRL = 0;
520 }
521 }
522 if (key_tap(KEY_SELECT)) {
523 TIMER_CTRL_0 ^= TIMER_CTRL_ENABLE;
524 SOUND_SQUARE1_CTRL = 0;
525 SOUND_SQUARE2_CTRL = 0;
526 SOUND_WAVE_CTRL = 0;
527 }
528
529 if (key_tap(KEY_LEFT)
530 || key_tap(KEY_RIGHT)
531 || key_tap(KEY_UP)
532 || key_tap(KEY_DOWN)
533 || key_tap(KEY_L)
534 || key_tap(KEY_R)
535 ) {
536 }
537}
538
539void
540set_time(int bpm) {
541 // The number of ticks of a 1024 cycle clock in a step based on the BPM can
542 // be calculated as:
543 // X bpm -> 60000 / 4 / bpm = Y ms = Ye-3 s
544 // Y ms -> Ye-3 / 59.99e-9 / 1024 = Z ticks
545 // We have to operate on integer values, so the numbers have been
546 // precalculated to `n_ticks = 244181 / bmp`
547 int n_ticks = -244181 / bpm;
548 irs_set(IRQ_TIMER_0, irq_timer_0);
549 TIMER_DATA_0 = n_ticks;
550 TIMER_CTRL_0 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_FREQ_3;
551}
552
553void
554sequencer_init(void) {
555 // Initialize background objects and sprites.
556 draw_triggers();
557 draw_channels();
558
559 // Initialize sound system.
560 SOUND_STATUS = SOUND_ENABLE;
561 SOUND_DMG_MASTER = sound_volume(SOUND_SQUARE1
562 | SOUND_SQUARE2
563 | SOUND_WAVE, 3);
564 SOUND_DSOUND_MASTER = SOUND_DMG25;
565 set_time(bpm);
566}