cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

sound.c (26963B)


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