psg.c
  1  #include "shared.h"
  2  
  3  t_psg psg;
  4  
  5  /*--------------------------------------------------------------------------*/
  6  /* Init, reset, shutdown routines                                           */
  7  /*--------------------------------------------------------------------------*/
  8  
  9  int psg_init(void)
 10  {
 11      memset(&psg, 0, sizeof(psg));
 12      return (0);
 13  }
 14  
 15  void psg_reset(void)
 16  {
 17      memset(&psg, 0, sizeof(psg));
 18  }
 19  
 20  void psg_shutdown(void)
 21  {
 22  }
 23  
 24  /*--------------------------------------------------------------------------*/
 25  /* PSG emulation                                                            */
 26  /*--------------------------------------------------------------------------*/
 27  
 28  void psg_w(uint16 address, uint8 data)
 29  {
 30      switch(address)
 31      {
 32          case 0x0800: /* Channel select */
 33              psg.select = (data & 7);
 34              break;
 35  
 36          case 0x0801: /* Global sound balance */
 37              psg.globalbalance = data;
 38              break;
 39  
 40          case 0x0802: /* Channel frequency (LSB) */
 41              PSGCH.frequency = (PSGCH.frequency & 0x0F00) | (data);
 42              break;
 43  
 44          case 0x0803: /* Channel frequency (MSB) */
 45              PSGCH.frequency = (PSGCH.frequency & 0x00FF) | ((data & 0x0F) << 8);
 46              break;
 47  
 48          case 0x0804: /* Channel enable, DDA, volume */
 49              PSGCH.control = data;
 50              if((data & 0xC0) == 0x40) PSGCH.waveform_index = 0;
 51              break;
 52  
 53          case 0x0805: /* Channel balance */
 54              PSGCH.balance = data;
 55              break;
 56  
 57          case 0x0806: /* Channel waveform data */
 58              PSGCH.waveform[PSGCH.waveform_index] = data;
 59              PSGCH.waveform_index = ((PSGCH.waveform_index + 1) & 0x1F);
 60              break;
 61  
 62          case 0x0807: /* Noise enable and frequency */
 63              psg.noisectrl = data;
 64              break;
 65  
 66          case 0x0808: /* LFO frequency */
 67              psg.lfofreq = data;
 68              break;
 69  
 70          case 0x0809: /* LFO trigger and control */
 71              psg.lfoctrl = data;
 72              break;
 73      }
 74  }
 75  
 76  void psg_update(int16 *bufl, int16 *bufr, int length)
 77  {
 78      /* Fill as many samples as needed */
 79      while(length > 0)
 80      {
 81          int ch;                    /* Channel index */
 82          int sample[2] = {0, 0};    /* Left and right samples */
 83          int start;                 /* Skip channels 0, 1 if LFO is enabled */ 
 84          int stop;                  /* Skip channels 4, 5 if noise is enabled */
 85  
 86          start = ((psg.lfoctrl & 3) == 0) ? 0 : 2;
 87          stop = (psg.noisectrl & 0x80) ? 4 : 6;
 88  
 89          for(ch = start; ch < stop; ch += 1)
 90          {
 91              /* If channel is ON and DDA is OFF, play waveform data */
 92              if((psg.channel[ch].control & 0xC0) == 0x80)
 93              {
 94                  /* Global sound balance (left and right, all channels) */
 95                  int lbal = (psg.globalbalance >> 4) & 0x0F;
 96                  int rbal = (psg.globalbalance >> 0) & 0x0F;
 97  
 98                  /* Balance (left and right, this channel) */
 99                  int lchb = (psg.channel[ch].balance >> 4) & 0x0F;
100                  int rchb = (psg.channel[ch].balance >> 0) & 0x0F;
101  
102                  /* Volume level (this channel) */
103                  int chvl = (psg.channel[ch].control & 0x1F);
104      
105                  /* Total volume levels for left and right
106                     (volume sounds too soft - not sure how to combine these) */
107                  int lvol = (lbal + lchb + chvl);
108                  int rvol = (rbal + rchb + chvl);
109  
110                  int base, step, offset, data;
111  
112                  /* This is the largest possible step value which is divided
113                     by the channel frequency used to increment the counter,
114                     which in turn is used to traverse the waveform buffer.
115                     3580000 (PSG clock) / 32 (length of waveform) = 111875 (base step value)
116                     That doesn't work right but multiplying it by three sounds better. */
117                  base = (3580000 / 32) * 3;
118  
119                  /* Calculate the value to add to the counter for each sample,
120                     but don't divide by zero if the frequency is zero */
121                  step = (psg.channel[ch].frequency) ? base / psg.channel[ch].frequency : 0;
122  
123                  /* Use upper 5 bits of 12-bit frequency as wave index */
124                  offset = (psg.channel[ch].counter >> 12) & 0x1F;
125  
126                  /* Bump waveform index */
127                  psg.channel[ch].counter += step;
128  
129                  /* Data is 5 bits */
130                  data = (psg.channel[ch].waveform[offset] & 0x1F);
131  
132                  /* Add new sample to old one */
133                  sample[0] = (sample[0] + (lvol * data));
134                  sample[1] = (sample[1] + (rvol * data));
135              }
136          }
137  
138          /* Make samples signed */
139          if(sample[0] & 0x8000) sample[0] ^= 0x8000;
140          if(sample[1] & 0x8000) sample[1] ^= 0x8000;
141  
142          /* Store samples in buffer */
143          *bufl++ = sample[0]; //(sample[0]+sample[1])/2;
144          //*bufl++ = sample[1];
145          //*bufr++ = sample[1];
146  
147          /* Do next sample pair */
148          --length;
149      }
150  }