git.y1.nz

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.