aboutsummaryrefslogtreecommitdiffstats
path: root/src/sequencer.c
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2023-04-23 15:48:59 +0200
committerBad Diode <bd@badd10de.dev>2023-04-23 15:48:59 +0200
commitff6e784e7c5ebe223666c6c631305397ad358289 (patch)
tree0f87823d48366a6beb8d36d7eea5dc33663d7abd /src/sequencer.c
parentdeb9c48fbd3dc5854de4ae3a04dc999029c10ae0 (diff)
downloadstepper-ff6e784e7c5ebe223666c6c631305397ad358289.tar.gz
stepper-ff6e784e7c5ebe223666c6c631305397ad358289.zip
Start decoupling of rendering from update passes
Diffstat (limited to 'src/sequencer.c')
-rw-r--r--src/sequencer.c2079
1 files changed, 6 insertions, 2073 deletions
diff --git a/src/sequencer.c b/src/sequencer.c
index ff3904d..fd47d0b 100644
--- a/src/sequencer.c
+++ b/src/sequencer.c
@@ -1,1740 +1,13 @@
1#include "globals.c"
1#include "rng.c" 2#include "rng.c"
2#include "text.h" 3#include "text.h"
3 4#include "assets.c"
4void 5#include "patterns.c"
5sram_read(u8 *dst, u16 pos, u16 n_bytes) { 6#include "save.c"
6 for (size_t i = 0; i < n_bytes; ++i) { 7#include "drawing.c"
7 dst[i] = SRAM[pos + i]; 8#include "clipboard.c"
8 }
9}
10
11void
12sram_write(u8 *src, u16 pos, u16 n_bytes) {
13 for (size_t i = 0; i < n_bytes; ++i) {
14 SRAM[pos + i] = src[i];
15 }
16}
17 9
18void set_time(int bpm); 10void set_time(int bpm);
19void clipboard_paste(void);
20void clipboard_copy(void);
21
22//
23// Color indexes.
24//
25
26#define COL_BG 0
27#define COL_FG 1
28#define COL_RED 2
29#define COL_BLUE 3
30#define COL_CYAN 4
31#define COL_GREY 5
32
33// Theme colors.
34#define COL_CURSOR COL_BLUE
35#define COL_NOTE_PRESSED COL_GREY
36#define COL_WAVE_A COL_RED
37#define COL_WAVE_B COL_CYAN
38
39#define CHAN_W 19
40#define CHAN_H 8
41#define CHAN_START_X 29
42#define CHAN_START_Y 92
43#define CHAN_OFFSET_Y 12
44
45#define TRIG_W 15
46#define TRIG_H 24
47#define TRIG_START_X 58
48#define TRIG_START_Y 92
49#define TRIG_OFFSET_X (TRIG_W + 3)
50#define TRIG_OFFSET_Y (TRIG_H + 7)
51
52#define PIANO_W 170
53#define PIANO_H 20
54#define PIANO_START_X 29
55#define PIANO_START_Y 65
56#define PIANO_NOTE_W 2
57
58#define PARAMS_W 170
59#define PARAMS_H 64
60#define PARAMS_START_X 29
61#define PARAMS_START_Y 1
62
63#define R_SIDEBAR_X ((TRIG_START_X) + (TRIG_OFFSET_X) * 8 + 4)
64#define L_SIDEBAR_X ((CHAN_START_X) - 26)
65
66#define PAT_START_X (L_SIDEBAR_X + 5)
67#define PAT_START_Y 18
68#define PAT_W 14
69#define PAT_H 12
70#define PAT_OFFSET_Y 17
71
72#define R_COL_W 24
73#define BPM_START_X (R_SIDEBAR_X)
74#define BPM_START_Y (TRIG_START_Y + TRIG_H + 9)
75#define BPM_H 22
76
77#define PLAY_START_X (R_SIDEBAR_X)
78#define PLAY_START_Y (TRIG_START_Y)
79#define STOP_START_X (R_SIDEBAR_X)
80#define STOP_START_Y (TRIG_START_Y + 14)
81#define PLAY_STOP_H (10)
82
83#define BANK_START_X (R_SIDEBAR_X + 5)
84#define BANK_START_Y (PAT_START_Y)
85
86#define SEQ_N_CHANNELS 4
87
88//
89// Assets.
90//
91
92#define N_TILES_NOTE_NAMES 73 * 2
93#define N_TILES_CHAN_BTSN 4 * 3
94#define N_TILES_WAVE_BTNS 4 * 2
95
96#define ASSETS_NOTE_NAMES ((u32*)(MEM_VRAM + KB(32)))
97#define ASSETS_CHANNEL_BUTTONS (ASSETS_NOTE_NAMES + (N_TILES_NOTE_NAMES * 8))
98#define ASSETS_DEFAULT_WAVES (ASSETS_CHANNEL_BUTTONS + (N_TILES_CHAN_BTSN * 8))
99
100static const u32 note_names[] = {
101 0x000000e0, 0x202020e0, 0x0000000e, 0x080e020e,
102 0x00000098, 0xa8a8a898, 0x00000038, 0x203b0a39,
103 0x00000060, 0xa0a0a060, 0x0000000e, 0x080e020e,
104 0x000000b8, 0x889888b8, 0x00000038, 0x203b0a39,
105 0x000000e0, 0x206020e0, 0x0000000e, 0x080e020e,
106 0x000000e0, 0x20602020, 0x0000000e, 0x080e020e,
107 0x000000b8, 0x8888a8b8, 0x00000038, 0x203b0a39,
108 0x000000e0, 0x2020a0e0, 0x0000000e, 0x080e020e,
109 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x203b0a39,
110 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x080e020e,
111 0x000000b8, 0xa898a8b8, 0x00000038, 0x203b0a39,
112 0x000000e0, 0xa060a0e0, 0x0000000e, 0x080e020e,
113 0x000000e0, 0x202020e0, 0x0000000e, 0x080c080e,
114 0x00000098, 0xa8a8a898, 0x00000038, 0x20332239,
115 0x00000060, 0xa0a0a060, 0x0000000e, 0x080c080e,
116 0x000000b8, 0x889888b8, 0x00000038, 0x20332239,
117 0x000000e0, 0x206020e0, 0x0000000e, 0x080c080e,
118 0x000000e0, 0x20602020, 0x0000000e, 0x080c080e,
119 0x000000b8, 0x8888a8b8, 0x00000038, 0x20332239,
120 0x000000e0, 0x2020a0e0, 0x0000000e, 0x080c080e,
121 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x20332239,
122 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x080c080e,
123 0x000000b8, 0xa898a8b8, 0x00000038, 0x20332239,
124 0x000000e0, 0xa060a0e0, 0x0000000e, 0x080c080e,
125 0x000000e0, 0x202020e0, 0x0000000a, 0x0a0e0808,
126 0x00000098, 0xa8a8a898, 0x00000028, 0x283b2221,
127 0x00000060, 0xa0a0a060, 0x0000000a, 0x0a0e0808,
128 0x000000b8, 0x889888b8, 0x00000028, 0x283b2221,
129 0x000000e0, 0x206020e0, 0x0000000a, 0x0a0e0808,
130 0x000000e0, 0x20602020, 0x0000000a, 0x0a0e0808,
131 0x000000b8, 0x8888a8b8, 0x00000028, 0x283b2221,
132 0x000000e0, 0x2020a0e0, 0x0000000a, 0x0a0e0808,
133 0x000000b8, 0xa8a8b8a8, 0x00000028, 0x283b2221,
134 0x000000e0, 0xa0a0e0a0, 0x0000000a, 0x0a0e0808,
135 0x000000b8, 0xa898a8b8, 0x00000028, 0x283b2221,
136 0x000000e0, 0xa060a0e0, 0x0000000a, 0x0a0e0808,
137 0x000000e0, 0x202020e0, 0x0000000e, 0x020e080e,
138 0x00000098, 0xa8a8a898, 0x00000038, 0x083b2239,
139 0x00000060, 0xa0a0a060, 0x0000000e, 0x020e080e,
140 0x000000b8, 0x889888b8, 0x00000038, 0x083b2239,
141 0x000000e0, 0x206020e0, 0x0000000e, 0x020e080e,
142 0x000000e0, 0x20602020, 0x0000000e, 0x020e080e,
143 0x000000b8, 0x8888a8b8, 0x00000038, 0x083b2239,
144 0x000000e0, 0x2020a0e0, 0x0000000e, 0x020e080e,
145 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x083b2239,
146 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x020e080e,
147 0x000000b8, 0xa898a8b8, 0x00000038, 0x083b2239,
148 0x000000e0, 0xa060a0e0, 0x0000000e, 0x020e080e,
149 0x000000e0, 0x202020e0, 0x0000000e, 0x020e0a0e,
150 0x00000098, 0xa8a8a898, 0x00000038, 0x083b2a39,
151 0x00000060, 0xa0a0a060, 0x0000000e, 0x020e0a0e,
152 0x000000b8, 0x889888b8, 0x00000038, 0x083b2a39,
153 0x000000e0, 0x206020e0, 0x0000000e, 0x020e0a0e,
154 0x000000e0, 0x20602020, 0x0000000e, 0x020e0a0e,
155 0x000000b8, 0x8888a8b8, 0x00000038, 0x083b2a39,
156 0x000000e0, 0x2020a0e0, 0x0000000e, 0x020e0a0e,
157 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x083b2a39,
158 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x020e0a0e,
159 0x000000b8, 0xa898a8b8, 0x00000038, 0x083b2a39,
160 0x000000e0, 0xa060a0e0, 0x0000000e, 0x020e0a0e,
161 0x000000e0, 0x202020e0, 0x0000000e, 0x08040202,
162 0x00000098, 0xa8a8a898, 0x00000038, 0x20130a09,
163 0x00000060, 0xa0a0a060, 0x0000000e, 0x08040202,
164 0x000000b8, 0x889888b8, 0x00000038, 0x20130a09,
165 0x000000e0, 0x206020e0, 0x0000000e, 0x08040202,
166 0x000000e0, 0x20602020, 0x0000000e, 0x08040202,
167 0x000000b8, 0x8888a8b8, 0x00000038, 0x20130a09,
168 0x000000e0, 0x2020a0e0, 0x0000000e, 0x08040202,
169 0x000000b8, 0xa8a8b8a8, 0x00000038, 0x20130a09,
170 0x000000e0, 0xa0a0e0a0, 0x0000000e, 0x08040202,
171 0x000000b8, 0xa898a8b8, 0x00000038, 0x20130a09,
172 0x000000e0, 0xa060a0e0, 0x0000000e, 0x08040202,
173 0x000000e0, 0x202020e0, 0x0000000e, 0x0a0e0a0e,
174};
175
176static const u32 channel_buttons[] = {
177 0xff017111, 0x117101ff, 0xff008585, 0x879500ff,
178 0x0f080808, 0x0808080f, 0xff01b989, 0x89b901ff,
179 0xff004242, 0x434a00ff, 0x0f080909, 0x0909080f,
180 0xff015d45, 0xc55d01ff, 0xff00a1a1, 0xa1a500ff,
181 0x0f080a0a, 0x0a0a080f, 0xff015d45, 0xc55d01ff,
182 0xff00a1a1, 0xa12500ff, 0x0f080a0a, 0x0a0b080f,
183 0xff01c141, 0xc14101ff, 0xff00151c, 0x141400ff,
184 0x0f080808, 0x0808080f,
185};
186
187static const u32 default_wave_buttons[] = {
188 0xff013149, 0x850101ff, 0x3f202028, 0x2423203f,
189 0xff016151, 0x49c501ff, 0x3f202c2a, 0x2928203f,
190 0xff017d45, 0x45c501ff, 0x3f202828, 0x282f203f,
191 0xff014911, 0x812501ff, 0x3f202128, 0x2420203f,
192};
193
194//
195// Wave data.
196//
197
198static const u32 sine_wave[16] = {
199 0xefdebc89, 0x98cbedfe, 0x10214376, 0x67341201,
200};
201
202static const u32 saw_wave[16] = {
203 0x67452301, 0xefcdab89, 0x67452301, 0xefcdab89,
204};
205
206static const u32 square_wave[16] = {
207 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
208};
209
210//
211// Globals.
212//
213
214const int default_bpm = 75;
215static int step_counter = 0;
216int trig_selection_loc = 0;
217int param_selection_loc = 0;
218int channel_selection_loc = 0;
219int pattern_selection_loc = 0;
220int right_col_selection_loc = 0;
221int play_status = 0;
222static int current_pattern = 0;
223static int next_pattern = 0;
224static int current_bank = 0;
225
226enum RIGHT_COL_LOC {
227 R_COL_BPM = 0,
228 R_COL_STOP = 1,
229 R_COL_PLAY = 2,
230 R_COL_BANK_D = 3,
231 R_COL_BANK_C = 4,
232 R_COL_BANK_B = 5,
233 R_COL_BANK_A = 6,
234};
235
236typedef struct TriggerNote {
237 bool active;
238 Note note;
239} TriggerNote;
240
241typedef struct ChannelSquareParams {
242 u8 env_volume;
243 u8 env_time;
244 u8 env_direction;
245 u8 duty_cycle;
246 u8 sweep_number;
247 u8 sweep_time;
248 u8 sweep_direction;
249} ChannelSquareParams;
250
251typedef struct ChannelWaveParams {
252 u8 wave_volume;
253 u8 wave_mode;
254 u32 wave_a[4];
255 u32 wave_b[4];
256} ChannelWaveParams;
257
258typedef struct ChannelNoiseParams {
259 u8 env_volume;
260 u8 env_time;
261 u8 env_direction;
262 u8 bit_mode;
263} ChannelNoiseParams;
264
265typedef struct ChannelSquare {
266 bool active;
267 TriggerNote notes[16];
268 ChannelSquareParams params[16];
269} ChannelSquare;
270
271typedef struct ChannelWave {
272 bool active;
273 TriggerNote notes[16];
274 ChannelWaveParams params[16];
275} ChannelWave;
276
277typedef struct ChannelNoise {
278 bool active;
279 TriggerNote notes[16];
280 ChannelNoiseParams params[16];
281} ChannelNoise;
282
283const ChannelSquare default_ch1 = {
284 .notes = {
285 {true, NOTE_C_4},
286 {true, NOTE_D_SHARP_4},
287 {true, NOTE_G_4},
288 {true, NOTE_A_SHARP_4},
289 {true, NOTE_C_4},
290 {true, NOTE_D_SHARP_4},
291 {true, NOTE_G_4},
292 {true, NOTE_A_SHARP_4},
293 {true, NOTE_C_4},
294 {true, NOTE_D_SHARP_4},
295 {true, NOTE_G_4},
296 {true, NOTE_A_SHARP_4},
297 {true, NOTE_C_4},
298 {true, NOTE_D_SHARP_4},
299 {true, NOTE_G_4},
300 {true, NOTE_A_SHARP_4},
301 },
302 .params = {
303 {8, 4, 0, 2, 0, 0, 0},
304 {8, 4, 0, 2, 0, 0, 0},
305 {8, 4, 0, 2, 0, 0, 0},
306 {8, 4, 0, 2, 0, 0, 0},
307 {8, 4, 0, 2, 0, 0, 0},
308 {8, 4, 0, 2, 0, 0, 0},
309 {8, 4, 0, 2, 0, 0, 0},
310 {8, 4, 0, 2, 0, 0, 0},
311 {8, 4, 0, 2, 0, 0, 0},
312 {8, 4, 0, 2, 0, 0, 0},
313 {8, 4, 0, 2, 0, 0, 0},
314 {8, 4, 0, 2, 0, 0, 0},
315 {8, 4, 0, 2, 0, 0, 0},
316 {8, 4, 0, 2, 0, 0, 0},
317 {8, 4, 0, 2, 0, 0, 0},
318 {8, 4, 0, 2, 0, 0, 0},
319 },
320 .active = true,
321};
322
323const ChannelSquare default_ch2 = {
324 .notes = {
325 {true, NOTE_C_3},
326 {true, NOTE_C_3},
327 {true, NOTE_C_3},
328 {true, NOTE_C_3},
329 {true, NOTE_C_3},
330 {true, NOTE_C_3},
331 {true, NOTE_C_3},
332 {true, NOTE_C_3},
333 {true, NOTE_C_3},
334 {true, NOTE_C_3},
335 {true, NOTE_C_3},
336 {true, NOTE_C_3},
337 {true, NOTE_C_3},
338 {true, NOTE_C_3},
339 {true, NOTE_C_3},
340 {true, NOTE_C_3},
341 },
342 .params = {
343 {8, 4, 0, 2, 0, 0, 0},
344 {8, 4, 0, 2, 0, 0, 0},
345 {8, 4, 0, 2, 0, 0, 0},
346 {8, 4, 0, 2, 0, 0, 0},
347 {8, 4, 0, 2, 0, 0, 0},
348 {8, 4, 0, 2, 0, 0, 0},
349 {8, 4, 0, 2, 0, 0, 0},
350 {8, 4, 0, 2, 0, 0, 0},
351 {8, 4, 0, 2, 0, 0, 0},
352 {8, 4, 0, 2, 0, 0, 0},
353 {8, 4, 0, 2, 0, 0, 0},
354 {8, 4, 0, 2, 0, 0, 0},
355 {8, 4, 0, 2, 0, 0, 0},
356 {8, 4, 0, 2, 0, 0, 0},
357 {8, 4, 0, 2, 0, 0, 0},
358 {8, 4, 0, 2, 0, 0, 0},
359 },
360 .active = true,
361};
362
363const ChannelWave default_ch3 = {
364 .notes = {
365 {true, NOTE_C_5},
366 {true, NOTE_C_5},
367 {true, NOTE_C_5},
368 {true, NOTE_A_SHARP_5},
369 {true, NOTE_A_SHARP_5},
370 {true, NOTE_C_5},
371 {true, NOTE_C_5},
372 {true, NOTE_G_5},
373 {true, NOTE_C_5},
374 {true, NOTE_C_5},
375 {true, NOTE_C_5},
376 {true, NOTE_A_SHARP_5},
377 {true, NOTE_A_SHARP_5},
378 {true, NOTE_C_5},
379 {true, NOTE_C_5},
380 {true, NOTE_G_5},
381 },
382 .params = {
383 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
384 {3, 0, {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
385 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
386 {3, 0, {0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
387 {3, 0, {0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
388 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
389 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
390 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
391 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
392 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
393 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
394 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
395 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
396 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
397 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
398 {3, 0, {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000},{0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000}},
399 },
400 .active = true,
401};
402
403const ChannelNoise default_ch4 = {
404 .notes = {
405 {true, NOTE_D_SHARP_4},
406 {false, NOTE_E_6},
407 {false, NOTE_E_6},
408 {false, NOTE_E_6},
409 {true, NOTE_D_SHARP_4},
410 {false, NOTE_E_6},
411 {false, NOTE_E_6},
412 {false, NOTE_E_6},
413 {true, NOTE_D_SHARP_4},
414 {false, NOTE_E_6},
415 {false, NOTE_E_6},
416 {false, NOTE_E_6},
417 {true, NOTE_D_SHARP_4},
418 {false, NOTE_E_6},
419 {false, NOTE_E_6},
420 {false, NOTE_E_6},
421 },
422 .params = {
423 {0xF, 0x2, 0, 0},
424 {0xF, 0x2, 0, 0},
425 {0xF, 0x2, 0, 0},
426 {0xF, 0x2, 0, 0},
427 {0xF, 0x2, 0, 0},
428 {0xF, 0x2, 0, 0},
429 {0xF, 0x2, 0, 0},
430 {0xF, 0x2, 0, 0},
431 {0xF, 0x2, 0, 0},
432 {0xF, 0x2, 0, 0},
433 {0xF, 0x2, 0, 0},
434 {0xF, 0x2, 0, 0},
435 {0xF, 0x2, 0, 0},
436 {0xF, 0x2, 0, 0},
437 {0xF, 0x2, 0, 0},
438 {0xF, 0x2, 0, 0},
439 },
440 .active = true,
441};
442
443typedef struct Metadata {
444 u8 blank;
445 u32 magic;
446 int current_bank;
447 int current_pattern;
448} Metadata;
449
450static Metadata metadata = {0};
451
452typedef struct Pattern {
453 ChannelSquare ch1;
454 ChannelSquare ch2;
455 ChannelWave ch3;
456 ChannelNoise ch4;
457 int bpm;
458 u8 bank;
459} Pattern;
460
461static Pattern patterns[8] = {
462 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
463 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
464 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
465 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
466 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
467 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
468 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
469 {default_ch1, default_ch2, default_ch3, default_ch4, default_bpm, 0},
470};
471
472typedef enum ClipboardType {
473 CLIP_EMPTY,
474 CLIP_TRIG,
475 CLIP_PARAM_CH1,
476 CLIP_PARAM_CH2,
477 CLIP_PARAM_CH3,
478 CLIP_PARAM_CH4,
479 CLIP_PATTERN,
480 CLIP_CHANNEL,
481} ClipboardType;
482
483typedef struct Clipboard {
484 ClipboardType type;
485 u8 src_pat;
486 u8 src_chan;
487 u8 src_trig;
488} Clipboard;
489
490static Clipboard clipboard = {CLIP_EMPTY, 0, 0, 0};
491
492void
493save_bank(int i) {
494 sram_write(&patterns, sizeof(Metadata) + i * sizeof(patterns), sizeof(patterns));
495}
496
497void
498load_bank(int i) {
499 sram_read(&patterns, sizeof(Metadata) + i * sizeof(patterns), sizeof(patterns));
500}
501
502//
503// Channel render functions.
504//
505
506void
507draw_channels(void) {
508 // Contains 5 channel buttons: Ch. 1-4 + FM. We are only drawing the DMG
509 // channels for now, since FM may take some time to develop.
510 Tile *channel_tiles = ASSETS_CHANNEL_BUTTONS;
511 size_t k = 0;
512 for (size_t i = 0; i < 4; i++) {
513 bool active = false;
514 switch (i) {
515 case 0: {
516 active = patterns[pattern_selection_loc].ch1.active;
517 } break;
518 case 1: {
519 active = patterns[pattern_selection_loc].ch2.active;
520 } break;
521 case 2: {
522 active = patterns[pattern_selection_loc].ch3.active;
523 } break;
524 case 3: {
525 active = patterns[pattern_selection_loc].ch4.active;
526 } break;
527 }
528 u8 clr = active ? COL_FG : COL_GREY;
529 size_t y = CHAN_START_Y + i * CHAN_OFFSET_Y;
530 // draw_tile(CHAN_START_X, y, channel_tiles + k++, clr, false);
531 // draw_tile(CHAN_START_X + 8, y, channel_tiles + k++, clr, false);
532 // draw_tile(CHAN_START_X + 16, y, channel_tiles + k++, clr, false);
533 }
534}
535
536void
537draw_channel_cursor(size_t i, u8 clr) {
538 size_t offset_x = 0;
539 size_t offset_y = CHAN_H + i * CHAN_OFFSET_Y + 1;
540 size_t x0 = CHAN_START_X + offset_x;
541 size_t x1 = CHAN_START_X + offset_x + CHAN_W;
542 size_t y = CHAN_START_Y + offset_y;
543 draw_line(x0, y, x1, y, clr);
544}
545
546//
547// Trigger render functions.
548//
549
550void
551clear_trigger(size_t i) {
552 size_t offset_x = TRIG_OFFSET_X * (i % 8);
553 size_t offset_y = i < 8 ? 0 : TRIG_OFFSET_Y;
554 size_t x0 = TRIG_START_X + offset_x + 1;
555 size_t x1 = TRIG_START_X + offset_x + TRIG_W - 1;
556 size_t y0 = TRIG_START_Y + offset_y + 1;
557 size_t y1 = TRIG_START_Y + offset_y + TRIG_H - 4;
558 draw_filled_rect(x0, y0, x1, y1, COL_BG);
559}
560
561void
562draw_trigger(size_t chan, size_t i) {
563 TriggerNote trig = {0};
564 switch (chan) {
565 case 0: {
566 trig = patterns[pattern_selection_loc].ch1.notes[i];
567 } break;
568 case 1: {
569 trig = patterns[pattern_selection_loc].ch2.notes[i];
570 } break;
571 case 2: {
572 trig = patterns[pattern_selection_loc].ch3.notes[i];
573 } break;
574 case 3: {
575 trig = patterns[pattern_selection_loc].ch4.notes[i];
576 } break;
577 }
578 if (trig.active) {
579 size_t offset_x = TRIG_OFFSET_X * (i % 8);
580 size_t offset_y = i < 8 ? 0 : TRIG_OFFSET_Y;
581 size_t x = TRIG_START_X + offset_x;
582 size_t y = TRIG_START_Y + offset_y;
583 Tile *tiles = ASSETS_NOTE_NAMES;
584 tiles += 2 * trig.note;
585 // draw_tile(x, y, tiles, COL_FG, true);
586 // draw_tile(x + 8, y, tiles + 1, COL_FG, true);
587 } else {
588 clear_trigger(i);
589 }
590}
591
592void
593draw_trig_cursor(size_t i, u8 clr) {
594 size_t offset_x = TRIG_OFFSET_X * (i % 8);
595 size_t offset_y = i < 8 ? 2 : 2 + TRIG_OFFSET_Y;
596 size_t x0 = TRIG_START_X + offset_x;
597 size_t x1 = TRIG_START_X + TRIG_W + offset_x;
598 size_t y = TRIG_START_Y + TRIG_H + offset_y;
599 draw_line(x0, y, x1, y, clr);
600}
601
602void
603draw_right_col_cursor(u8 clr) {
604 size_t x0 = 0;
605 size_t x1 = 0;
606 size_t y = 0;
607 switch (right_col_selection_loc) {
608 case R_COL_BPM: {
609 x0 = BPM_START_X;
610 x1 = x0 + R_COL_W;
611 y = BPM_START_Y + BPM_H + 2;
612 } break;
613 case R_COL_STOP: {
614 x0 = STOP_START_X;
615 x1 = x0 + R_COL_W;
616 y = STOP_START_Y + PLAY_STOP_H + 2;
617 } break;
618 case R_COL_PLAY: {
619 x0 = PLAY_START_X;
620 x1 = x0 + R_COL_W;
621 y = PLAY_START_Y + PLAY_STOP_H + 2;
622 } break;
623 case R_COL_BANK_A: {
624 x0 = BANK_START_X;
625 x1 = x0 + PAT_W;
626 y = BANK_START_Y + PAT_H + 2;
627 } break;
628 case R_COL_BANK_B: {
629 x0 = BANK_START_X;
630 x1 = x0 + PAT_W;
631 y = BANK_START_Y + PAT_H + 2 + 1 * PAT_OFFSET_Y;
632 } break;
633 case R_COL_BANK_C: {
634 x0 = BANK_START_X;
635 x1 = x0 + PAT_W;
636 y = BANK_START_Y + PAT_H + 2 + 2 * PAT_OFFSET_Y;
637 } break;
638 case R_COL_BANK_D: {
639 x0 = BANK_START_X;
640 x1 = x0 + PAT_W;
641 y = BANK_START_Y + PAT_H + 2 + 3 * PAT_OFFSET_Y;
642 } break;
643 }
644 draw_line(x0, y, x1, y, clr);
645}
646
647void
648draw_current_step(u8 col) {
649 size_t offset_x = TRIG_OFFSET_X * (step_counter % 8);
650 size_t offset_y = step_counter < 8 ? 2 : 2 + TRIG_OFFSET_Y;
651 size_t x0 = TRIG_START_X + 3 + offset_x;
652 size_t x1 = TRIG_START_X - 3 + TRIG_W + offset_x;
653 size_t y = TRIG_START_Y - 4 + TRIG_H + offset_y;
654 draw_line(x0, y, x1, y, col);
655}
656
657void
658draw_bank_buttons() {
659 size_t x = BANK_START_X;
660 size_t y = BANK_START_Y;
661 // txt_drawf_small("BANK", x - 2, y - 10, 4, COL_FG);
662 char bank_names[] = {
663 'A', 'B', 'C', 'D',
664 };
665 for (int i = 0; i < 4; i++) {
666 int color = COL_GREY;
667 if (i == current_bank) {
668 color = COL_FG;
669 }
670 draw_filled_rect(x, y, x + PAT_W, y + PAT_H, COL_BG);
671 draw_rect(x, y, x + PAT_W, y + PAT_H, color);
672 // txt_drawc(bank_names[i], x + 4, y + 2, 6, color);
673 y += PAT_OFFSET_Y;
674 }
675}
676
677void
678draw_pattern_buttons() {
679 size_t x = PAT_START_X;
680 size_t y = PAT_START_Y;
681 // txt_drawf_small("PAT", x, y - 10, 4, COL_FG);
682 char pat_names[] = {
683 'A', 'B', 'C', 'D',
684 'E', 'F', 'G', 'H',
685 };
686 for (int i = 0; i < 8; i++) {
687 int color = COL_GREY;
688 if (i == current_pattern) {
689 color = COL_FG;
690 }
691 if (i == next_pattern && current_pattern != next_pattern) {
692 color = COL_BLUE;
693 }
694 draw_filled_rect(x, y, x + PAT_W, y + PAT_H, COL_BG);
695 draw_rect(x, y, x + PAT_W, y + PAT_H, color);
696 // txt_drawc(pat_names[i], x + 4, y + 2, 6, color);
697 y += PAT_OFFSET_Y;
698 }
699}
700
701void
702draw_pattern_cursor(size_t i, u8 clr) {
703 size_t offset_x = 0;
704 size_t offset_y = PAT_H + i * PAT_OFFSET_Y + 2;
705 size_t x0 = PAT_START_X + offset_x;
706 size_t x1 = PAT_START_X + offset_x + PAT_W;
707 size_t y = PAT_START_Y + offset_y;
708 draw_line(x0, y, x1, y, clr);
709}
710
711void
712draw_play() {
713 size_t x = PLAY_START_X;
714 size_t y = PLAY_START_Y;
715 draw_filled_rect(x, y, x + R_COL_W, y + PLAY_STOP_H, COL_BG);
716 draw_rect(x, y, x + R_COL_W, y + PLAY_STOP_H, COL_CYAN);
717 if (play_status == 1) {
718 // Pause button
719 draw_filled_rect(x + 10, y + 3, x + 11, y + 7, COL_CYAN);
720 draw_filled_rect(x + 13, y + 3, x + 14, y + 7, COL_CYAN);
721 } else {
722 // Play button
723 x += 1;
724 draw_line(x + 10, y + 2, x + 10, y + 8, COL_CYAN);
725 draw_line(x + 11, y + 3, x + 11, y + 7, COL_CYAN);
726 draw_line(x + 12, y + 4, x + 12, y + 6, COL_CYAN);
727 draw_line(x + 13, y + 5, x + 13, y + 5, COL_CYAN);
728 }
729}
730
731void
732draw_stop() {
733 size_t x = STOP_START_X;
734 size_t y = STOP_START_Y;
735 draw_rect(x, y, x + R_COL_W, y + PLAY_STOP_H, COL_RED);
736 draw_filled_rect(x + 10, y + 3, x + 14, y + 7, COL_RED);
737}
738
739void
740draw_bpm() {
741 size_t x = BPM_START_X;
742 size_t y = BPM_START_Y;
743
744 // Draw bounding box.
745 draw_filled_rect(x, y, x + R_COL_W, y + BPM_H, COL_BG);
746 draw_rect(x, y, x + R_COL_W, y + BPM_H, COL_FG);
747 draw_line(x + 5, y, x + 19, y, COL_BG);
748 // txt_drawf_small("BPM", x + 5, y - 4, 4, COL_FG);
749
750 // Make sure its horizontally centered if only 2 digits
751 int bpm = patterns[pattern_selection_loc].bpm;
752 if (bpm >= 100) {
753 txt_drawf("%d", x + 3, y + 7, 6, COL_FG, bpm);
754 } else {
755 txt_drawf("%d", x + 6, y + 7, 6, COL_FG, bpm);
756 }
757}
758
759void
760draw_triggers(void) {
761 for (size_t i = 0; i < 16; i++) {
762 size_t offset_x = TRIG_OFFSET_X * (i % 8);
763 size_t offset_y = i < 8 ? 0 : 0 + TRIG_OFFSET_Y;
764 size_t x0 = TRIG_START_X + offset_x;
765 size_t x1 = TRIG_START_X + offset_x + TRIG_W;
766 size_t y0 = TRIG_START_Y + offset_y;
767 size_t y1 = TRIG_START_Y + offset_y + TRIG_H;
768 draw_rect(x0, y0, x1, y1, COL_FG);
769 clear_trigger(i);
770 draw_trigger(channel_selection_loc, i);
771 }
772}
773
774void
775draw_note(u8 note, u8 clr) {
776 size_t octave = note / 12;
777 size_t value = note % 12;
778
779 size_t x0 = 0;
780 size_t y0 = 0;
781 size_t x1 = 0;
782 size_t y1 = 0;
783 switch (value) {
784 // White notes.
785 case 0:{
786 x0 = PIANO_START_X + 2 + octave * 28;
787 x1 = x0 + 1;
788 y0 = PIANO_START_Y + 2;
789 y1 = PIANO_START_Y - 2 + PIANO_H;
790 draw_filled_rect(x0, y0, x1, y1, clr);
791 x0 = PIANO_START_X + 2 + octave * 28 + 2;
792 x1 = x0;
793 y0 = y0 + 9;
794 draw_filled_rect(x0, y0, x1, y1, clr);
795 } break;
796 case 2:{
797 x0 = PIANO_START_X + 2 + octave * 28 + 5;
798 x1 = x0;
799 y0 = PIANO_START_Y + 2;
800 y1 = PIANO_START_Y - 2 + 12;
801 draw_filled_rect(x0, y0, x1, y1, clr);
802 x0 = PIANO_START_X + 2 + octave * 28 + 4;
803 x1 = x0 + 2;
804 y0 = PIANO_START_Y - 2 + 13;
805 y1 = y0 + 7;
806 draw_filled_rect(x0, y0, x1, y1, clr);
807 } break;
808 case 4:{
809 x0 = PIANO_START_X + 2 + octave * 28 + 9;
810 x1 = x0 + 1;
811 y0 = PIANO_START_Y + 2;
812 y1 = PIANO_START_Y - 2 + 12;
813 draw_filled_rect(x0, y0, x1, y1, clr);
814 x0 = PIANO_START_X + 2 + octave * 28 + 8;
815 x1 = x0 + 2;
816 y0 = PIANO_START_Y - 2 + 13;
817 y1 = y0 + 7;
818 draw_filled_rect(x0, y0, x1, y1, clr);
819 } break;
820 case 5:{
821 x0 = PIANO_START_X + 2 + octave * 28 + 12;
822 x1 = x0 + 1;
823 y0 = PIANO_START_Y + 2;
824 y1 = PIANO_START_Y - 2 + PIANO_H;
825 draw_filled_rect(x0, y0, x1, y1, clr);
826 x0 = PIANO_START_X + 2 + octave * 28 + 14;
827 x1 = x0;
828 y0 = y0 + 9;
829 draw_filled_rect(x0, y0, x1, y1, clr);
830 } break;
831 case 7:{
832 x0 = PIANO_START_X + 2 + octave * 28 + 17;
833 x1 = x0;
834 y0 = PIANO_START_Y + 2;
835 y1 = PIANO_START_Y - 2 + 12;
836 draw_filled_rect(x0, y0, x1, y1, clr);
837 x0 = PIANO_START_X + 2 + octave * 28 + 16;
838 x1 = x0 + 2;
839 y0 = PIANO_START_Y - 2 + 13;
840 y1 = y0 + 7;
841 draw_filled_rect(x0, y0, x1, y1, clr);
842 } break;
843 case 9:{
844 x0 = PIANO_START_X + 2 + octave * 28 + 21;
845 x1 = x0;
846 y0 = PIANO_START_Y + 2;
847 y1 = PIANO_START_Y - 2 + 12;
848 draw_filled_rect(x0, y0, x1, y1, clr);
849 x0 = PIANO_START_X + 2 + octave * 28 + 20;
850 x1 = x0 + 2;
851 y0 = PIANO_START_Y - 2 + 13;
852 y1 = y0 + 7;
853 draw_filled_rect(x0, y0, x1, y1, clr);
854 } break;
855 case 11: {
856 x0 = PIANO_START_X + 2 + octave * 28 + 25;
857 x1 = x0 + 1;
858 y0 = PIANO_START_Y + 2;
859 y1 = PIANO_START_Y - 2 + 12;
860 draw_filled_rect(x0, y0, x1, y1, clr);
861 x0 = PIANO_START_X + 2 + octave * 28 + 24;
862 x1 = x0 + 2;
863 y0 = PIANO_START_Y - 2 + 13;
864 y1 = y0 + 7;
865 draw_filled_rect(x0, y0, x1, y1, clr);
866 } break;
867 default: {
868 if (clr == COL_FG) {
869 clr = COL_BG;
870 }
871 y0 = PIANO_START_Y + 2;
872 y1 = PIANO_START_Y - 2 + 11;
873 switch (value) {
874 case 1: {
875 x0 = PIANO_START_X + 2 + octave * 28 + 3;
876 } break;
877 case 3: {
878 x0 = PIANO_START_X + 2 + octave * 28 + 7;
879 } break;
880 case 6: {
881 x0 = PIANO_START_X + 2 + octave * 28 + 15;
882 } break;
883 case 8: {
884 x0 = PIANO_START_X + 2 + octave * 28 + 19;
885 } break;
886 case 10: {
887 x0 = PIANO_START_X + 2 + octave * 28 + 23;
888 } break;
889 }
890 x1 = x0;
891 draw_line(x0, y0, x1, y1, clr);
892 } break;
893 }
894}
895
896void
897draw_piano(void) {
898 size_t x0 = PIANO_START_X;
899 size_t x1 = PIANO_START_X + PIANO_W;
900 size_t y0 = PIANO_START_Y;
901 size_t y1 = PIANO_START_Y + PIANO_H;
902 draw_rect(x0, y0, x1, y1, COL_FG);
903 for (size_t i = 0; i < 12 * 6; i++) {
904 draw_note(i, COL_FG);
905 }
906}
907
908void
909draw_params_cursor_wave(size_t i, u8 clr) {
910 u8 x_positions[] = {
911 // 32 half bytes (Wave A).
912 0, 4, 8, 12, 16, 20, 24, 28,
913 34, 38, 42, 46, 50, 54, 58, 62,
914 0, 4, 8, 12, 16, 20, 24, 28,
915 34, 38, 42, 46, 50, 54, 58, 62,
916 // 32 half bytes (Wave B).
917 70, 74, 78, 82, 86, 90, 94, 98,
918 104, 108, 112, 116, 120, 124, 128, 132,
919 70, 74, 78, 82, 86, 90, 94, 98,
920 104, 108, 112, 116, 120, 124, 128, 132,
921 // Default wave A.
922 1, 18, 35, 52,
923 // Default wave B.
924 71, 88, 105, 122,
925 // Mode selection.
926 141,
927 // Volume selection.
928 141,
929 };
930 u8 y_positions[] = {
931 // 32 half bytes (Wave A)
932 0, 0, 0, 0, 0, 0, 0, 0,
933 0, 0, 0, 0, 0, 0, 0, 0,
934 8, 8, 8, 8, 8, 8, 8, 8,
935 8, 8, 8, 8, 8, 8, 8, 8,
936 // 32 half bytes (Wave B)
937 0, 0, 0, 0, 0, 0, 0, 0,
938 0, 0, 0, 0, 0, 0, 0, 0,
939 8, 8, 8, 8, 8, 8, 8, 8,
940 8, 8, 8, 8, 8, 8, 8, 8,
941 // Default wave A.
942 20, 20, 20, 20,
943 // Default wave B.
944 20, 20, 20, 20,
945 // Mode selection.
946 20,
947 // Volume selection.
948 0,
949 };
950 size_t cursor_length = 0;
951 if (i < 64) {
952 cursor_length = 4;
953 } else if (i < 72) {
954 cursor_length = 13;
955 } else {
956 cursor_length = 30;
957 }
958 size_t x = PARAMS_START_X + x_positions[i] - 1;
959 size_t y = PARAMS_START_Y + PARAMS_H - 23 + y_positions[i];
960 draw_line(x, y, x + cursor_length, y, clr);
961}
962
963void
964draw_params_cursor_noise(size_t i, u8 clr) {
965 u8 x_positions[] = {
966 0, // Bit mode.
967 31, // Env. Vol.
968 59, // Env. Direction.
969 87, // Env. Time.
970 };
971 u8 y_positions[] = {
972 20, // Bit mode.
973 20, // Env. Vol.
974 20, // Env. Direction.
975 20, // Env. Time.
976 };
977 size_t cursor_length = 24;
978 size_t x = PARAMS_START_X + x_positions[i] + 30;
979 size_t y = PARAMS_START_Y + PARAMS_H - 23 + y_positions[i];
980 draw_line(x, y, x + cursor_length, y, clr);
981}
982
983void
984draw_params_cursor_square(size_t i, u8 clr, bool sweep) {
985 size_t x_offset = sweep ? 0 : 30;
986 u8 x_positions[] = {
987 0, // Duty.
988 31, // Env. Vol.
989 59, // Env. Direction.
990 87, // Env. Time.
991 118, // Sweep Number.
992 146, // Sweep Time.
993 132, // Sweep Direction.
994 };
995 u8 y_positions[] = {
996 20, // Duty.
997 20, // Env. Vol.
998 20, // Env. Direction.
999 20, // Env. Time.
1000 20, // Sweep Number.
1001 20, // Sweep Time.
1002 0, // Sweep Direction.
1003 };
1004 size_t cursor_length = 24;
1005 size_t x = PARAMS_START_X + x_positions[i] + x_offset;
1006 size_t y = PARAMS_START_Y + PARAMS_H - 23 + y_positions[i];
1007 draw_line(x, y, x + cursor_length, y, clr);
1008}
1009
1010void
1011draw_params_cursor(size_t i, u8 clr) {
1012 switch (channel_selection_loc) {
1013 case 0: {
1014 draw_params_cursor_square(i, clr, true);
1015 } break;
1016 case 1: {
1017 draw_params_cursor_square(i, clr, false);
1018 } break;
1019 case 2: {
1020 draw_params_cursor_wave(i, clr);
1021 } break;
1022 case 3: {
1023 draw_params_cursor_noise(i, clr);
1024 } break;
1025 }
1026}
1027
1028IWRAM_CODE
1029void
1030draw_wave_pattern(u8 *pattern, int x, int y, u8 clr) {
1031 for (size_t i = 0; i < 16; ++i) {
1032 u8 byte = pattern[i];
1033 u8 first = (byte >> 4) & 0xF;
1034 u8 second = byte & 0xF;
1035 u8 a = x + i * 4;
1036 u8 b = y + 16;
1037 draw_pixel(a, b - first, clr);
1038 draw_pixel(a + 1, b - first, clr);
1039 draw_pixel(a + 2, b - second, clr);
1040 draw_pixel(a + 3, b - second, clr);
1041 }
1042}
1043
1044IWRAM_CODE
1045void
1046clear_parameters(void) {
1047 size_t x0 = PARAMS_START_X;
1048 size_t y0 = PARAMS_START_Y;
1049 size_t x1 = PARAMS_START_X + PARAMS_W;
1050 size_t y1 = PARAMS_START_Y + PARAMS_H - 1;
1051 draw_filled_rect(x0, y0, x1, y1, COL_BG);
1052}
1053
1054IWRAM_CODE
1055void
1056draw_parameters_wave(void) {
1057 // Draw current wave data.
1058 Pattern *pat = &patterns[pattern_selection_loc];
1059 {
1060 u8 *wave_a = pat->ch3.params[trig_selection_loc].wave_a;
1061 u8 *wave_b = pat->ch3.params[trig_selection_loc].wave_b;
1062
1063 size_t x = PARAMS_START_X;
1064 size_t y = PARAMS_START_Y + 13;
1065
1066 // Wave Patterns.
1067 draw_wave_pattern(wave_a, x, y, COL_WAVE_A);
1068 draw_wave_pattern(wave_b, x + 70, y, COL_WAVE_B);
1069
1070 // Wave text.
1071 x -= 2;
1072 // txt_drawf_small("%02x%02x%02x%02x", x, y + 20, 4, COL_FG,
1073 // wave_a[0], wave_a[1], wave_a[2], wave_a[3]);
1074 // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 20, 4, COL_FG,
1075 // wave_a[4], wave_a[5], wave_a[6], wave_a[7]);
1076 // txt_drawf_small("%02x%02x%02x%02x", x, y + 28, 4, COL_FG,
1077 // wave_a[8], wave_a[9], wave_a[10], wave_a[11]);
1078 // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 28, 4, COL_FG,
1079 // wave_a[12], wave_a[13], wave_a[14], wave_a[15]);
1080
1081 x += 70;
1082 // txt_drawf_small("%02x%02x%02x%02x", x, y + 20, 4, COL_FG,
1083 // wave_b[0], wave_b[1], wave_b[2], wave_b[3]);
1084 // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 20, 4, COL_FG,
1085 // wave_b[4], wave_b[5], wave_b[6], wave_b[7]);
1086 // txt_drawf_small("%02x%02x%02x%02x", x, y + 28, 4, COL_FG,
1087 // wave_b[8], wave_b[9], wave_b[10], wave_b[11]);
1088 // txt_drawf_small("%02x%02x%02x%02x", x + 34, y + 28, 4, COL_FG,
1089 // wave_b[12], wave_b[13], wave_b[14], wave_b[15]);
1090 }
1091
1092 // Draw default wave buttons.
1093 {
1094 Tile *wave_tiles = ASSETS_DEFAULT_WAVES;
1095 size_t x = PARAMS_START_X;
1096 size_t y = PARAMS_START_Y + PARAMS_H - 12;
1097 for (size_t i = 0, k = 0; i < 4 * 2; i += 2, k++) {
1098 // draw_tile(x + 17 * k, y, wave_tiles + i, COL_FG, true);
1099 // draw_tile(x + 17 * k + 8, y, wave_tiles + i + 1, COL_FG, true);
1100 }
1101 for (size_t i = 0, k = 0; i < 4 * 2; i += 2, k++) {
1102 // draw_tile(x + 17 * k + 70, y, wave_tiles + i, COL_FG, true);
1103 // draw_tile(x + 17 * k + 8 + 70, y, wave_tiles + i + 1, COL_FG, true);
1104 }
1105 }
1106
1107 // Mode selection.
1108 {
1109 size_t x = PARAMS_START_X + 140;
1110 size_t y = PARAMS_START_Y + PARAMS_H - 22;
1111 draw_line(x, y + 4, x + 5, y + 4, COL_FG);
1112 draw_line(x + 25, y + 4, x + 30, y + 4, COL_FG);
1113 draw_line(x, y + 5, x, y + 16, COL_FG);
1114 draw_line(x + 30, y + 5, x + 30, y + 17, COL_FG);
1115 draw_line(x, y + 17, x + 30, y + 17, COL_FG);
1116 // txt_drawf_small("mode", x + 6, y, 4, COL_FG);
1117
1118 switch (pat->ch3.params[trig_selection_loc].wave_mode) {
1119 case 0: {
1120 txt_drawf("A", x + 12, y + 7, 6, COL_FG);
1121 } break;
1122 case 1: {
1123 txt_drawf("B", x + 12, y + 7, 6, COL_FG);
1124 } break;
1125 case 2: {
1126 txt_drawf("A+B", x + 6, y + 7, 6, COL_FG);
1127 } break;
1128 }
1129 }
1130
1131 // Wave volume.
1132 {
1133 size_t x = PARAMS_START_X + 140;
1134 size_t y = PARAMS_START_Y + PARAMS_H - 45;
1135 draw_line(x, y + 7, x + 7, y + 7, COL_FG);
1136 draw_line(x + 23, y + 7, x + 30, y + 7, COL_FG);
1137 draw_line(x, y + 8, x, y + 19, COL_FG);
1138 draw_line(x + 30, y + 8, x + 30, y + 19, COL_FG);
1139 draw_line(x, y + 20, x + 30, y + 20, COL_FG);
1140 // txt_drawf_small("vol", x + 8, y + 3, 4, COL_FG);
1141
1142 switch (pat->ch3.params[trig_selection_loc].wave_volume) {
1143 case 0: {
1144 txt_drawf("0", x + 12, y + 10, 6, COL_FG);
1145 } break;
1146 case 1: {
1147 txt_drawf("25", x + 9, y + 10, 6, COL_FG);
1148 } break;
1149 case 2: {
1150 txt_drawf("50", x + 9, y + 10, 6, COL_FG);
1151 } break;
1152 case 3: {
1153 txt_drawf("75", x + 9, y + 10, 6, COL_FG);
1154 } break;
1155 case 4: {
1156 txt_drawf("100", x + 6, y + 10, 6, COL_FG);
1157 } break;
1158 }
1159 }
1160}
1161
1162void
1163draw_parameters_square(ChannelSquareParams *params, bool sweep) {
1164 size_t x_offset = sweep ? 0 : 30;
1165
1166 // Duty cycle.
1167 {
1168 // Shape drawing.
1169 {
1170 size_t x = PARAMS_START_X + x_offset;
1171 size_t y = PARAMS_START_Y + PARAMS_H - 44;
1172
1173 size_t x0 = x + 2;
1174 size_t x1 = x0;
1175 size_t x2 = x0;
1176 size_t x3 = x0;
1177 size_t x4 = x0;
1178 size_t x5 = x0;
1179 size_t y0 = y + 14;
1180 size_t y1 = y + 2;
1181
1182 switch (params->duty_cycle) {
1183 case 0: {
1184 x1 += 4;
1185 x2 += 6;
1186 x3 += 13;
1187 x4 += 15;
1188 x5 += 20;
1189 } break;
1190 case 1: {
1191 x1 += 4;
1192 x2 += 7;
1193 x3 += 13;
1194 x4 += 16;
1195 x5 += 20;
1196 } break;
1197 case 2: {
1198 x1 += 3;
1199 x2 += 8;
1200 x3 += 12;
1201 x4 += 17;
1202 x5 += 20;
1203 } break;
1204 case 3: {
1205 x1 += 2;
1206 x2 += 9;
1207 x3 += 11;
1208 x4 += 18;
1209 x5 += 20;
1210 } break;
1211 }
1212 draw_line(x0, y0, x1, y0, COL_RED);
1213 draw_line(x1, y1, x1, y0, COL_RED);
1214 draw_line(x1, y1, x2, y1, COL_RED);
1215 draw_line(x2, y1, x2, y0, COL_RED);
1216 draw_line(x2, y0, x3, y0, COL_RED);
1217 draw_line(x3, y1, x3, y0, COL_RED);
1218 draw_line(x3, y1, x4, y1, COL_RED);
1219 draw_line(x4, y1, x4, y0, COL_RED);
1220 draw_line(x4, y0, x5, y0, COL_RED);
1221
1222 // Bounding box.
1223 draw_rect(x, y - 3, x + 24, y + 18, COL_RED);
1224 }
1225
1226 // Param box.
1227 {
1228 size_t x = PARAMS_START_X + x_offset;
1229 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1230 draw_line(x, y + 7, x + 2, y + 7, COL_FG);
1231 draw_line(x + 22, y + 7, x + 24, y + 7, COL_FG);
1232 draw_line(x, y + 8, x, y + 19, COL_FG);
1233 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1234 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1235 // txt_drawf_small("duty", x + 3, y + 3, 4, COL_FG);
1236
1237 switch (params->duty_cycle) {
1238 case 0: {
1239 txt_drawf("12", x + 6, y + 10, 6, COL_FG);
1240 } break;
1241 case 1: {
1242 txt_drawf("25", x + 6, y + 10, 6, COL_FG);
1243 } break;
1244 case 2: {
1245 txt_drawf("50", x + 6, y + 10, 6, COL_FG);
1246 } break;
1247 case 3: {
1248 txt_drawf("75", x + 6, y + 10, 6, COL_FG);
1249 } break;
1250 }
1251 }
1252 }
1253
1254 // Envelope.
1255 {
1256 // Env. drawing.
1257 {
1258 // Bounding box.
1259 {
1260 size_t x0 = PARAMS_START_X + 31 + x_offset;
1261 size_t y0 = PARAMS_START_Y + PARAMS_H - 47;
1262 size_t x1 = x0 + 79;
1263 size_t y1 = y0 + 21;
1264 draw_rect(x0, y0, x1, y1, COL_CYAN);
1265 }
1266
1267 size_t x = PARAMS_START_X + 42 + x_offset;
1268 size_t y = PARAMS_START_Y + PARAMS_H - 44;
1269 size_t x0 = x;
1270 size_t y0 = y + 15 - params->env_volume;
1271 size_t x1 = x + 8 * params->env_time;
1272 size_t y1 = params->env_direction == 0 ? y + 15 : y;
1273 size_t x2 = x + 8 * 7 + 1;
1274 size_t y2 = y1;
1275
1276 // Env.
1277 if (params->env_time == 0) {
1278 draw_line(x1, y0, x2, y0, COL_CYAN);
1279 } else {
1280 draw_line(x0, y0, x1, y1, COL_CYAN);
1281 draw_line(x1, y1, x2, y2, COL_CYAN);
1282 }
1283 }
1284
1285 // Env. volume.
1286 {
1287 size_t x = PARAMS_START_X + 31 + x_offset;
1288 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1289 draw_line(x, y + 7, x + 4, y + 7, COL_FG);
1290 draw_line(x + 20, y + 7, x + 24, y + 7, COL_FG);
1291 draw_line(x, y + 8, x, y + 19, COL_FG);
1292 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1293 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1294 // txt_drawf_small("vol", x + 5, y + 3, 4, COL_FG);
1295
1296 switch (params->env_volume) {
1297 case 0: {
1298 txt_drawf("0", x + 9, y + 10, 6, COL_FG);
1299 } break;
1300 case 1: {
1301 txt_drawf("6", x + 9, y + 10, 6, COL_FG);
1302 } break;
1303 case 2: {
1304 txt_drawf("13", x + 6, y + 10, 6, COL_FG);
1305 } break;
1306 case 3: {
1307 txt_drawf("20", x + 6, y + 10, 6, COL_FG);
1308 } break;
1309 case 4: {
1310 txt_drawf("26", x + 6, y + 10, 6, COL_FG);
1311 } break;
1312 case 5: {
1313 txt_drawf("33", x + 6, y + 10, 6, COL_FG);
1314 } break;
1315 case 6: {
1316 txt_drawf("40", x + 6, y + 10, 6, COL_FG);
1317 } break;
1318 case 7: {
1319 txt_drawf("46", x + 6, y + 10, 6, COL_FG);
1320 } break;
1321 case 8: {
1322 txt_drawf("53", x + 6, y + 10, 6, COL_FG);
1323 } break;
1324 case 9: {
1325 txt_drawf("60", x + 6, y + 10, 6, COL_FG);
1326 } break;
1327 case 10: {
1328 txt_drawf("66", x + 6, y + 10, 6, COL_FG);
1329 } break;
1330 case 11: {
1331 txt_drawf("73", x + 6, y + 10, 6, COL_FG);
1332 } break;
1333 case 12: {
1334 txt_drawf("80", x + 6, y + 10, 6, COL_FG);
1335 } break;
1336 case 13: {
1337 txt_drawf("86", x + 6, y + 10, 6, COL_FG);
1338 } break;
1339 case 14: {
1340 txt_drawf("93", x + 6, y + 10, 6, COL_FG);
1341 } break;
1342 case 15: {
1343 txt_drawf("100", x + 3, y + 10, 6, COL_FG);
1344 } break;
1345 }
1346 }
1347
1348 // Env. direction
1349 {
1350 size_t x = PARAMS_START_X + 59 + x_offset;
1351 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1352 draw_line(x, y + 7, x + 4, y + 7, COL_FG);
1353 draw_line(x + 20, y + 7, x + 24, y + 7, COL_FG);
1354 draw_line(x, y + 8, x, y + 19, COL_FG);
1355 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1356 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1357 // txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG);
1358
1359 char arr_up[2] = { 0x19, 0 };
1360 char arr_down[2] = { 0x18, 0 };
1361 switch (params->env_direction) {
1362 case 0: {
1363 txt_drawf(arr_up, x + 9, y + 11, 6, COL_FG);
1364 } break;
1365 case 1: {
1366 txt_drawf(arr_down, x + 9, y + 11, 6, COL_FG);
1367 } break;
1368 }
1369 }
1370
1371 // Env. time.
1372 {
1373 size_t x = PARAMS_START_X + 87 + x_offset;
1374 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1375 draw_line(x, y + 7, x + 2, y + 7, COL_FG);
1376 draw_line(x + 22, y + 7, x + 24, y + 7, COL_FG);
1377 draw_line(x, y + 8, x, y + 19, COL_FG);
1378 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1379 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1380 // txt_drawf_small("time", x + 3, y + 3, 4, COL_FG);
1381
1382 switch (params->env_time) {
1383 case 0: {
1384 txt_drawf("0", x + 9, y + 10, 6, COL_FG);
1385 } break;
1386 case 1: {
1387 txt_drawf("14", x + 6, y + 10, 6, COL_FG);
1388 } break;
1389 case 2: {
1390 txt_drawf("28", x + 6, y + 10, 6, COL_FG);
1391 } break;
1392 case 3: {
1393 txt_drawf("42", x + 6, y + 10, 6, COL_FG);
1394 } break;
1395 case 4: {
1396 txt_drawf("57", x + 6, y + 10, 6, COL_FG);
1397 } break;
1398 case 5: {
1399 txt_drawf("71", x + 6, y + 10, 6, COL_FG);
1400 } break;
1401 case 6: {
1402 txt_drawf("85", x + 6, y + 10, 6, COL_FG);
1403 } break;
1404 case 7: {
1405 txt_drawf("100", x + 3, y + 10, 6, COL_FG);
1406 } break;
1407 }
1408 }
1409 }
1410
1411 // Sweep number.
1412 if (sweep) {
1413 size_t x = PARAMS_START_X + 118;
1414 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1415 draw_line(x, y + 7, x + 4, y + 7, COL_FG);
1416 draw_line(x + 20, y + 7, x + 24, y + 7, COL_FG);
1417 draw_line(x, y + 8, x, y + 19, COL_FG);
1418 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1419 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1420 // txt_drawf_small("num", x + 5, y + 3, 4, COL_FG);
1421
1422 switch (params->sweep_number) {
1423 case 0: {
1424 txt_drawf("0", x + 9, y + 10, 6, COL_FG);
1425 } break;
1426 case 1: {
1427 txt_drawf("1", x + 9, y + 10, 6, COL_FG);
1428 } break;
1429 case 2: {
1430 txt_drawf("2", x + 9, y + 10, 6, COL_FG);
1431 } break;
1432 case 3: {
1433 txt_drawf("3", x + 9, y + 10, 6, COL_FG);
1434 } break;
1435 case 4: {
1436 txt_drawf("4", x + 9, y + 10, 6, COL_FG);
1437 } break;
1438 case 5: {
1439 txt_drawf("5", x + 9, y + 10, 6, COL_FG);
1440 } break;
1441 case 6: {
1442 txt_drawf("6", x + 9, y + 10, 6, COL_FG);
1443 } break;
1444 case 7: {
1445 txt_drawf("7", x + 9, y + 10, 6, COL_FG);
1446 } break;
1447 }
1448 }
1449
1450 // Sweep time.
1451 if (sweep) {
1452 size_t x = PARAMS_START_X + 146;
1453 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1454 draw_line(x, y + 7, x + 2, y + 7, COL_FG);
1455 draw_line(x + 22, y + 7, x + 24, y + 7, COL_FG);
1456 draw_line(x, y + 8, x, y + 19, COL_FG);
1457 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1458 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1459 // txt_drawf_small("time", x + 3, y + 3, 4, COL_FG);
1460
1461 switch (params->sweep_time) {
1462 case 0: {
1463 txt_drawf("0", x + 9, y + 10, 6, COL_FG);
1464 } break;
1465 case 1: {
1466 txt_drawf("1", x + 9, y + 10, 6, COL_FG);
1467 } break;
1468 case 2: {
1469 txt_drawf("2", x + 9, y + 10, 6, COL_FG);
1470 } break;
1471 case 3: {
1472 txt_drawf("3", x + 9, y + 10, 6, COL_FG);
1473 } break;
1474 case 4: {
1475 txt_drawf("4", x + 9, y + 10, 6, COL_FG);
1476 } break;
1477 case 5: {
1478 txt_drawf("5", x + 9, y + 10, 6, COL_FG);
1479 } break;
1480 case 6: {
1481 txt_drawf("6", x + 9, y + 10, 6, COL_FG);
1482 } break;
1483 case 7: {
1484 txt_drawf("7", x + 9, y + 10, 6, COL_FG);
1485 } break;
1486 }
1487 }
1488
1489 // Sweep direction.
1490 if (sweep) {
1491 size_t x = PARAMS_START_X + 132;
1492 size_t y = PARAMS_START_Y + PARAMS_H - 45;
1493 draw_line(x, y + 7, x + 4, y + 7, COL_FG);
1494 draw_line(x + 20, y + 7, x + 24, y + 7, COL_FG);
1495 draw_line(x, y + 8, x, y + 19, COL_FG);
1496 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1497 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1498 // txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG);
1499
1500 char arr_up[2] = { 0x19, 0 };
1501 char arr_down[2] = { 0x18, 0 };
1502 switch (params->sweep_direction) {
1503 case 0: {
1504 txt_drawf(arr_up, x + 9, y + 11, 6, COL_FG);
1505 } break;
1506 case 1: {
1507 txt_drawf(arr_down, x + 9, y + 11, 6, COL_FG);
1508 } break;
1509 }
1510 }
1511
1512 // Labels.
1513 {
1514 size_t x = PARAMS_START_X + x_offset;
1515 size_t y = PARAMS_START_Y + PARAMS_H - 45;
1516 // txt_drawf_small("shape", x + 1, y - 12, 4, COL_FG);
1517 // txt_drawf_small("envelope", x + 54, y - 12, 4, COL_FG);
1518 if (sweep) {
1519 // txt_drawf_small("sweep", x + 133, y - 12, 4, COL_FG);
1520 }
1521 }
1522}
1523
1524void
1525draw_parameters_noise(void) {
1526 size_t x_offset = 30;
1527 Pattern *pat = &patterns[pattern_selection_loc];
1528 ChannelNoiseParams *params = &pat->ch4.params[trig_selection_loc];
1529
1530 // Bit mode.
1531 {
1532 // Param box.
1533 {
1534 size_t x = PARAMS_START_X + x_offset;
1535 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1536 draw_line(x, y + 7, x + 2, y + 7, COL_FG);
1537 draw_line(x + 22, y + 7, x + 24, y + 7, COL_FG);
1538 draw_line(x, y + 8, x, y + 19, COL_FG);
1539 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1540 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1541 // txt_drawf_small("mode", x + 3, y + 3, 4, COL_FG);
1542
1543 switch (params->bit_mode) {
1544 case 0: {
1545 txt_drawf("A", x + 9, y + 10, 6, COL_FG);
1546 } break;
1547 case 1: {
1548 txt_drawf("B", x + 9, y + 10, 6, COL_FG);
1549 } break;
1550 }
1551 }
1552 }
1553
1554 // Envelope.
1555 {
1556 // Env. drawing.
1557 {
1558 // Bounding box.
1559 {
1560 size_t x0 = PARAMS_START_X + 31 + x_offset;
1561 size_t y0 = PARAMS_START_Y + PARAMS_H - 47;
1562 size_t x1 = x0 + 79;
1563 size_t y1 = y0 + 21;
1564 draw_rect(x0, y0, x1, y1, COL_CYAN);
1565 }
1566
1567 size_t x = PARAMS_START_X + 42 + x_offset;
1568 size_t y = PARAMS_START_Y + PARAMS_H - 44;
1569 size_t x0 = x;
1570 size_t y0 = y + 15 - params->env_volume;
1571 size_t x1 = x + 8 * params->env_time;
1572 size_t y1 = params->env_direction == 0 ? y + 15 : y;
1573 size_t x2 = x + 8 * 7 + 1;
1574 size_t y2 = y1;
1575
1576 // Env.
1577 if (params->env_time == 0) {
1578 draw_line(x1, y0, x2, y0, COL_CYAN);
1579 } else {
1580 draw_line(x0, y0, x1, y1, COL_CYAN);
1581 draw_line(x1, y1, x2, y2, COL_CYAN);
1582 }
1583 }
1584
1585 // Env. volume.
1586 {
1587 size_t x = PARAMS_START_X + 31 + x_offset;
1588 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1589 draw_line(x, y + 7, x + 4, y + 7, COL_FG);
1590 draw_line(x + 20, y + 7, x + 24, y + 7, COL_FG);
1591 draw_line(x, y + 8, x, y + 19, COL_FG);
1592 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1593 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1594 // txt_drawf_small("vol", x + 5, y + 3, 4, COL_FG);
1595
1596 switch (params->env_volume) {
1597 case 0: {
1598 txt_drawf("0", x + 9, y + 10, 6, COL_FG);
1599 } break;
1600 case 1: {
1601 txt_drawf("6", x + 9, y + 10, 6, COL_FG);
1602 } break;
1603 case 2: {
1604 txt_drawf("13", x + 6, y + 10, 6, COL_FG);
1605 } break;
1606 case 3: {
1607 txt_drawf("20", x + 6, y + 10, 6, COL_FG);
1608 } break;
1609 case 4: {
1610 txt_drawf("26", x + 6, y + 10, 6, COL_FG);
1611 } break;
1612 case 5: {
1613 txt_drawf("33", x + 6, y + 10, 6, COL_FG);
1614 } break;
1615 case 6: {
1616 txt_drawf("40", x + 6, y + 10, 6, COL_FG);
1617 } break;
1618 case 7: {
1619 txt_drawf("46", x + 6, y + 10, 6, COL_FG);
1620 } break;
1621 case 8: {
1622 txt_drawf("53", x + 6, y + 10, 6, COL_FG);
1623 } break;
1624 case 9: {
1625 txt_drawf("60", x + 6, y + 10, 6, COL_FG);
1626 } break;
1627 case 10: {
1628 txt_drawf("66", x + 6, y + 10, 6, COL_FG);
1629 } break;
1630 case 11: {
1631 txt_drawf("73", x + 6, y + 10, 6, COL_FG);
1632 } break;
1633 case 12: {
1634 txt_drawf("80", x + 6, y + 10, 6, COL_FG);
1635 } break;
1636 case 13: {
1637 txt_drawf("86", x + 6, y + 10, 6, COL_FG);
1638 } break;
1639 case 14: {
1640 txt_drawf("93", x + 6, y + 10, 6, COL_FG);
1641 } break;
1642 case 15: {
1643 txt_drawf("100", x + 3, y + 10, 6, COL_FG);
1644 } break;
1645 }
1646 }
1647
1648 // Env. direction
1649 {
1650 size_t x = PARAMS_START_X + 59 + x_offset;
1651 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1652 draw_line(x, y + 7, x + 4, y + 7, COL_FG);
1653 draw_line(x + 20, y + 7, x + 24, y + 7, COL_FG);
1654 draw_line(x, y + 8, x, y + 19, COL_FG);
1655 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1656 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1657 // txt_drawf_small("dir", x + 5, y + 3, 4, COL_FG);
1658
1659 char arr_up[2] = { 0x19, 0 };
1660 char arr_down[2] = { 0x18, 0 };
1661 switch (params->env_direction) {
1662 case 0: {
1663 txt_drawf(arr_up, x + 9, y + 11, 6, COL_FG);
1664 } break;
1665 case 1: {
1666 txt_drawf(arr_down, x + 9, y + 11, 6, COL_FG);
1667 } break;
1668 }
1669 }
1670
1671 // Env. time.
1672 {
1673 size_t x = PARAMS_START_X + 87 + x_offset;
1674 size_t y = PARAMS_START_Y + PARAMS_H - 25;
1675 draw_line(x, y + 7, x + 2, y + 7, COL_FG);
1676 draw_line(x + 22, y + 7, x + 24, y + 7, COL_FG);
1677 draw_line(x, y + 8, x, y + 19, COL_FG);
1678 draw_line(x + 24, y + 8, x + 24, y + 19, COL_FG);
1679 draw_line(x, y + 20, x + 24, y + 20, COL_FG);
1680 // txt_drawf_small("time", x + 3, y + 3, 4, COL_FG);
1681
1682 switch (params->env_time) {
1683 case 0: {
1684 txt_drawf("0", x + 9, y + 10, 6, COL_FG);
1685 } break;
1686 case 1: {
1687 txt_drawf("14", x + 6, y + 10, 6, COL_FG);
1688 } break;
1689 case 2: {
1690 txt_drawf("28", x + 6, y + 10, 6, COL_FG);
1691 } break;
1692 case 3: {
1693 txt_drawf("42", x + 6, y + 10, 6, COL_FG);
1694 } break;
1695 case 4: {
1696 txt_drawf("57", x + 6, y + 10, 6, COL_FG);
1697 } break;
1698 case 5: {
1699 txt_drawf("71", x + 6, y + 10, 6, COL_FG);
1700 } break;
1701 case 6: {
1702 txt_drawf("85", x + 6, y + 10, 6, COL_FG);
1703 } break;
1704 case 7: {
1705 txt_drawf("100", x + 3, y + 10, 6, COL_FG);
1706 } break;
1707 }
1708 }
1709 }
1710
1711 // Labels.
1712 {
1713 size_t x = PARAMS_START_X + x_offset;
1714 size_t y = PARAMS_START_Y + PARAMS_H - 45;
1715 // txt_drawf_small("envelope", x + 54, y - 12, 4, COL_FG);
1716 }
1717}
1718
1719void
1720draw_parameters(void) {
1721 clear_parameters();
1722 Pattern *pat = &patterns[pattern_selection_loc];
1723 switch (channel_selection_loc) {
1724 case 0: {
1725 draw_parameters_square(&pat->ch1.params[trig_selection_loc], true);
1726 } break;
1727 case 1: {
1728 draw_parameters_square(&pat->ch2.params[trig_selection_loc], false);
1729 } break;
1730 case 2: {
1731 draw_parameters_wave();
1732 } break;
1733 case 3: {
1734 draw_parameters_noise();
1735 } break;
1736 }
1737}
1738 11
1739void 12void
1740irq_timer(void) { 13irq_timer(void) {
@@ -1901,20 +174,6 @@ get_current_trig(void) {
1901 return NULL; 174 return NULL;
1902} 175}
1903 176
1904// Input handling works using a FSM. The input handler is switched to whichever
1905// function controls each section. For example, channel selection or trigger
1906// selection.
1907void (*input_handler)(void);
1908
1909void handle_trigger_selection(void);
1910void handle_channel_selection(void);
1911void handle_pattern_selection(void);
1912void handle_param_selection_sq1(void);
1913void handle_param_selection_sq2(void);
1914void handle_param_selection_wave(void);
1915void handle_param_selection_noise(void);
1916void handle_right_col_selection(void);
1917
1918void 177void
1919handle_channel_selection(void) { 178handle_channel_selection(void) {
1920 if (key_tap(KEY_B)) { 179 if (key_tap(KEY_B)) {
@@ -2624,302 +883,6 @@ handle_trigger_selection(void) {
2624} 883}
2625 884
2626void 885void
2627clipboard_paste(void) {
2628 Pattern *pat_dst = &patterns[pattern_selection_loc];
2629 Pattern *pat_src = &patterns[clipboard.src_pat];
2630
2631 if (input_handler == handle_trigger_selection) {
2632 if (clipboard.type == CLIP_TRIG) {
2633 // Copy notes or parameters when applicable.
2634 switch (clipboard.src_chan) {
2635 case 0: {
2636 switch (channel_selection_loc) {
2637 case 0: {
2638 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
2639 pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
2640 } break;
2641 case 1: {
2642 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
2643 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
2644 } break;
2645 case 2: {
2646 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
2647 } break;
2648 case 3: {
2649 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch1.notes[clipboard.src_trig];
2650 } break;
2651 }
2652 } break;
2653 case 1: {
2654 switch (channel_selection_loc) {
2655 case 0: {
2656 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
2657 pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
2658 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
2659 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
2660 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
2661 } break;
2662 case 1: {
2663 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
2664 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
2665 } break;
2666 case 2: {
2667 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
2668 } break;
2669 case 3: {
2670 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch2.notes[clipboard.src_trig];
2671 } break;
2672 }
2673 } break;
2674 case 2: {
2675 switch (channel_selection_loc) {
2676 case 0: {
2677 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
2678 } break;
2679 case 1: {
2680 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
2681 } break;
2682 case 2: {
2683 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
2684 pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
2685 } break;
2686 case 3: {
2687 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch3.notes[clipboard.src_trig];
2688 } break;
2689 }
2690 } break;
2691 case 3: {
2692 switch (channel_selection_loc) {
2693 case 0: {
2694 pat_dst->ch1.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
2695 } break;
2696 case 1: {
2697 pat_dst->ch2.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
2698 } break;
2699 case 2: {
2700 pat_dst->ch3.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
2701 } break;
2702 case 3: {
2703 pat_dst->ch4.notes[trig_selection_loc] = pat_src->ch4.notes[clipboard.src_trig];
2704 pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig];
2705 } break;
2706 }
2707 } break;
2708 }
2709 }
2710 // Only paste the params for the respective trigger.
2711 if (clipboard.type == CLIP_PARAM_CH1) {
2712 switch (channel_selection_loc) {
2713 case 0: {
2714 pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
2715 } break;
2716 case 1: {
2717 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
2718 } break;
2719 }
2720 }
2721 if (clipboard.type == CLIP_PARAM_CH2) {
2722 switch (channel_selection_loc) {
2723 case 0: {
2724 pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
2725 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
2726 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
2727 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
2728 } break;
2729 case 1: {
2730 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
2731 } break;
2732 }
2733 }
2734 if (clipboard.type == CLIP_PARAM_CH3 && channel_selection_loc == clipboard.src_chan) {
2735 pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
2736 }
2737 if (clipboard.type == CLIP_PARAM_CH4 && channel_selection_loc == clipboard.src_chan) {
2738 pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig];
2739 }
2740 draw_triggers();
2741 draw_parameters();
2742 } else if (input_handler == handle_param_selection_sq1 && clipboard.type == CLIP_PARAM_CH1) {
2743 pat_dst->ch1.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
2744 draw_parameters();
2745 } else if (input_handler == handle_param_selection_sq1 && clipboard.type == CLIP_PARAM_CH2) {
2746 pat_dst->ch1.params[trig_selection_loc].env_volume = pat_src->ch2.params[clipboard.src_trig].env_volume;
2747 pat_dst->ch1.params[trig_selection_loc].env_time = pat_src->ch2.params[clipboard.src_trig].env_time;
2748 pat_dst->ch1.params[trig_selection_loc].env_direction = pat_src->ch2.params[clipboard.src_trig].env_direction;
2749 pat_dst->ch1.params[trig_selection_loc].duty_cycle = pat_src->ch2.params[clipboard.src_trig].duty_cycle;
2750 draw_parameters();
2751 } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH2) {
2752 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch2.params[clipboard.src_trig];
2753 draw_parameters();
2754 } else if (input_handler == handle_param_selection_sq2 && clipboard.type == CLIP_PARAM_CH1) {
2755 pat_dst->ch2.params[trig_selection_loc] = pat_src->ch1.params[clipboard.src_trig];
2756 draw_parameters();
2757 } else if (input_handler == handle_param_selection_wave && clipboard.type == CLIP_PARAM_CH3) {
2758 pat_dst->ch3.params[trig_selection_loc] = pat_src->ch3.params[clipboard.src_trig];
2759 draw_parameters();
2760 } else if (input_handler == handle_param_selection_noise && clipboard.type == CLIP_PARAM_CH4) {
2761 pat_dst->ch4.params[trig_selection_loc] = pat_src->ch4.params[clipboard.src_trig];
2762 draw_parameters();
2763 } else if (input_handler == handle_channel_selection && clipboard.type == CLIP_CHANNEL) {
2764 // Copy notes from a different channel OR notes and parameters
2765 // from a different pattern.
2766 if (clipboard.src_chan == channel_selection_loc) {
2767 switch (clipboard.src_chan) {
2768 case 0: { pat_dst->ch1 = pat_src->ch1; } break;
2769 case 1: { pat_dst->ch2 = pat_src->ch2; } break;
2770 case 2: { pat_dst->ch3 = pat_src->ch3; } break;
2771 case 3: { pat_dst->ch4 = pat_src->ch4; } break;
2772 }
2773 } else {
2774 switch (clipboard.src_chan) {
2775 case 0: {
2776 switch (channel_selection_loc) {
2777 case 0: {
2778 for (size_t i = 0; i < 16; i++) {
2779 pat_dst->ch1.notes[i] = pat_src->ch1.notes[i];
2780 }
2781 } break;
2782 case 1: {
2783 for (size_t i = 0; i < 16; i++) {
2784 pat_dst->ch2.notes[i] = pat_src->ch1.notes[i];
2785 }
2786 } break;
2787 case 2: {
2788 for (size_t i = 0; i < 16; i++) {
2789 pat_dst->ch3.notes[i] = pat_src->ch1.notes[i];
2790 }
2791 } break;
2792 case 3: {
2793 for (size_t i = 0; i < 16; i++) {
2794 pat_dst->ch4.notes[i] = pat_src->ch1.notes[i];
2795 }
2796 } break;
2797 }
2798 } break;
2799 case 1: {
2800 switch (channel_selection_loc) {
2801 case 0: {
2802 for (size_t i = 0; i < 16; i++) {
2803 pat_dst->ch1.notes[i] = pat_src->ch2.notes[i];
2804 }
2805 } break;
2806 case 1: {
2807 for (size_t i = 0; i < 16; i++) {
2808 pat_dst->ch2.notes[i] = pat_src->ch2.notes[i];
2809 }
2810 } break;
2811 case 2: {
2812 for (size_t i = 0; i < 16; i++) {
2813 pat_dst->ch3.notes[i] = pat_src->ch2.notes[i];
2814 }
2815 } break;
2816 case 3: {
2817 for (size_t i = 0; i < 16; i++) {
2818 pat_dst->ch4.notes[i] = pat_src->ch2.notes[i];
2819 }
2820 } break;
2821 }
2822 } break;
2823 case 2: {
2824 switch (channel_selection_loc) {
2825 case 0: {
2826 for (size_t i = 0; i < 16; i++) {
2827 pat_dst->ch1.notes[i] = pat_src->ch3.notes[i];
2828 }
2829 } break;
2830 case 1: {
2831 for (size_t i = 0; i < 16; i++) {
2832 pat_dst->ch2.notes[i] = pat_src->ch3.notes[i];
2833 }
2834 } break;
2835 case 2: {
2836 for (size_t i = 0; i < 16; i++) {
2837 pat_dst->ch3.notes[i] = pat_src->ch3.notes[i];
2838 }
2839 } break;
2840 case 3: {
2841 for (size_t i = 0; i < 16; i++) {
2842 pat_dst->ch4.notes[i] = pat_src->ch3.notes[i];
2843 }
2844 } break;
2845 }
2846 } break;
2847 case 3: {
2848 switch (channel_selection_loc) {
2849 case 0: {
2850 for (size_t i = 0; i < 16; i++) {
2851 pat_dst->ch1.notes[i] = pat_src->ch4.notes[i];
2852 }
2853 } break;
2854 case 1: {
2855 for (size_t i = 0; i < 16; i++) {
2856 pat_dst->ch2.notes[i] = pat_src->ch4.notes[i];
2857 }
2858 } break;
2859 case 2: {
2860 for (size_t i = 0; i < 16; i++) {
2861 pat_dst->ch3.notes[i] = pat_src->ch4.notes[i];
2862 }
2863 } break;
2864 case 3: {
2865 for (size_t i = 0; i < 16; i++) {
2866 pat_dst->ch4.notes[i] = pat_src->ch4.notes[i];
2867 }
2868 } break;
2869 }
2870 } break;
2871 }
2872 }
2873 draw_channels();
2874 draw_triggers();
2875 } else if (input_handler == handle_pattern_selection && clipboard.type == CLIP_PATTERN) {
2876 // Copy an entire pattern.
2877 if (pattern_selection_loc != clipboard.src_pat) {
2878 *pat_dst = *pat_src;
2879 draw_channels();
2880 draw_triggers();
2881 }
2882 }
2883}
2884
2885void
2886clipboard_copy(void) {
2887 if (input_handler == handle_trigger_selection) {
2888 clipboard.type = CLIP_TRIG;
2889 clipboard.src_pat = pattern_selection_loc;
2890 clipboard.src_chan = channel_selection_loc;
2891 clipboard.src_trig = trig_selection_loc;
2892 } else if (input_handler == handle_param_selection_sq1) {
2893 clipboard.type = CLIP_PARAM_CH1;
2894 clipboard.src_pat = pattern_selection_loc;
2895 clipboard.src_chan = channel_selection_loc;
2896 clipboard.src_trig = trig_selection_loc;
2897 } else if (input_handler == handle_param_selection_sq2) {
2898 clipboard.type = CLIP_PARAM_CH2;
2899 clipboard.src_pat = pattern_selection_loc;
2900 clipboard.src_chan = channel_selection_loc;
2901 clipboard.src_trig = trig_selection_loc;
2902 } else if (input_handler == handle_param_selection_wave) {
2903 clipboard.type = CLIP_PARAM_CH3;
2904 clipboard.src_pat = pattern_selection_loc;
2905 clipboard.src_chan = channel_selection_loc;
2906 clipboard.src_trig = trig_selection_loc;
2907 } else if (input_handler == handle_param_selection_noise) {
2908 clipboard.type = CLIP_PARAM_CH4;
2909 clipboard.src_pat = pattern_selection_loc;
2910 clipboard.src_chan = channel_selection_loc;
2911 clipboard.src_trig = trig_selection_loc;
2912 } else if (input_handler == handle_channel_selection) {
2913 clipboard.type = CLIP_CHANNEL;
2914 clipboard.src_pat = pattern_selection_loc;
2915 clipboard.src_chan = channel_selection_loc;
2916 } else if (input_handler == handle_pattern_selection) {
2917 clipboard.type = CLIP_PATTERN;
2918 clipboard.src_pat = pattern_selection_loc;
2919 }
2920}
2921
2922void
2923handle_sequencer_input(void) { 886handle_sequencer_input(void) {
2924 if (key_tap(KEY_START)) { 887 if (key_tap(KEY_START)) {
2925 // Stop the sequencer or start playing from the beginning. 888 // Stop the sequencer or start playing from the beginning.
@@ -2944,17 +907,7 @@ handle_sequencer_input(void) {
2944} 907}
2945 908
2946void 909void
2947load_assets(void) {
2948 unpack_tiles(note_names, ASSETS_NOTE_NAMES, N_TILES_NOTE_NAMES);
2949 unpack_tiles(channel_buttons, ASSETS_CHANNEL_BUTTONS, N_TILES_CHAN_BTSN);
2950 unpack_tiles(default_wave_buttons, ASSETS_DEFAULT_WAVES, N_TILES_WAVE_BTNS);
2951}
2952
2953void
2954sequencer_init(void) { 910sequencer_init(void) {
2955 // Unpack non-sprite tiles directly on the VRAM.
2956 load_assets();
2957
2958 // Load the previous bank from SRAM or initialize it if needed. 911 // Load the previous bank from SRAM or initialize it if needed.
2959 sram_read(&metadata, 0, sizeof(Metadata)); 912 sram_read(&metadata, 0, sizeof(Metadata));
2960 if (metadata.magic != 0xbadd10de) { 913 if (metadata.magic != 0xbadd10de) {
@@ -2972,28 +925,8 @@ sequencer_init(void) {
2972 load_bank(metadata.current_bank); 925 load_bank(metadata.current_bank);
2973 } 926 }
2974 927
2975 // Initialize background objects and sprites.
2976 draw_triggers();
2977 draw_channels();
2978 draw_piano();
2979 TriggerNote *trig = get_current_trig();
2980 draw_note(trig->note, COL_NOTE_PRESSED);
2981
2982 // Draw screen border frame.
2983 draw_rect(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 1);
2984
2985 // Initialize input handler. 928 // Initialize input handler.
2986 input_handler = handle_trigger_selection; 929 input_handler = handle_trigger_selection;
2987 draw_trig_cursor(trig_selection_loc, COL_CURSOR);
2988 draw_channel_cursor(channel_selection_loc, COL_GREY);
2989 draw_pattern_cursor(pattern_selection_loc, COL_GREY);
2990 draw_current_step(COL_RED);
2991 draw_parameters();
2992 draw_bpm();
2993 draw_play();
2994 draw_stop();
2995 draw_pattern_buttons();
2996 draw_bank_buttons();
2997 930
2998 // Initialize sound system. 931 // Initialize sound system.
2999 SOUND_STATUS = SOUND_ENABLE; 932 SOUND_STATUS = SOUND_ENABLE;