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 }