]> Shamusworld >> Repos - thunder/blob - src/psg.cpp
b4f3f47c0f59da0724ac25583c921b0265d30716
[thunder] / src / psg.cpp
1 //
2 // PSG handler
3 //
4 // This emulates the Rolling Thunder PSG (Namco CUS30)
5 //
6 // by James Hammons
7 // (C) 2014 Underground Software
8 //
9 // JLH = James Hammons <jlhamm@acm.org>
10 //
11 // Who  When        What
12 // ---  ----------  -----------------------------------------------------------
13 // JLH  04/21/2014  Created this file.
14 //
15
16 #include "psg.h"
17 #include <stdio.h>
18 #include <string.h>
19
20
21 struct Voice
22 {
23         uint8_t leftVolume;
24         uint8_t rightVolume;
25         uint8_t waveform;
26         uint32_t frequency;
27         uint32_t counter;
28         bool noise;
29         uint32_t noiseSeed;
30 };
31
32 static Voice voice[8];
33 static uint8_t memory[0x200];
34 //static 
35 static uint32_t sampleRate = 44100;
36
37 extern FILE * psg1;
38 extern FILE * psg2;
39
40
41 void InitPSG(uint32_t s/*=44100*/)
42 {
43         sampleRate = s;
44
45         for(int i=0; i<8; i++)
46                 voice[i].noiseSeed = 1;
47 }
48
49
50 void UpdatePSG(uint8_t * buffer, int count)
51 {
52 /*
53 if F == 44100, then counter++ for each sample.
54 if F == 88200, then counter += 2 for each sample.
55 if F == 22050, then counter += 0.5 for each sample.
56 */
57 //      memset(buffer, 0, count * 2);
58
59         // Recast buffer as int16, we're doing 16-bit sound here
60         int16_t * p = (int16_t *)buffer;
61
62         for(int i=0; i<8; i++)
63         {
64                 if (!voice[i].noise)
65                 {
66                         if ((voice[i].leftVolume == 0) || (voice[i].frequency == 0))
67                                 continue;
68
69                         for(int j=0; j<count; j++)
70                         {
71 //                              uint8_t pos = (voice[i].counter / (sampleRate * 2)) & 0x1F;
72 // Where does 60000 come from? IDK. This would probably change depending on
73 // the playback rate (currently, 44100). N.B.: 58800 is a hair too high in pitch!
74 // 44100 / 60000 = 0.735
75 // 192000 / 60000 = 3.2
76 //                              uint8_t pos = (voice[i].counter / (60000)) & 0x1F;
77                                 uint8_t pos = (voice[i].counter / (65536)) & 0x1F;
78                                 uint8_t sample = ((pos & 0x01) == 0
79                                         ? memory[(voice[i].waveform * 16) + (pos / 2)] >> 4
80                                         : memory[(voice[i].waveform * 16) + (pos / 2)]) & 0x0F;
81 //                              p[j] += (((memory[(voice[i].waveform * 32) + pos] & 0x0F) - 8)
82 //                                      * voice[i].leftVolume) << 5;
83                                 p[j] += ((sample - 8) * voice[i].leftVolume) << 5;
84                                 voice[i].counter += voice[i].frequency;
85                         }
86                 }
87                 else
88                 {
89                         if ((voice[i].leftVolume == 0) || ((voice[i].frequency & 0xFF) == 0))
90                                 continue;
91
92                         int16_t sample = (7 * voice[i].leftVolume) << 4;
93                         int16_t noiseSign = 1;
94                         int16_t hold = 1 << 1;
95
96                         for(int j=0; j<count; j++)
97                         {
98                                 p[j] += sample * noiseSign;
99 #if 0
100 if (i == 1)
101 {
102         fputc(sample & 0xFF, psg1);
103         fputc((sample >> 8) & 0xFF , psg1);
104 }
105 else if (i == 3)
106 {
107         fputc(sample & 0xFF, psg2);
108         fputc((sample >> 8) & 0xFF , psg2);
109 }
110 #endif
111
112                                 if (hold)
113                                 {
114                                         hold--;
115                                         continue;
116                                 }
117
118                                 hold = 1 << 1;
119
120                                 voice[i].counter += (voice[i].frequency & 0xFF) << 4;
121                                 int c = voice[i].counter >> 12;
122                                 voice[i].counter &= 0xFFF;
123
124                                 for(; c>0; c--)
125                                 {
126                                         if ((voice[i].noiseSeed + 1) & 0x02)
127                                                 noiseSign *= -1;
128
129                                         if (voice[i].noiseSeed & 0x01)
130                                                 voice[i].noiseSeed ^= 0x28000;
131
132                                         voice[i].noiseSeed >>= 1;
133                                 }
134                         }
135                 }
136         }
137 }
138
139
140 void WritePSG(uint16_t address, uint8_t data)
141 {
142         if ((address >= 0x100) && (address <= 0x13F))
143         {
144                 uint8_t channel = (address - 0x100) / 8;
145                 uint8_t knob = (address - 0x100) - (channel * 8);
146
147                 if (channel < 8)
148                 {
149                         switch (knob)
150                         {
151                         case 0:
152                                 voice[channel].leftVolume = data & 0x0F;
153                                 break;
154                         case 1:
155                                 voice[channel].waveform = data >> 4;
156                                 voice[channel].frequency = ((data & 0x0F) << 16) 
157                                         | (voice[channel].frequency & 0x0FFFF);
158 #if 0
159 printf("PSG: Setting waveform on channel %i to %i...\n", channel, voice[channel].waveform);
160 #endif
161                                 break;
162                         case 2:
163                                 voice[channel].frequency = (data << 8)
164                                         | (voice[channel].frequency & 0xF00FF);
165                                 break;
166                         case 3:
167                                 voice[channel].frequency = data
168                                         | (voice[channel].frequency & 0xFFF00);
169                                 break;
170                         case 4:
171                                 voice[channel].rightVolume = data & 0x0F;
172                                 // Noise switch is channel # + 1 (wraps to zero)
173                                 voice[(channel + 1) & 0x07].noise = (data & 0x80 ? true : false);
174 #if 0
175 if (voice[(channel + 1) & 0x07].noise)
176 {
177         uint8_t ch = (channel + 1) & 0x07;
178         printf("PSG: Setting noise on channel %i, vol=%i, freq=%i...\n", ch, voice[ch].leftVolume, voice[ch].frequency);
179 }
180 #endif
181 #if 0
182 if (data & 0x0F)
183 {
184         printf("PSG: Setting right volume on channel %i: vol=%i...\n", channel, voice[channel].rightVolume);
185 }
186 #endif
187                                 break;
188                         }
189                 }
190
191 //              return;
192         }
193 #if 0
194         else
195                 printf("PSG: Write to $%03X of $%02X...\n", address, data);
196 #endif
197
198 //if (address < 0x100)
199 //      printf("PSG: Waveform byte[$%02X] = $%02X...\n", address, data);
200
201         memory[address & 0x01FF] = data;
202 }
203
204
205 uint8_t ReadPSG(uint16_t address)
206 {
207         return memory[address & 0x01FF];
208 }
209