gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/examples/gb/sound/sound.c
1 #include <gb/gb.h>
2 #include <gbdk/console.h>
3 #include <stdint.h>
4 #include <stdio.h>
5
6
7 inline uint8_t translate_envelope(uint8_t value) {
8 #ifdef MEGADUCK
9 // Mega Duck has nybbles swapped for NR12, NR22, NR42 audio envelope registers
10 return ((uint8_t)(value << 4) | (uint8_t)(value >> 4));
11 #else
12 return value;
13 #endif
14 }
15
16 inline uint8_t translate_frequency(uint8_t value) {
17 #ifdef MEGADUCK
18 // Mega Duck has nybbles swapped for NR43 frequency & randomness audio register
19 return ((uint8_t)(value << 4) | (uint8_t)(value >> 4));
20 #else
21 return value;
22 #endif
23 }
24
25 inline uint8_t translate_volume(uint8_t value) {
26 #ifdef MEGADUCK
27 // Mega Duck has bit values changed for NR32 volume register
28 // To translate the volume: New Volume = ((0x00 - Volume) & 0x60)
29 // GB: Bits:6..5 : 00 = mute, 01 = 100%, 10 = 50%, 11 = 25%
30 // MD: Bits:6..5 : 00 = mute, 11 = 100%, 10 = 50%, 01 = 25%
31 return ((~(uint8_t)value) + 1u) & (uint8_t)0x60u;
32 #else
33 return value;
34 #endif
35 }
36
37
38 #define ARROW_CHAR '>'
39 #define SPACE_CHAR ' '
40
41 #define ARROW_X 0
42 #define VAL_X 15
43 #define TITLE_Y 0
44 #define FIRST_X (ARROW_X+1)
45 #define FIRST_Y (TITLE_Y+2)
46
47 #define PLAY 0x20
48 #define FREQUENCY 0x21
49
50 #define MIN(x,y) ((x) > (y) ? (y) : (x))
51 #define MAX(x,y) ((x) < (y) ? (y) : (x))
52
53 #define NB_MODES 5
54
55 #define UNSIGNED 0
56
57 uint8_t previous_keys = 0;
58 int8_t keys = 0;
59 #define UPDATE_KEYS() previous_keys = keys; keys = joypad()
60 #define KEY_PRESSED(K) (keys & (K))
61 #define KEY_TICKED(K) ((keys & (K)) && !(previous_keys & (K)))
62
63 void show_register_channel(uint8_t mode);
64
65 void clss(void) {
66 uint8_t i = 0;
67 for(i = 0; i < 18; ++i) {
68 gotoxy(0, i);
69 printf(" ");
70 }
71 }
72
73 void print(const char* str) {
74 printf("%s", str);
75 }
76
77 const char hex[] = "0123456789ABCDEF";
78 void printn(uint16_t n, uint8_t base, uint8_t sign) {
79 (void) sign;
80 if(base == 16u) {
81 printf("%c", hex[0x000Fu & (n >> 4u)]);
82 printf("%c", hex[0x000Fu & (n)]);
83 } else {
84 printf("%d", n);
85 }
86 }
87
88
89 void println(uint16_t n, uint8_t base, uint8_t sign) {
90 printn(n, base, sign);
91 printf("\n");
92 }
93
94 enum notes {
95 C0, Cd0, D0, Dd0, E0, F0, Fd0, G0, Gd0, A0, Ad0, B0,
96 C1, Cd1, D1, Dd1, E1, F1, Fd1, G1, Gd1, A1, Ad1, B1,
97 C2, Cd2, D2, Dd2, E2, F2, Fd2, G2, Gd2, A2, Ad2, B2,
98 C3, Cd3, D3, Dd3, E3, F3, Fd3, G3, Gd3, A3, Ad3, B3,
99 C4, Cd4, D4, Dd4, E4, F4, Fd4, G4, Gd4, A4, Ad4, B4,
100 C5, Cd5, D5, Dd5, E5, F5, Fd5, G5, Gd5, A5, Ad5, B5,
101 SILENCE, END
102 };
103
104 const uint16_t frequencies[] = {
105 44, 156, 262, 363, 457, 547, 631, 710, 786, 854, 923, 986,
106 1046, 1102, 1155, 1205, 1253, 1297, 1339, 1379, 1417, 1452, 1486, 1517,
107 1546, 1575, 1602, 1627, 1650, 1673, 1694, 1714, 1732, 1750, 1767, 1783,
108 1798, 1812, 1825, 1837, 1849, 1860, 1871, 1881, 1890, 1899, 1907, 1915,
109 1923, 1930, 1936, 1943, 1949, 1954, 1959, 1964, 1969, 1974, 1978, 1982,
110 1985, 1988, 1992, 1995, 1998, 2001, 2004, 2006, 2009, 2011, 2013, 2015
111 };
112
113 const uint8_t music[] = {
114 C3, C3, G3, G3, A3, A3, G3, SILENCE,
115 F3, F3, E3, E3, D3, D3, C3, SILENCE,
116 G3, G3, F3, F3, E3, E3, D3, D3,
117 G3, G3, F3, F3, E3, E3, D3, D3,
118 C3, C3, G3, G3, A3, A3, G3, SILENCE,
119 F3, F3, E3, E3, D3, D3, C3, SILENCE,
120 END
121 };
122
123 struct Params {
124 char *name;
125 uint16_t max;
126 };
127
128 const struct Params params_0[] = {
129 { "Main Controls" , 0 },
130 { "All On/Off" , 1 },
131 { "Vin->SO1" , 1 },
132 { "Vin->SO2" , 1 },
133 { "SO1 Volume" , 7 },
134 { "SO2 Volume" , 7 },
135 { NULL , 0 }
136 };
137
138 const struct Params params_1[] = {
139 { "Sound Mode #1" , 0 },
140 { "Swp Time" , 7 },
141 { "Swp Mode" , 1 },
142 { "Swp Shifts" , 7 },
143 { "Pat Duty" , 3 },
144 { "Sound Len" , 63 },
145 { "Env Init" , 15 },
146 { "Env Mode" , 1 },
147 { "Env Nb Swp" , 7 },
148 { "Frequency" , 2047 },
149 { "Cons Sel" , 1 },
150 { "Out to SO1" , 1 },
151 { "Out to SO2" , 1 },
152 { "On/Off" , 1 },
153 { NULL , 0 }
154 };
155
156 const struct Params params_2[] = {
157 { "Sound Mode #2" , 0 },
158 { "Pat Duty" , 3 },
159 { "Sound Len" , 63 },
160 { "Env Init" , 15 },
161 { "Env Mode" , 1 },
162 { "Env Nb Step" , 7 },
163 { "Frequency" , 2047 },
164 { "Cons Sel" , 1 },
165 { "Out to SO1" , 1 },
166 { "Out to SO2" , 1 },
167 { "On/Off" , 1 },
168 { NULL , 0 }
169 };
170
171 const struct Params params_3[] = {
172 { "Sound Mode #3" , 0 },
173 { "Sound On/Off" , 1 },
174 { "Sound Len" , 255 },
175 { "Sel Out Level" , 3 },
176 { "Frequency" , 2047 },
177 { "Cons Sel" , 1 },
178 { "Out to SO1" , 1 },
179 { "Out to SO2" , 1 },
180 { "On/Off" , 1 },
181 { NULL , 0 }
182 };
183
184 const struct Params params_4[] = {
185 { "Sound Mode #4" , 0 },
186 { "Sound Len" , 63 },
187 { "Env Init" , 15 },
188 { "Env Mode" , 1 },
189 { "Env Nb Step" , 7 },
190 { "Poly Cnt Freq" , 15 },
191 { "Poly Cnt Step" , 1 },
192 { "Poly Cnt Div" , 7 },
193 { "Cons Sel" , 1 },
194 { "Out to SO1" , 1 },
195 { "Out to SO2" , 1 },
196 { "On/Off" , 1 },
197 { NULL , 0 }
198 };
199
200 const struct Params *params_array[] = {
201 params_0,
202 params_1,
203 params_2,
204 params_3,
205 params_4,
206 };
207
208 const struct Params *params;
209
210 struct SoundReg {
211 struct {
212 //NR10 0xFF10
213 uint16_t sweepShifts ;//: 3;
214 uint16_t sweepMode ;//: 1;
215 uint16_t sweepTime ;//: 3;
216 uint16_t unused_1 ;//: 1;
217
218 //NR11 0xFF11
219 uint16_t soundLength ;//: 6;
220 uint16_t patternDuty ;//: 2;
221
222 //NR12 0xFF12
223 uint16_t envNbSweep ;//: 3;
224 uint16_t envMode ;//: 1;
225 uint16_t envInitialValue ;//: 4;
226
227 //NR13 0xFF13
228 uint16_t frequencyLow;
229
230 //NR14 0xFF14
231 uint16_t frequencyHigh ;//: 3;
232 uint16_t unused_2 ;//: 3;
233 uint16_t counter_ConsSel ;//: 1;
234 uint16_t restart ;//: 1;
235 } mode1;
236 struct {
237 //NR20 0xFF15
238 uint16_t unused_1;
239
240 //NR21 0xFF16
241 uint16_t soundLength ;//: 6;
242 uint16_t patternDuty ;//: 2;
243
244 //NR22 0xFF17
245 uint16_t envNbStep ;//: 3;
246 uint16_t envMode ;//: 1;
247 uint16_t envInitialValue ;//: 4;
248
249 //NR23 0xFF18
250 uint16_t frequencyLow;
251
252 //NR24 0xFF19
253 uint16_t frequencyHigh ;//: 3;
254 uint16_t unused_2 ;//: 3;
255 uint16_t counter_ConsSel ;//: 1;
256 uint16_t restart ;//: 1;
257 } mode2;
258 struct {
259 //NR30 0xFF1A
260 uint16_t unused_1 ;//: 7;
261 uint16_t on_Off ;//: 1;
262
263 //NR31 0xFF1B
264 uint16_t soundLength;
265
266 //NR32 0xFF1C
267 uint16_t unused_2 ;//: 5;
268 uint16_t selOutputLevel ;//: 2;
269 uint16_t unused_3 ;//: 1;
270
271 //NR33 0xFF1D
272 uint16_t frequencyLow;
273
274 //NR34 0xFF1E
275 uint16_t frequencyHigh ;//: 3;
276 uint16_t unused_4 ;//: 3;
277 uint16_t counter_ConsSel ;//: 1;
278 uint16_t restart ;//: 1;
279 } mode3;
280 struct {
281 //NR40 0xFF1F
282 uint16_t unused_1;
283
284 //NR41 0xFF20
285 uint16_t soundLength ;//: 6;
286 uint16_t unused_2 ;//: 2;
287
288 //NR42 0xFF21
289 uint16_t envNbStep ;//: 3;
290 uint16_t envMode ;//: 1;
291 uint16_t envInitialValue ;//: 4;
292
293 //NR43 0xFF22
294 uint16_t polyCounterDiv ;//: 3;
295 uint16_t polyCounterStep ;//: 1;
296 uint16_t polyCounterFreq ;//: 4;
297
298 //NR44 0xFF23
299 uint16_t unused_3 ;//: 6;
300 uint16_t counter_ConsSel ;//: 1;
301 uint16_t restart ;//: 1;
302 } mode4;
303 struct {
304 // NR50 0xFF24
305 uint16_t SO1_OutputLevel ;//: 3;
306 uint16_t Vin_SO1 ;//: 1;
307 uint16_t SO2_OutputLevel ;//: 3;
308 uint16_t Vin_SO2 ;//: 1;
309
310 // NR51 0xFF25
311 uint16_t Sound1_To_SO1 ;//: 1;
312 uint16_t Sound2_To_SO1 ;//: 1;
313 uint16_t Sound3_To_SO1 ;//: 1;
314 uint16_t Sound4_To_SO1 ;//: 1;
315 uint16_t Sound1_To_SO2 ;//: 1;
316 uint16_t Sound2_To_SO2 ;//: 1;
317 uint16_t Sound3_To_SO2 ;//: 1;
318 uint16_t Sound4_To_SO2 ;//: 1;
319
320 // NR52 0xFF26
321 uint16_t Sound1_On_Off ;//: 1;
322 uint16_t Sound2_On_Off ;//: 1;
323 uint16_t Sound3_On_Off ;//: 1;
324 uint16_t Sound4_On_Off ;//: 1;
325 uint16_t unused_1 ;//: 3;
326 uint16_t global_On_Off ;//: 1;
327 } control;
328 };
329
330 struct SoundReg *soundReg;
331
332 struct SoundReg s = {
333 { 0u, 0u, 0u, 0u,
334 1, 2,
335 3, 0, 4,
336 0x73U,
337 6, 0, 0, 0 },
338 { 0,
339 1, 2,
340 4, 0, 8,
341 0xD7U,
342 6, 0, 0, 0 },
343 { 0, 1,
344 0,
345 0, 3, 0,
346 0xD6U,
347 6, 0, 1, 0 },
348 { 0,
349 58, 0,
350 1, 0, 10,
351 0, 0, 0,
352 0, 1, 0 },
353 { 7, 0, 7, 0,
354 1, 1, 1, 1, 1, 1, 1, 1,
355 0, 0, 0, 0, 0, 1 }
356 };
357
358 uint8_t NR10(void) {
359 return soundReg->mode1.sweepShifts | (soundReg->mode1.sweepMode << 3) | (soundReg->mode1.sweepTime << 4);
360 }
361
362 uint8_t NR11(void) {
363 return soundReg->mode1.soundLength | (soundReg->mode1.patternDuty << 6);
364 }
365
366 uint8_t NR12(void) {
367 return soundReg->mode1.envNbSweep | (soundReg->mode1.envMode << 3) | (soundReg->mode1.envInitialValue << 4);
368 }
369
370 uint8_t NR13(void) {
371 return soundReg->mode1.frequencyLow;
372 }
373
374 uint8_t NR14(void) {
375 return soundReg->mode1.frequencyHigh | (soundReg->mode1.counter_ConsSel << 6) | (soundReg->mode1.restart << 7);
376 }
377
378 //--------------------------
379 uint8_t NR21(void) {
380 return soundReg->mode2.soundLength | (soundReg->mode2.patternDuty << 6);
381 }
382
383 uint8_t NR22(void) {
384 return soundReg->mode2.envNbStep | (soundReg->mode2.envMode << 3) | (soundReg->mode2.envInitialValue << 4);
385 }
386
387 uint8_t NR23(void) {
388 return soundReg->mode2.frequencyLow;
389 }
390
391 uint8_t NR24(void) {
392 return soundReg->mode2.frequencyHigh | (soundReg->mode2.counter_ConsSel << 6) | (soundReg->mode2.restart << 7);
393 }
394
395 //-------------------------------
396 uint8_t NR30(void) {
397 return soundReg->mode3.on_Off << 7;
398 }
399
400 uint8_t NR31(void) {
401 return soundReg->mode3.soundLength;
402 }
403
404 uint8_t NR32(void) {
405 return soundReg->mode3.selOutputLevel << 5;
406 }
407
408 uint8_t NR33(void) {
409 return soundReg->mode3.frequencyLow;
410 }
411
412 uint8_t NR34(void) {
413 return soundReg->mode3.frequencyHigh | (soundReg->mode3.counter_ConsSel << 6) | (soundReg->mode3.restart << 7);
414 }
415
416 //-------------------------------
417 uint8_t NR41(void) {
418 return soundReg->mode4.soundLength;
419 }
420
421 uint8_t NR42(void) {
422 return soundReg->mode4.envNbStep | (soundReg->mode4.envMode << 3) | (soundReg->mode4.envInitialValue << 4);
423 }
424
425 uint8_t NR43(void) {
426 return soundReg->mode4.polyCounterDiv | (soundReg->mode4.polyCounterStep << 3) | (soundReg->mode4.polyCounterFreq << 4);
427 }
428
429 uint8_t NR44(void) {
430 return (soundReg->mode4.counter_ConsSel << 6) | (soundReg->mode4.restart << 7);
431 }
432
433 //-------------------------------
434 uint8_t NR50(void) {
435 return soundReg->control.SO1_OutputLevel | (soundReg->control.Vin_SO1 << 3u) | (soundReg->control.SO2_OutputLevel << 4u) |
436 (soundReg->control.Vin_SO2 << 7u);
437 }
438
439 uint8_t NR51(void) {
440 return soundReg->control.Sound1_To_SO1 | (soundReg->control.Sound2_To_SO1 << 1) | (soundReg->control.Sound3_To_SO1 << 2) |
441 (soundReg->control.Sound4_To_SO1 << 3) | (soundReg->control.Sound1_To_SO2 << 4) | (soundReg->control.Sound2_To_SO2 << 5) |
442 (soundReg->control.Sound3_To_SO2 << 6)| (soundReg->control.Sound4_To_SO2 << 7);
443 }
444
445 uint8_t NR52(void) {
446 return soundReg->control.global_On_Off << 7;
447 }
448
449 //---------------------------------------------------------------------------------
450 uint16_t current_value(uint8_t mode, uint8_t line)
451 {
452 if(mode == 0) {
453 switch(line)
454 {
455 case 0: // global_On_Off
456 return soundReg->control.global_On_Off;
457 case 1: // Vin_SO1
458 return soundReg->control.Vin_SO1;
459 case 2: // Vin_SO2
460 return soundReg->control.Vin_SO2;
461 case 3: // SO1_OutputLevel
462 return soundReg->control.SO1_OutputLevel;
463 case 4: // SO2_OutputLevel
464 return soundReg->control.SO2_OutputLevel;
465 }
466 } else if(mode == 1) {
467 switch(line)
468 {
469 case 0: // sweepTime
470 return soundReg->mode1.sweepTime;
471 case 1: // sweepMode
472 return soundReg->mode1.sweepMode;
473 case 2: // sweepShifts
474 return soundReg->mode1.sweepShifts;
475 case 3: // patternDuty
476 return soundReg->mode1.patternDuty;
477 case 4: // soundLength
478 return soundReg->mode1.soundLength;
479 case 5: // envInitialValue
480 return soundReg->mode1.envInitialValue;
481 case 6: // envMode
482 return soundReg->mode1.envMode;
483 case 7: // envNbSweep
484 return soundReg->mode1.envNbSweep;
485 case 8: // frequency
486 case FREQUENCY:
487 return (soundReg->mode1.frequencyHigh << 8) | soundReg->mode1.frequencyLow;
488 case 9: // counter_ConsSel
489 return soundReg->mode1.counter_ConsSel;
490 case 10: // Sound1_To_SO1
491 return soundReg->control.Sound1_To_SO1;
492 case 11: // Sound1_To_SO2
493 return soundReg->control.Sound1_To_SO2;
494 case 12: // Sound1_On_Off
495 return soundReg->control.Sound1_On_Off;
496 }
497 } else if(mode == 2) {
498 switch(line)
499 {
500 case 0: // patternDuty
501 return soundReg->mode2.patternDuty;
502 case 1: // soundLength
503 return soundReg->mode2.soundLength;
504 case 2: // envInitialValue
505 return soundReg->mode2.envInitialValue;
506 case 3: // envMode
507 return soundReg->mode2.envMode;
508 case 4: // envNbStep
509 return soundReg->mode2.envNbStep;
510 case 5: // frequency
511 case FREQUENCY:
512 return (soundReg->mode2.frequencyHigh << 8) | soundReg->mode2.frequencyLow;
513 case 6: // counter_ConsSel
514 return soundReg->mode2.counter_ConsSel;
515 case 7: // Sound2_To_SO1
516 return soundReg->control.Sound2_To_SO1;
517 case 8: // Sound2_To_SO2
518 return soundReg->control.Sound2_To_SO2;
519 case 9: // Sound2_On_Off
520 return soundReg->control.Sound2_On_Off;
521 }
522 } else if(mode == 3) {
523 switch(line)
524 {
525 case 0: // on_Off
526 return soundReg->mode3.on_Off;
527 case 1: // soundLength
528 return soundReg->mode3.soundLength;
529 case 2: // selOutputLevel
530 return soundReg->mode3.selOutputLevel;
531 case 3: // frequency
532 case FREQUENCY:
533 return (soundReg->mode3.frequencyHigh << 8) | soundReg->mode3.frequencyLow;
534 case 4: // counter_ConsSel
535 return soundReg->mode3.counter_ConsSel;
536 case 5: // Sound3_To_SO1
537 return soundReg->control.Sound3_To_SO1;
538 case 6: // Sound3_To_SO2
539 return soundReg->control.Sound3_To_SO2;
540 case 7: // Sound3_On_Off
541 return soundReg->control.Sound3_On_Off;
542 }
543 } else if(mode == 4) {
544 switch(line)
545 {
546 case 0: // soundLength
547 return soundReg->mode4.soundLength;
548 case 1: // envInitialValue
549 return soundReg->mode4.envInitialValue;
550 case 2: // envMode
551 return soundReg->mode4.envMode;
552 case 3: // envNbStep
553 return soundReg->mode4.envNbStep;
554 case 4: // polyCounterFreq
555 return soundReg->mode4.polyCounterFreq;
556 case 5: // polyCounterStep
557 return soundReg->mode4.polyCounterStep;
558 case 6: // polyCounterDiv
559 return soundReg->mode4.polyCounterDiv;
560 case 7: // counter_ConsSel
561 return soundReg->mode4.counter_ConsSel;
562 case 8: // Sound4_To_SO1
563 return soundReg->control.Sound4_To_SO1;
564 case 9: // Sound4_To_SO2
565 return soundReg->control.Sound4_To_SO2;
566 case 10: // Sound4_On_Off
567 return soundReg->control.Sound4_On_Off;
568 }
569 }
570 return 0;
571 }
572
573 void update_value(uint8_t mode, uint8_t line, uint16_t value)
574 {
575 if(mode == 0) {
576 switch(line)
577 {
578 case 0: // global_On_Off
579 soundReg->control.global_On_Off = value;
580 NR52_REG = NR52();
581 break;
582 case 1: // Vin_SO1
583 soundReg->control.Vin_SO1 = value;
584 NR50_REG = NR50();
585 break;
586 case 2: // Vin_SO2
587 soundReg->control.Vin_SO2 = value;
588 NR50_REG = NR50();
589 break;
590 case 3: // SO1_OutputLevel
591 soundReg->control.SO1_OutputLevel = value;
592 NR50_REG = NR50();
593 break;
594 case 4: // SO2_OutputLevel
595 soundReg->control.SO2_OutputLevel = value;
596 NR50_REG = NR50();
597 break;
598 case FREQUENCY:
599 update_value(1, FREQUENCY, value);
600 update_value(2, FREQUENCY, value);
601 update_value(3, FREQUENCY, value);
602 break;
603 case PLAY: // restart
604 update_value(1, FREQUENCY, current_value(1, FREQUENCY));
605 update_value(2, FREQUENCY, current_value(2, FREQUENCY));
606 update_value(3, FREQUENCY, current_value(3, FREQUENCY));
607 soundReg->mode1.restart = value;
608 soundReg->mode2.restart = value;
609 soundReg->mode3.restart = value;
610 soundReg->mode4.restart = value;
611 NR14_REG = NR14();
612 NR24_REG = NR24();
613 NR34_REG = NR34();
614 NR44_REG = NR44();
615 soundReg->mode1.restart = 0;
616 soundReg->mode2.restart = 0;
617 soundReg->mode3.restart = 0;
618 soundReg->mode4.restart = 0;
619 break;
620 }
621 } else if(mode == 1) {
622 switch(line)
623 {
624 case 0: // sweepTime
625 soundReg->mode1.sweepTime = value;
626 NR10_REG = NR10();
627 break;
628 case 1: // sweepMode
629 soundReg->mode1.sweepMode = value;
630 NR10_REG = NR10();
631 break;
632 case 2: // sweepShifts
633 soundReg->mode1.sweepShifts = value;
634 NR10_REG = NR10();
635 break;
636 case 3: // patternDuty
637 soundReg->mode1.patternDuty = value;
638 NR11_REG = NR11();
639 break;
640 case 4: // soundLength
641 soundReg->mode1.soundLength = value;
642 NR11_REG = NR11();
643 break;
644 case 5: // envInitialValue
645 soundReg->mode1.envInitialValue = value;
646 NR12_REG = translate_envelope( NR12() );
647 break;
648 case 6: // envMode
649 soundReg->mode1.envMode = value;
650 NR12_REG = translate_envelope( NR12() );
651 break;
652 case 7: // envNbSweep
653 soundReg->mode1.envNbSweep = value;
654 NR12_REG = translate_envelope( NR12() );
655 break;
656 case 8: // frequency
657 case FREQUENCY:
658 soundReg->mode1.frequencyHigh = value >> 8;
659 soundReg->mode1.frequencyLow = 0xFF & value;
660 NR13_REG = NR13();
661 NR14_REG = NR14();
662 break;
663 case 9: // counter_ConsSel
664 soundReg->mode1.counter_ConsSel = value;
665 NR14_REG = NR14();
666 break;
667 case 10: // Sound1_To_SO1
668 soundReg->control.Sound1_To_SO1 = value;
669 NR51_REG = NR51();
670 break;
671 case 11: // Sound1_To_SO2
672 soundReg->control.Sound1_To_SO2 = value;
673 NR51_REG = NR51();
674 break;
675 case 12: // Sound1_On_Off
676 soundReg->control.Sound1_On_Off = value;
677 NR52_REG = NR52();
678 break;
679 case PLAY: // restart
680 update_value(mode, FREQUENCY, current_value(mode, FREQUENCY));
681 if (soundReg->mode1.counter_ConsSel == 1) NR11_REG = NR11();
682 soundReg->mode1.restart = value;
683 NR14_REG = NR14();
684 soundReg->mode1.restart = 0;
685 break;
686 }
687 } else if(mode == 2) {
688 switch(line)
689 {
690 case 0: // patternDuty
691 soundReg->mode2.patternDuty = value;
692 NR21_REG = NR21();
693 break;
694 case 1: // soundLength
695 soundReg->mode2.soundLength = value;
696 NR21_REG = NR21();
697 break;
698 case 2: // envInitialValue
699 soundReg->mode2.envInitialValue = value;
700 NR22_REG = translate_envelope( NR22() );
701 break;
702 case 3: // envMode
703 soundReg->mode2.envMode = value;
704 NR22_REG = translate_envelope( NR22() );
705 break;
706 case 4: // envNbStep
707 soundReg->mode2.envNbStep = value;
708 NR22_REG = translate_envelope( NR22() );
709 break;
710 case 5: // frequency
711 case FREQUENCY:
712 soundReg->mode2.frequencyHigh = value >> 8;
713 soundReg->mode2.frequencyLow = 0xFF & value;
714 NR23_REG = NR23();
715 NR24_REG = NR24();
716 break;
717 case 6: // counter_ConsSel
718 soundReg->mode2.counter_ConsSel = value;
719 NR24_REG = NR24();
720 break;
721 case 7: // Sound2_To_SO1
722 soundReg->control.Sound2_To_SO1 = value;
723 NR51_REG = NR51();
724 break;
725 case 8: // Sound2_To_SO2
726 soundReg->control.Sound2_To_SO2 = value;
727 NR51_REG = NR51();
728 break;
729 case 9: // Sound2_On_Off
730 soundReg->control.Sound2_On_Off = value;
731 NR52_REG = NR52();
732 break;
733 case PLAY: // restart
734 update_value(mode, FREQUENCY, current_value(mode, FREQUENCY));
735 if (soundReg->mode2.counter_ConsSel == 1) NR21_REG = NR21();
736 soundReg->mode2.restart = value;
737 NR24_REG = NR24();
738 soundReg->mode2.restart = 0;
739 break;
740 }
741 } else if(mode == 3) {
742 switch(line)
743 {
744 case 0: // on_Off
745 soundReg->mode3.on_Off = value;
746 NR30_REG = NR30();
747 break;
748 case 1: // soundLength
749 soundReg->mode3.soundLength = value;
750 NR31_REG = NR31();
751 break;
752 case 2: // selOutputLevel
753 soundReg->mode3.selOutputLevel = value;
754 NR32_REG = translate_volume( NR32() );
755 break;
756 case 3: // frequency
757 case FREQUENCY:
758 soundReg->mode3.frequencyHigh = value >> 8;
759 soundReg->mode3.frequencyLow = 0xFF & value;
760 NR33_REG = NR33();
761 NR34_REG = NR34();
762 break;
763 case 4: // counter_ConsSel
764 soundReg->mode3.counter_ConsSel = value;
765 NR34_REG = NR34();
766 break;
767 case 5: // Sound3_To_SO1
768 soundReg->control.Sound3_To_SO1 = value;
769 NR51_REG = NR51();
770 break;
771 case 6: // Sound3_To_SO2
772 soundReg->control.Sound3_To_SO2 = value;
773 NR51_REG = NR51();
774 break;
775 case 7: // Sound3_On_Off
776 soundReg->control.Sound3_On_Off = value;
777 NR52_REG = NR52();
778 break;
779 case PLAY: // restart
780 update_value(mode, FREQUENCY, current_value(mode, FREQUENCY));
781 if (soundReg->mode3.counter_ConsSel == 1) NR31_REG = NR31();
782 soundReg->mode3.restart = value;
783 NR34_REG = NR34();
784 soundReg->mode3.restart = 0;
785 break;
786 }
787 } else if(mode == 4) {
788 switch(line)
789 {
790 case 0: // soundLength
791 soundReg->mode4.soundLength = value;
792 NR41_REG = NR41();
793 break;
794 case 1: // envInitialValue
795 soundReg->mode4.envInitialValue = value;
796 NR42_REG = translate_envelope( NR42() );
797 break;
798 case 2: // envMode
799 soundReg->mode4.envMode = value;
800 NR42_REG = translate_envelope( NR42() );
801 break;
802 case 3: // envNbStep
803 soundReg->mode4.envNbStep = value;
804 NR42_REG = translate_envelope( NR42() );
805 break;
806 case 4: // polyCounterFreq
807 soundReg->mode4.polyCounterFreq = value;
808 NR43_REG = translate_frequency( NR43() );
809 break;
810 case 5: // polyCounterStep
811 soundReg->mode4.polyCounterStep = value;
812 NR43_REG = translate_frequency( NR43() );
813 break;
814 case 6: // polyCounterDiv
815 soundReg->mode4.polyCounterDiv = value;
816 NR43_REG = translate_frequency( NR43() );
817 break;
818 case 7: // counter_ConsSel
819 soundReg->mode4.counter_ConsSel = value;
820 NR44_REG = NR44();
821 break;
822 case 8: // Sound4_To_SO1
823 soundReg->control.Sound4_To_SO1 = value;
824 NR51_REG = NR51();
825 break;
826 case 9: // Sound4_To_SO2
827 soundReg->control.Sound4_To_SO2 = value;
828 NR51_REG = NR51();
829 break;
830 case 10: // Sound4_On_Off
831 soundReg->control.Sound4_On_Off = value;
832 NR52_REG = NR52();
833 break;
834 case PLAY: // restart
835 if (soundReg->mode4.counter_ConsSel == 1) NR41_REG = NR41();
836 soundReg->mode4.restart = value;
837 NR44_REG = NR44();
838 soundReg->mode4.restart = 0;
839 break;
840 }
841 }
842 }
843
844 uint8_t draw_screen(uint8_t mode)
845 {
846 uint8_t i;
847
848 clss();
849 gotoxy(FIRST_X, TITLE_Y);
850 print(params[0].name);
851
852 for(i = 0; params[i+1].name; i++) {
853 gotoxy(FIRST_X, FIRST_Y+i);
854 print(params[i+1].name);
855 gotoxy(VAL_X, FIRST_Y+i);
856 println(current_value(mode, i), 10, UNSIGNED);
857 }
858
859 return i-1;
860 }
861
862
863 void play_music(uint8_t mode)
864 {
865 uint8_t i = 0;
866
867 while(music[i] != END) {
868 if(music[i] != SILENCE) {
869 update_value(mode, FREQUENCY, frequencies[music[i]]);
870 update_value(mode, PLAY, 1);
871 }
872 delay(500);
873 i++;
874 }
875 }
876
877
878 void show_register_channel(uint8_t mode) {
879
880 #ifdef MEGADUCK
881 gotoxy(0, 15);
882 print("MDuck:Shows GB Eqivs");
883 #endif
884
885 switch (mode) {
886 case 1:
887 gotoxy(0, 16);
888 print("NR10-14:");
889
890 gotoxy(1, 17); // Last line
891 printn(NR10(), 16, UNSIGNED); print(", ");
892 printn(NR11(), 16, UNSIGNED); print(", ");
893 printn(NR12(), 16, UNSIGNED); print(", ");
894 printn(NR13(), 16, UNSIGNED); print(", ");
895 printn(0x80 | NR14(), 16, UNSIGNED);
896
897 break;
898
899 case 2:
900 gotoxy(0, 16);
901 print("NR21-24:");
902
903 gotoxy(1, 17); // Last line
904 printn(NR21(), 16, UNSIGNED); print(", ");
905 printn(NR22(), 16, UNSIGNED); print(", ");
906 printn(NR23(), 16, UNSIGNED); print(", ");
907 printn(0x80 | NR24(), 16, UNSIGNED);
908
909 break;
910
911 case 3:
912 gotoxy(0, 16);
913 print("NR30-34:");
914
915 gotoxy(1, 17); // Last line
916 printn(NR30(), 16, UNSIGNED); print(", ");
917 printn(NR31(), 16, UNSIGNED); print(", ");
918 printn(NR32(), 16, UNSIGNED); print(", ");
919 printn(NR33(), 16, UNSIGNED); print(", ");
920 printn(0x80 | NR34(), 16, UNSIGNED);
921
922 break;
923
924 case 4:
925 gotoxy(0, 16);
926 print("NR41-44:");
927
928 gotoxy(1, 17); // Last line
929 printn(NR41(), 16, UNSIGNED); print(", ");
930 printn(NR42(), 16, UNSIGNED); print(", ");
931 printn(NR43(), 16, UNSIGNED); print(", ");
932 printn(0x80 | NR44(), 16, UNSIGNED);
933
934 break;
935
936 case 0:
937 gotoxy(0, 16);
938 print("NR50-52:");
939
940 gotoxy(1, 17); // Last line
941 printn(NR50(), 16, UNSIGNED); print(", ");
942 printn(NR51(), 16, UNSIGNED); print(", ");
943 printn(NR52(), 16, UNSIGNED); print(", ");
944
945 break;
946
947 }
948 }
949
950
951 void dump_registers(void)
952 {
953 clss();
954 gotoxy(FIRST_X, TITLE_Y);
955 print("Register Dump\n\n");
956
957 print("NR10:");println(NR10(), 16, UNSIGNED);
958 print("NR11:");printn(NR11(), 16, UNSIGNED); print(" NR21:");println(NR21(), 16, UNSIGNED);
959 print("NR12:");printn(NR12(), 16, UNSIGNED); print(" NR22:");println(NR22(), 16, UNSIGNED);
960 print("NR13:");printn(NR13(), 16, UNSIGNED); print(" NR23:");println(NR23(), 16, UNSIGNED);
961 print("NR14:");printn(0x80 | NR14(), 16, UNSIGNED); print(" NR24:");println(0x80 | NR24(), 16, UNSIGNED);
962 printf("\n");
963
964 print("NR30:");println(NR30(), 16, UNSIGNED);
965 print("NR31:");printn(NR31(), 16, UNSIGNED); print(" NR41:");println(NR41(), 16, UNSIGNED);
966 print("NR32:");printn(NR32(), 16, UNSIGNED); print(" NR42:");println(NR42(), 16, UNSIGNED);
967 print("NR33:");printn(NR33(), 16, UNSIGNED); print(" NR43:");println(NR43(), 16, UNSIGNED);
968 print("NR34:");printn(0x80 | NR34(), 16, UNSIGNED); print(" NR44:");println(0x80 | NR44(), 16, UNSIGNED);
969 printf("\n");
970
971 print("NR50:");println(NR50(), 16, UNSIGNED);
972 print("NR51:");println(NR51(), 16, UNSIGNED);
973 print("NR52:");println(NR52(), 16, UNSIGNED);
974 }
975
976 void wait_event(uint8_t mode)
977 {
978 uint8_t y, last_y;
979 uint16_t l = 0;
980 uint16_t m = 0;
981
982 while(1) {
983 params = params_array[mode];
984 last_y = draw_screen(mode) + FIRST_Y;
985 y = FIRST_Y;
986 gotoxy(ARROW_X, y);
987 setchar(ARROW_CHAR);
988
989 show_register_channel(mode);
990
991 while(1) {
992 if(KEY_TICKED(J_UP)) {
993 gotoxy(ARROW_X, y); setchar(SPACE_CHAR);
994 if(--y < FIRST_Y)
995 y = last_y;
996 gotoxy(ARROW_X, y); setchar(ARROW_CHAR);
997
998 } else if(KEY_TICKED(J_DOWN)) {
999 gotoxy(ARROW_X, y); setchar(SPACE_CHAR);
1000 if(++y > last_y)
1001 y = FIRST_Y;
1002 gotoxy(ARROW_X, y); setchar(ARROW_CHAR);
1003
1004 } else if(KEY_TICKED(J_LEFT)) {
1005 l = current_value(mode, y-FIRST_Y);
1006 if(l != 0) {
1007 if(KEY_PRESSED(J_A) && KEY_PRESSED(J_B))
1008 l = 0;
1009 else if(KEY_PRESSED(J_A))
1010 l = (l > 10) ? (l - 10) : 0;
1011 else if(KEY_PRESSED(J_B))
1012 l = (l > 100) ? (l - 100) : 0;
1013 else
1014 l--;
1015 update_value(mode, y-FIRST_Y, l);
1016 }
1017 gotoxy(VAL_X, y); print(" ");
1018 gotoxy(VAL_X, y); println(l, 10, UNSIGNED);
1019
1020 show_register_channel(mode);
1021
1022 } else if(KEY_TICKED(J_RIGHT)) {
1023 l = current_value(mode, y-FIRST_Y);
1024 m = params[y-(FIRST_Y-1)].max;
1025 if(l != m) {
1026 if(KEY_PRESSED(J_A) && KEY_PRESSED(J_B)) {
1027 l = m;
1028 }
1029 else if(KEY_PRESSED(J_A)) {
1030 l += 10;
1031 if(l > m)
1032 l = m;
1033 } else if(KEY_PRESSED(J_B)) {
1034 l += 100;
1035 if(l > m)
1036 l = m;
1037 }
1038 else
1039 l++;
1040 update_value(mode, y-FIRST_Y, l);
1041 }
1042 gotoxy(VAL_X, y); print(" ");
1043 gotoxy(VAL_X, y); println(l, 10, UNSIGNED);
1044
1045 show_register_channel(mode);
1046
1047 } else if(KEY_TICKED(J_START)) {
1048 if (KEY_PRESSED(J_A))
1049 play_music(mode);
1050 else
1051 update_value(mode, PLAY, 1);
1052
1053 } else if(KEY_PRESSED(J_SELECT)) {
1054 if(KEY_PRESSED(J_A))
1055 dump_registers();
1056 else {
1057 mode = (mode+1) % NB_MODES;
1058 }
1059 waitpadup();
1060 keys = 0;
1061 break;
1062 }
1063 vsync();
1064 UPDATE_KEYS();
1065 }
1066 }
1067 }
1068
1069 void main(void)
1070 {
1071 //
1072 // Before modifying any sound register, sound must be turned on!
1073 // (it is turned off by default to save batteries)
1074 //
1075 NR52_REG = 0x80;
1076
1077 // Init Channel 3 Wave RAM to known values
1078 // (Match CGB power-on defaults of alternating 00/FF)
1079 for (uint8_t c = 0u; c < 16u; c++)
1080 AUD3WAVE[c] = (c & 1u) ? 0x00u : 0xFFu;
1081
1082 soundReg = &s;
1083 NR10_REG = NR10();
1084 NR11_REG = NR11();
1085 NR12_REG = translate_envelope( NR12() );
1086 NR13_REG = NR13();
1087 NR14_REG = NR14();
1088
1089 NR21_REG = NR21();
1090 NR22_REG = translate_envelope( NR22() );
1091 NR23_REG = NR23();
1092 NR24_REG = NR24();
1093
1094 NR30_REG = NR30();
1095 NR31_REG = NR31();
1096 NR32_REG = translate_volume( NR32() );
1097 NR33_REG = NR33();
1098 NR34_REG = NR34();
1099
1100 NR41_REG = NR41();
1101 NR42_REG = translate_envelope( NR42() );
1102 NR43_REG = translate_frequency( NR43() );
1103 NR44_REG = NR44();
1104
1105 NR50_REG = NR50();
1106 NR51_REG = NR51();
1107 NR52_REG = NR52();
1108
1109 clss();
1110
1111 wait_event(1);
1112 }
1113
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.