1 #include "shared.h"
2 #include <math.h>
3 #include <string.h>
4 #include "../filter.h"
5
6 /*--------------------------------------------------------------------------*/
7 /* Init, reset, shutdown routines */
8 /*--------------------------------------------------------------------------*/
9
10
11 static int32 dbtable[32][32];
12
redo_ddacache(FESTALON_HES * hes,psg_channel * ch)13 static inline void redo_ddacache(FESTALON_HES *hes, psg_channel *ch)
14 {
15 static const int scale_tab[] = {
16 0x00, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
17 0x10, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F
18 };
19
20 int al,lal,ral,lmal,rmal;
21 int vll,vlr;
22
23 al = ch->control & 0x1F;
24
25 lal = scale_tab[(ch->balance >> 4) & 0xF];
26 ral = scale_tab[(ch->balance >> 0) & 0xF];
27
28 lmal = scale_tab[(hes->psg.globalbalance >> 4) & 0xF];
29 rmal = scale_tab[(hes->psg.globalbalance >> 0) & 0xF];
30
31 vll = (0x1F - lal) + (0x1F - al) + (0x1F - lmal);
32 if(vll > 0x1F) vll = 0x1F;
33
34 vlr = (0x1F - ral) + (0x1F - al) + (0x1F - rmal);
35 if(vlr > 0x1F) vlr = 0x1F;
36
37 ch->dda_cache[0] = dbtable[ch->dda][vll];
38 ch->dda_cache[1] = dbtable[ch->dda][vlr];
39 }
40
41
psg_init(FESTALON_HES * hes)42 int psg_init(FESTALON_HES *hes)
43 {
44 int x;
45
46 for(x=0;x<32;x++)
47 {
48 int y;
49 double flub;
50
51 flub = 1;
52
53 if(x)
54 flub /= pow(2, (double)1/4*x); // ~1.5dB reduction per increment of x
55 for(y=0;y<32;y++)
56 dbtable[y][x] = (flub * (y - 0x10) * 128);
57 //printf("%f\n",flub);
58 }
59 memset(&hes->psg, 0, sizeof(hes->psg));
60
61 return (0);
62 }
63
psg_reset(FESTALON_HES * hes)64 void psg_reset(FESTALON_HES *hes)
65 {
66 memset(&hes->psg.channel, 0, sizeof(hes->psg.channel));
67 }
68
psg_shutdown(FESTALON_HES * hes)69 void psg_shutdown(FESTALON_HES *hes)
70 {
71 int x;
72
73 for(x=0;x<2;x++)
74 {
75 if(hes->psg.ff[x])
76 {
77 FESTAFILT_Kill(hes->psg.ff[x]);
78 hes->psg.ff[x] = 0;
79 }
80 if(hes->psg.WaveFinal[x])
81 FESTA_free(hes->psg.WaveFinal[x]);
82 hes->psg.WaveFinal[x] = 0;
83 }
84 if(hes->psg.WaveIL)
85 FESTA_free(hes->psg.WaveIL);
86 hes->psg.WaveIL = 0;
87 }
88
89 /*--------------------------------------------------------------------------*/
90 /* PSG emulation */
91 /*--------------------------------------------------------------------------*/
92
93 /* Macro to access currently selected PSG channel */
94 #define PSGCH hes->psg.channel[hes->psg.select]
95
psg_w(FESTALON_HES * hes,uint16 address,uint8 data)96 void psg_w(FESTALON_HES *hes, uint16 address, uint8 data)
97 {
98 psg_update(hes);
99 int x;
100
101 switch(address)
102 {
103 case 0x0800: /* Channel select */
104 hes->psg.select = (data & 7);
105 break;
106
107 case 0x0801: /* Global sound balance */
108 //printf("Global: %02x\n\n",data);
109 hes->psg.globalbalance = data;
110 for(x=0;x<6;x++)
111 redo_ddacache(hes, &hes->psg.channel[x]);
112 break;
113
114 case 0x0802: /* Channel frequency (LSB) */
115 PSGCH.frequency = (PSGCH.frequency & 0x0F00) | (data);
116 break;
117
118 case 0x0803: /* Channel frequency (MSB) */
119 PSGCH.frequency = (PSGCH.frequency & 0x00FF) | ((data & 0x0F) << 8);
120 break;
121
122 case 0x0804: /* Channel enable, DDA, volume */
123 //if(hes->psg.select == 5) printf("Ch: %02x\n",data&0x1F);
124 PSGCH.control = data;
125 if((data & 0xC0) == 0x40) PSGCH.waveform_index = 0;
126 redo_ddacache(hes, &PSGCH);
127 break;
128
129 case 0x0805: /* Channel balance */
130 PSGCH.balance = data;
131 redo_ddacache(hes, &PSGCH);
132 break;
133
134 case 0x0806: /* Channel waveform data */
135 data &= 0x1F;
136
137 if((PSGCH.control & 0xC0) == 0x00)
138 {
139 PSGCH.waveform[PSGCH.waveform_index] = data;
140 PSGCH.waveform_index = ((PSGCH.waveform_index + 1) & 0x1F);
141 }
142
143 /* DDA mode - data goes to speaker */
144 if((PSGCH.control & 0xC0) == 0xC0)
145 {
146 PSGCH.dda = data;
147 }
148 redo_ddacache(hes, &PSGCH);
149 break;
150
151 case 0x0807: /* Noise enable and frequency */
152 if(hes->psg.select >= 4) PSGCH.noisectrl = data;
153 break;
154
155 case 0x0808: /* LFO frequency */
156 hes->psg.lfofreq = data;
157 break;
158
159 case 0x0809: /* LFO trigger and control */
160 hes->psg.lfoctrl = data;
161 break;
162 }
163 }
164
psg_update(FESTALON_HES * hes)165 void psg_update(FESTALON_HES *hes)
166 {
167 int chc;
168 int32 V;
169 int32 timestamp;
170 int disabled[6];
171
172 timestamp = (((h6280_Regs *)hes->h6280)->timestamp >> 1) &~1;
173
174 for(V=0;V<6;V++)
175 {
176 disabled[V] = ((hes->psg.channel[V].control & 0x80)^0x80) >> 7;
177
178 disabled[V] |= (hes->psg.disabled >> V)&1;
179 }
180
181 if(((FESTAFILT *)hes->psg.ff[0])->input_format == FFI_INT16)
182 {
183 int16 *WaveHiLeft=hes->psg.WaveHi16[0];
184 int16 *WaveHiRight = hes->psg.WaveHi16[1];
185 #include "psg-loop.h"
186 }
187 else
188 {
189 int32 *WaveHiLeft=hes->psg.WaveHi[0];
190 int32 *WaveHiRight = hes->psg.WaveHi[1];
191 #include "psg-loop.h"
192 }
193
194
195 hes->psg.lastts = timestamp;
196 }
197
198
psg_flush(FESTALON_HES * hes)199 uint32 psg_flush(FESTALON_HES *hes)
200 {
201 int32 timestamp;
202 int32 end, left;
203 int32 x;
204 int cb;
205
206 h6280_Regs *h6280 = hes->h6280;
207
208 psg_update(hes);
209
210 timestamp = h6280->timestamp >> 2;
211
212 for(cb=0;cb<2;cb++)
213 {
214 //printf("%d: %d\n",cb, hes->psg.ff[cb]);
215 if(((FESTAFILT *)hes->psg.ff[cb])->input_format == FFI_INT16)
216 {
217
218 }
219 else
220 {
221 float *tmpo=(float *)&hes->psg.WaveHi[cb][hes->psg.lastpoo];
222 int32 *intmpo = &hes->psg.WaveHi[cb][hes->psg.lastpoo];
223
224 for(x=timestamp- hes->psg.lastpoo;x;x--)
225 {
226 *tmpo=*intmpo;
227 tmpo++;
228 intmpo++;
229 }
230 }
231
232 if(((FESTAFILT *)hes->psg.ff[cb])->input_format == FFI_INT16)
233 {
234 end = FESTAFILT_Do(hes->psg.ff[cb],(float *)hes->psg.WaveHi16[cb],hes->psg.WaveFinal[cb], hes->psg.WaveFinalLen, timestamp, &left, 1);
235 memmove(hes->psg.WaveHi16[cb],(int16 *)hes->psg.WaveHi16[cb]+timestamp-left,left*sizeof(uint16));
236 memset((int16 *)hes->psg.WaveHi16[cb]+left,0,sizeof(hes->psg.WaveHi16[cb])-left*sizeof(uint16));
237 }
238 else
239 {
240 end = FESTAFILT_Do(hes->psg.ff[cb], (float *)hes->psg.WaveHi[cb],hes->psg.WaveFinal[cb], hes->psg.WaveFinalLen, timestamp, &left, 1);
241 memmove(hes->psg.WaveHi[cb],hes->psg.WaveHi[cb]+timestamp-left,left*sizeof(uint32));
242 memset(hes->psg.WaveHi[cb]+left,0,sizeof(hes->psg.WaveHi[cb])-left*sizeof(uint32));
243 }
244 }
245
246 h6280->timestamp = left;
247 hes->psg.lastpoo = h6280->timestamp;
248 hes->psg.lastts = left << 1;
249
250 h6280->timestamp <<= 2;
251
252 for(x=0;x<end;x++)
253 {
254 hes->psg.WaveIL[x*2] = hes->psg.WaveFinal[0][x];
255 hes->psg.WaveIL[x*2+1] = hes->psg.WaveFinal[1][x];
256 }
257 return(end);
258 }
259
260
FESTAHES_SetVolume(FESTALON_HES * hes,uint32 volume)261 void FESTAHES_SetVolume(FESTALON_HES *hes, uint32 volume)
262 {
263 ((FESTAFILT *)hes->psg.ff[0])->SoundVolume=volume;
264 ((FESTAFILT *)hes->psg.ff[1])->SoundVolume=volume;
265 }
266
267
FESTAHES_SetLowpass(FESTALON_HES * hes,int on,uint32 corner,uint32 order)268 int FESTAHES_SetLowpass(FESTALON_HES *hes, int on, uint32 corner, uint32 order)
269 {
270 if(!FESTAFILT_SetLowpass(hes->psg.ff[0], on, corner, order)) return(0);
271 if(!FESTAFILT_SetLowpass(hes->psg.ff[1], on, corner, order)) return(0);
272 return(1);
273 }
274
FESTAHES_SetSound(FESTALON_HES * hes,uint32 rate,int quality)275 int FESTAHES_SetSound(FESTALON_HES *hes, uint32 rate, int quality)
276 {
277 int x;
278
279 hes->psg.WaveFinalLen = rate / 60 * 2; // *2 for extra room
280
281 for(x=0;x<2;x++)
282 {
283 FESTAFILT **ff = (FESTAFILT **)hes->psg.ff;
284 if(ff[x])
285 {
286 FESTAFILT_Kill(ff[x]);
287 ff[x] = 0;
288 }
289 ff[x] = FESTAFILT_Init(rate,1789772.7272, 0, quality);
290
291 if(hes->psg.WaveFinal[x])
292 {
293 FESTA_free(hes->psg.WaveFinal[x]);
294 hes->psg.WaveFinal[x] = 0;
295 }
296 hes->psg.WaveFinal[x] = FESTA_malloc(16, sizeof(float) * hes->psg.WaveFinalLen);
297 }
298
299 if(hes->psg.WaveIL) FESTA_free(hes->psg.WaveIL);
300 hes->psg.WaveIL = FESTA_malloc(16, sizeof(float) * hes->psg.WaveFinalLen * 2);
301
302 return(1);
303 }
304
305