spu: put globals into a structure
[pcsx_rearmed.git] / plugins / dfsound / registers.c
CommitLineData
ef79bbde
P
1/***************************************************************************\r
2 registers.c - description\r
3 -------------------\r
4 begin : Wed May 15 2002\r
5 copyright : (C) 2002 by Pete Bernert\r
6 email : BlackDove@addcom.de\r
7 ***************************************************************************/\r
8/***************************************************************************\r
9 * *\r
10 * This program is free software; you can redistribute it and/or modify *\r
11 * it under the terms of the GNU General Public License as published by *\r
12 * the Free Software Foundation; either version 2 of the License, or *\r
13 * (at your option) any later version. See also the license.txt file for *\r
14 * additional informations. *\r
15 * *\r
16 ***************************************************************************/\r
17\r
18#include "stdafx.h"\r
19\r
20#define _IN_REGISTERS\r
21\r
22#include "externals.h"\r
23#include "registers.h"\r
3154bfab 24#include "spu_config.h"\r
ef79bbde 25\r
7e44d49d 26static void SoundOn(int start,int end,unsigned short val);\r
27static void SoundOff(int start,int end,unsigned short val);\r
28static void FModOn(int start,int end,unsigned short val);\r
29static void NoiseOn(int start,int end,unsigned short val);\r
30static void SetVolumeL(unsigned char ch,short vol);\r
31static void SetVolumeR(unsigned char ch,short vol);\r
32static void SetPitch(int ch,unsigned short val);\r
33static void ReverbOn(int start,int end,unsigned short val);\r
34\r
ef79bbde
P
35////////////////////////////////////////////////////////////////////////\r
36// WRITE REGISTERS: called by main emu\r
37////////////////////////////////////////////////////////////////////////\r
38\r
650adfd2 39static const uint32_t ignore_dupe[8] = {\r
40 // ch 0-15 c40 c80 cc0\r
41 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,\r
42 // ch 16-24 d40 control reverb\r
43 0x7f7f7f7f, 0x7f7f7f7f, 0xff05ff0f, 0xffffffff\r
44};\r
45\r
46void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,\r
47 unsigned int cycles)\r
ef79bbde 48{\r
650adfd2 49 int r = reg & 0xfff;\r
50 int rofs = (r - 0xc00) >> 1;\r
3154bfab 51 int changed = spu.regArea[rofs] != val;\r
52 spu.regArea[rofs] = val;\r
650adfd2 53\r
54 if (!changed && (ignore_dupe[rofs >> 5] & (1 << (rofs & 0x1f))))\r
55 return;\r
56 // zero keyon/keyoff?\r
57 if (val == 0 && (r & 0xff8) == 0xd88)\r
58 return;\r
59\r
60 do_samples_if_needed(cycles);\r
ef79bbde
P
61\r
62 if(r>=0x0c00 && r<0x0d80) // some channel info?\r
63 {\r
64 int ch=(r>>4)-0xc0; // calc channel\r
65 switch(r&0x0f)\r
66 {\r
67 //------------------------------------------------// r volume\r
68 case 0: \r
69 SetVolumeL((unsigned char)ch,val);\r
70 break;\r
71 //------------------------------------------------// l volume\r
72 case 2: \r
73 SetVolumeR((unsigned char)ch,val);\r
74 break;\r
75 //------------------------------------------------// pitch\r
76 case 4: \r
77 SetPitch(ch,val);\r
650adfd2 78 goto upd_irq;\r
ef79bbde
P
79 //------------------------------------------------// start\r
80 case 6: \r
7e44d49d 81 // taken from regArea later\r
ef79bbde
P
82 break;\r
83 //------------------------------------------------// level with pre-calcs\r
84 case 8:\r
85 {\r
6d866bb7 86 const unsigned long lval=val;\r
ef79bbde
P
87 //---------------------------------------------//\r
88 s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; \r
89 s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;\r
90 s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;\r
91 s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;\r
92 //---------------------------------------------//\r
ef79bbde
P
93 }\r
94 break;\r
95 //------------------------------------------------// adsr times with pre-calcs\r
96 case 10:\r
97 {\r
6d866bb7 98 const unsigned long lval=val;\r
ef79bbde
P
99\r
100 //----------------------------------------------//\r
101 s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;\r
102 s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;\r
103 s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;\r
104 s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;\r
105 s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;\r
106 //----------------------------------------------//\r
ef79bbde
P
107 }\r
108 break;\r
109 //------------------------------------------------// adsr volume... mmm have to investigate this\r
110 case 12:\r
111 break;\r
112 //------------------------------------------------//\r
113 case 14: // loop?\r
3154bfab 114 s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
650adfd2 115 goto upd_irq;\r
ef79bbde
P
116 //------------------------------------------------//\r
117 }\r
ef79bbde
P
118 return;\r
119 }\r
120\r
121 switch(r)\r
122 {\r
123 //-------------------------------------------------//\r
124 case H_SPUaddr:\r
3154bfab 125 spu.spuAddr = (unsigned long) val<<3;\r
ef79bbde
P
126 break;\r
127 //-------------------------------------------------//\r
128 case H_SPUdata:\r
3154bfab 129 spu.spuMem[spu.spuAddr>>1] = val;\r
130 spu.spuAddr+=2;\r
131 if(spu.spuAddr>0x7ffff) spu.spuAddr=0;\r
ef79bbde
P
132 break;\r
133 //-------------------------------------------------//\r
134 case H_SPUctrl:\r
3154bfab 135 if (!(spu.spuCtrl & CTRL_IRQ)) {\r
136 spu.spuStat&=~STAT_IRQ;\r
650adfd2 137 if (val & CTRL_IRQ)\r
138 schedule_next_irq();\r
139 }\r
3154bfab 140 spu.spuCtrl=val;\r
ef79bbde
P
141 break;\r
142 //-------------------------------------------------//\r
143 case H_SPUstat:\r
3154bfab 144 spu.spuStat=val&0xf800;\r
ef79bbde
P
145 break;\r
146 //-------------------------------------------------//\r
147 case H_SPUReverbAddr:\r
148 if(val==0xFFFF || val<=0x200)\r
149 {rvb.StartAddr=rvb.CurrAddr=0;}\r
150 else\r
151 {\r
152 const long iv=(unsigned long)val<<2;\r
153 if(rvb.StartAddr!=iv)\r
154 {\r
155 rvb.StartAddr=(unsigned long)val<<2;\r
156 rvb.CurrAddr=rvb.StartAddr;\r
157 }\r
158 }\r
650adfd2 159 goto rvbd;\r
ef79bbde
P
160 //-------------------------------------------------//\r
161 case H_SPUirqAddr:\r
3154bfab 162 spu.pSpuIrq=spu.spuMemC+(((unsigned long) val<<3)&~0xf);\r
650adfd2 163 goto upd_irq;\r
ef79bbde
P
164 //-------------------------------------------------//\r
165 case H_SPUrvolL:\r
166 rvb.VolLeft=val;\r
167 break;\r
168 //-------------------------------------------------//\r
169 case H_SPUrvolR:\r
170 rvb.VolRight=val;\r
171 break;\r
172 //-------------------------------------------------//\r
173\r
174/*\r
175 case H_ExtLeft:\r
176 //auxprintf("EL %d\n",val);\r
177 break;\r
178 //-------------------------------------------------//\r
179 case H_ExtRight:\r
180 //auxprintf("ER %d\n",val);\r
181 break;\r
182 //-------------------------------------------------//\r
183 case H_SPUmvolL:\r
184 //auxprintf("ML %d\n",val);\r
185 break;\r
186 //-------------------------------------------------//\r
187 case H_SPUmvolR:\r
188 //auxprintf("MR %d\n",val);\r
189 break;\r
190 //-------------------------------------------------//\r
191 case H_SPUMute1:\r
192 //auxprintf("M0 %04x\n",val);\r
193 break;\r
194 //-------------------------------------------------//\r
195 case H_SPUMute2:\r
196 //auxprintf("M1 %04x\n",val);\r
197 break;\r
198*/\r
199 //-------------------------------------------------//\r
200 case H_SPUon1:\r
201 SoundOn(0,16,val);\r
202 break;\r
203 //-------------------------------------------------//\r
204 case H_SPUon2:\r
205 SoundOn(16,24,val);\r
206 break;\r
207 //-------------------------------------------------//\r
208 case H_SPUoff1:\r
209 SoundOff(0,16,val);\r
210 break;\r
211 //-------------------------------------------------//\r
212 case H_SPUoff2:\r
213 SoundOff(16,24,val);\r
214 break;\r
215 //-------------------------------------------------//\r
216 case H_CDLeft:\r
3154bfab 217 spu.iLeftXAVol=val & 0x7fff;\r
218 if(spu.cddavCallback) spu.cddavCallback(0,val);\r
ef79bbde
P
219 break;\r
220 case H_CDRight:\r
3154bfab 221 spu.iRightXAVol=val & 0x7fff;\r
222 if(spu.cddavCallback) spu.cddavCallback(1,val);\r
ef79bbde
P
223 break;\r
224 //-------------------------------------------------//\r
225 case H_FMod1:\r
226 FModOn(0,16,val);\r
227 break;\r
228 //-------------------------------------------------//\r
229 case H_FMod2:\r
230 FModOn(16,24,val);\r
231 break;\r
232 //-------------------------------------------------//\r
233 case H_Noise1:\r
234 NoiseOn(0,16,val);\r
235 break;\r
236 //-------------------------------------------------//\r
237 case H_Noise2:\r
238 NoiseOn(16,24,val);\r
239 break;\r
240 //-------------------------------------------------//\r
241 case H_RVBon1:\r
242 ReverbOn(0,16,val);\r
243 break;\r
244 //-------------------------------------------------//\r
245 case H_RVBon2:\r
246 ReverbOn(16,24,val);\r
247 break;\r
248 //-------------------------------------------------//\r
650adfd2 249 case H_Reverb+0 : rvb.FB_SRC_A=val*4; goto rvbd;\r
250 case H_Reverb+2 : rvb.FB_SRC_B=val*4; goto rvbd;\r
251 case H_Reverb+4 : rvb.IIR_ALPHA=(short)val; goto rvbd;\r
252 case H_Reverb+6 : rvb.ACC_COEF_A=(short)val; goto rvbd;\r
253 case H_Reverb+8 : rvb.ACC_COEF_B=(short)val; goto rvbd;\r
254 case H_Reverb+10 : rvb.ACC_COEF_C=(short)val; goto rvbd;\r
255 case H_Reverb+12 : rvb.ACC_COEF_D=(short)val; goto rvbd;\r
256 case H_Reverb+14 : rvb.IIR_COEF=(short)val; goto rvbd;\r
257 case H_Reverb+16 : rvb.FB_ALPHA=(short)val; goto rvbd;\r
258 case H_Reverb+18 : rvb.FB_X=(short)val; goto rvbd;\r
259 case H_Reverb+20 : rvb.IIR_DEST_A0=val*4; goto rvbd;\r
260 case H_Reverb+22 : rvb.IIR_DEST_A1=val*4; goto rvbd;\r
261 case H_Reverb+24 : rvb.ACC_SRC_A0=val*4; goto rvbd;\r
262 case H_Reverb+26 : rvb.ACC_SRC_A1=val*4; goto rvbd;\r
263 case H_Reverb+28 : rvb.ACC_SRC_B0=val*4; goto rvbd;\r
264 case H_Reverb+30 : rvb.ACC_SRC_B1=val*4; goto rvbd;\r
265 case H_Reverb+32 : rvb.IIR_SRC_A0=val*4; goto rvbd;\r
266 case H_Reverb+34 : rvb.IIR_SRC_A1=val*4; goto rvbd;\r
267 case H_Reverb+36 : rvb.IIR_DEST_B0=val*4; goto rvbd;\r
268 case H_Reverb+38 : rvb.IIR_DEST_B1=val*4; goto rvbd;\r
269 case H_Reverb+40 : rvb.ACC_SRC_C0=val*4; goto rvbd;\r
270 case H_Reverb+42 : rvb.ACC_SRC_C1=val*4; goto rvbd;\r
271 case H_Reverb+44 : rvb.ACC_SRC_D0=val*4; goto rvbd;\r
272 case H_Reverb+46 : rvb.ACC_SRC_D1=val*4; goto rvbd;\r
273 case H_Reverb+48 : rvb.IIR_SRC_B1=val*4; goto rvbd;\r
274 case H_Reverb+50 : rvb.IIR_SRC_B0=val*4; goto rvbd;\r
275 case H_Reverb+52 : rvb.MIX_DEST_A0=val*4; goto rvbd;\r
276 case H_Reverb+54 : rvb.MIX_DEST_A1=val*4; goto rvbd;\r
277 case H_Reverb+56 : rvb.MIX_DEST_B0=val*4; goto rvbd;\r
278 case H_Reverb+58 : rvb.MIX_DEST_B1=val*4; goto rvbd;\r
279 case H_Reverb+60 : rvb.IN_COEF_L=(short)val; goto rvbd;\r
280 case H_Reverb+62 : rvb.IN_COEF_R=(short)val; goto rvbd;\r
ef79bbde 281 }\r
650adfd2 282 return;\r
283\r
284upd_irq:\r
3154bfab 285 if (spu.spuCtrl & CTRL_IRQ)\r
650adfd2 286 schedule_next_irq();\r
287 return;\r
ef79bbde 288\r
650adfd2 289rvbd:\r
290 rvb.dirty = 1; // recalculate on next update\r
ef79bbde
P
291}\r
292\r
293////////////////////////////////////////////////////////////////////////\r
294// READ REGISTER: called by main emu\r
295////////////////////////////////////////////////////////////////////////\r
296\r
297unsigned short CALLBACK SPUreadRegister(unsigned long reg)\r
298{\r
299 const unsigned long r=reg&0xfff;\r
300 \r
ef79bbde
P
301 if(r>=0x0c00 && r<0x0d80)\r
302 {\r
303 switch(r&0x0f)\r
304 {\r
305 case 12: // get adsr vol\r
306 {\r
307 const int ch=(r>>4)-0xc0;\r
3154bfab 308 if(spu.dwNewChannel&(1<<ch)) return 1; // we are started, but not processed? return 1\r
309 if((spu.dwChannelOn&(1<<ch)) && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well\r
6d866bb7 310 !s_chan[ch].ADSRX.EnvelopeVol)\r
ef79bbde
P
311 return 1;\r
312 return (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16);\r
313 }\r
314\r
315 case 14: // get loop address\r
316 {\r
317 const int ch=(r>>4)-0xc0;\r
3154bfab 318 return (unsigned short)((s_chan[ch].pLoop-spu.spuMemC)>>3);\r
ef79bbde
P
319 }\r
320 }\r
321 }\r
322\r
323 switch(r)\r
324 {\r
325 case H_SPUctrl:\r
3154bfab 326 return spu.spuCtrl;\r
ef79bbde
P
327\r
328 case H_SPUstat:\r
3154bfab 329 return spu.spuStat;\r
ef79bbde
P
330 \r
331 case H_SPUaddr:\r
3154bfab 332 return (unsigned short)(spu.spuAddr>>3);\r
ef79bbde
P
333\r
334 case H_SPUdata:\r
335 {\r
3154bfab 336 unsigned short s=spu.spuMem[spu.spuAddr>>1];\r
337 spu.spuAddr+=2;\r
338 if(spu.spuAddr>0x7ffff) spu.spuAddr=0;\r
ef79bbde
P
339 return s;\r
340 }\r
341\r
ef79bbde
P
342 //case H_SPUIsOn1:\r
343 // return IsSoundOn(0,16);\r
344\r
345 //case H_SPUIsOn2:\r
346 // return IsSoundOn(16,24);\r
347 \r
348 }\r
349\r
3154bfab 350 return spu.regArea[(r-0xc00)>>1];\r
ef79bbde
P
351}\r
352 \r
353////////////////////////////////////////////////////////////////////////\r
354// SOUND ON register write\r
355////////////////////////////////////////////////////////////////////////\r
356\r
7e44d49d 357static void SoundOn(int start,int end,unsigned short val)\r
ef79bbde
P
358{\r
359 int ch;\r
360\r
361 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
362 {\r
77d6fd63 363 if((val&1) && regAreaGet(ch,6)) // mmm... start has to be set before key on !?!\r
ef79bbde 364 {\r
b00afb77 365 // do this here, not in StartSound\r
366 // - fixes fussy timing issues\r
367 s_chan[ch].bStop=0;\r
3154bfab 368 s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned\r
369 s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3);\r
e4f075af 370 s_chan[ch].prevflags=2;\r
b00afb77 371\r
3154bfab 372 spu.dwNewChannel|=(1<<ch);\r
373 spu.dwChannelOn|=1<<ch;\r
374 spu.dwChannelDead&=~(1<<ch);\r
ef79bbde
P
375 }\r
376 }\r
377}\r
378\r
379////////////////////////////////////////////////////////////////////////\r
380// SOUND OFF register write\r
381////////////////////////////////////////////////////////////////////////\r
382\r
7e44d49d 383static void SoundOff(int start,int end,unsigned short val)\r
ef79bbde
P
384{\r
385 int ch;\r
386 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
387 {\r
388 if(val&1) // && s_chan[i].bOn) mmm...\r
389 {\r
390 s_chan[ch].bStop=1;\r
b00afb77 391\r
392 // Jungle Book - Rhythm 'n Groove\r
393 // - turns off buzzing sound (loop hangs)\r
3154bfab 394 spu.dwNewChannel &= ~(1<<ch);\r
ef79bbde
P
395 } \r
396 }\r
397}\r
398\r
399////////////////////////////////////////////////////////////////////////\r
400// FMOD register write\r
401////////////////////////////////////////////////////////////////////////\r
402\r
7e44d49d 403static void FModOn(int start,int end,unsigned short val)\r
ef79bbde
P
404{\r
405 int ch;\r
406\r
407 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
408 {\r
409 if(val&1) // -> fmod on/off\r
410 {\r
411 if(ch>0) \r
412 {\r
413 s_chan[ch].bFMod=1; // --> sound channel\r
414 s_chan[ch-1].bFMod=2; // --> freq channel\r
415 }\r
416 }\r
417 else\r
418 {\r
419 s_chan[ch].bFMod=0; // --> turn off fmod\r
07a6dd2c 420 if(ch>0&&s_chan[ch-1].bFMod==2)\r
421 s_chan[ch-1].bFMod=0;\r
ef79bbde
P
422 }\r
423 }\r
424}\r
425\r
426////////////////////////////////////////////////////////////////////////\r
427// NOISE register write\r
428////////////////////////////////////////////////////////////////////////\r
429\r
7e44d49d 430static void NoiseOn(int start,int end,unsigned short val)\r
ef79bbde
P
431{\r
432 int ch;\r
433\r
434 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
435 {\r
6d866bb7 436 s_chan[ch].bNoise=val&1; // -> noise on/off\r
ef79bbde
P
437 }\r
438}\r
439\r
440////////////////////////////////////////////////////////////////////////\r
441// LEFT VOLUME register write\r
442////////////////////////////////////////////////////////////////////////\r
443\r
444// please note: sweep and phase invert are wrong... but I've never seen\r
445// them used\r
446\r
7e44d49d 447static void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME\r
ef79bbde 448{\r
ef79bbde
P
449 if(vol&0x8000) // sweep?\r
450 {\r
451 short sInc=1; // -> sweep up?\r
452 if(vol&0x2000) sInc=-1; // -> or down?\r
453 if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this\r
454 vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64\r
455 vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!\r
456 vol*=128;\r
457 }\r
458 else // no sweep:\r
459 {\r
460 if(vol&0x4000) // -> mmm... phase inverted? have to investigate this\r
461 //vol^=0xffff;\r
462 vol=0x3fff-(vol&0x3fff);\r
463 }\r
464\r
465 vol&=0x3fff;\r
466 s_chan[ch].iLeftVolume=vol; // store volume\r
467}\r
468\r
469////////////////////////////////////////////////////////////////////////\r
470// RIGHT VOLUME register write\r
471////////////////////////////////////////////////////////////////////////\r
472\r
7e44d49d 473static void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME\r
ef79bbde 474{\r
ef79bbde
P
475 if(vol&0x8000) // comments... see above :)\r
476 {\r
477 short sInc=1;\r
478 if(vol&0x2000) sInc=-1;\r
479 if(vol&0x1000) vol^=0xffff;\r
480 vol=((vol&0x7f)+1)/2; \r
481 vol+=vol/(2*sInc);\r
482 vol*=128;\r
483 }\r
484 else \r
485 {\r
486 if(vol&0x4000) //vol=vol^=0xffff;\r
487 vol=0x3fff-(vol&0x3fff);\r
488 }\r
489\r
490 vol&=0x3fff;\r
491\r
492 s_chan[ch].iRightVolume=vol;\r
493}\r
494\r
495////////////////////////////////////////////////////////////////////////\r
496// PITCH register write\r
497////////////////////////////////////////////////////////////////////////\r
498\r
7e44d49d 499static void SetPitch(int ch,unsigned short val) // SET PITCH\r
ef79bbde
P
500{\r
501 int NP;\r
502 if(val>0x3fff) NP=0x3fff; // get pitch val\r
503 else NP=val;\r
504\r
505 s_chan[ch].iRawPitch=NP;\r
7e44d49d 506 s_chan[ch].sinc=(NP<<4)|8;\r
650adfd2 507 s_chan[ch].sinc_inv=0;\r
3154bfab 508 if(spu_config.iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simple interpolation mode: set flag\r
ef79bbde
P
509}\r
510\r
511////////////////////////////////////////////////////////////////////////\r
512// REVERB register write\r
513////////////////////////////////////////////////////////////////////////\r
514\r
7e44d49d 515static void ReverbOn(int start,int end,unsigned short val)\r
ef79bbde
P
516{\r
517 int ch;\r
518\r
519 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
520 {\r
6d866bb7 521 s_chan[ch].bReverb=val&1; // -> reverb on/off\r
ef79bbde
P
522 }\r
523}\r