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