drc: replace unused reg32 with new reg_sv_flags
[pcsx_rearmed.git] / plugins / dfsound / registers.c
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
24 #include "spu_config.h"\r
25 \r
26 static void SoundOn(int start,int end,unsigned short val);\r
27 static void SoundOff(int start,int end,unsigned short val);\r
28 static void FModOn(int start,int end,unsigned short val);\r
29 static void NoiseOn(int start,int end,unsigned short val);\r
30 static void SetVolumeL(unsigned char ch,short vol);\r
31 static void SetVolumeR(unsigned char ch,short vol);\r
32 static void SetPitch(int ch,unsigned short val);\r
33 static void ReverbOn(int start,int end,unsigned short val);\r
34 \r
35 ////////////////////////////////////////////////////////////////////////\r
36 // WRITE REGISTERS: called by main emu\r
37 ////////////////////////////////////////////////////////////////////////\r
38 \r
39 static 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
46 void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,\r
47  unsigned int cycles)\r
48 {\r
49  int r = reg & 0xfff;\r
50  int rofs = (r - 0xc00) >> 1;\r
51  int changed = spu.regArea[rofs] != val;\r
52  spu.regArea[rofs] = val;\r
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
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
78        goto upd_irq;\r
79      //------------------------------------------------// start\r
80      case 6:      \r
81        // taken from regArea later\r
82        break;\r
83      //------------------------------------------------// level with pre-calcs\r
84      case 8:\r
85        {\r
86         const unsigned long lval=val;\r
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
93        }\r
94       break;\r
95      //------------------------------------------------// adsr times with pre-calcs\r
96      case 10:\r
97       {\r
98        const unsigned long lval=val;\r
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
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
114        s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
115        goto upd_irq;\r
116      //------------------------------------------------//\r
117     }\r
118    return;\r
119   }\r
120 \r
121  switch(r)\r
122    {\r
123     //-------------------------------------------------//\r
124     case H_SPUaddr:\r
125       spu.spuAddr = (unsigned long) val<<3;\r
126       break;\r
127     //-------------------------------------------------//\r
128     case H_SPUdata:\r
129       spu.spuMem[spu.spuAddr>>1] = val;\r
130       spu.spuAddr+=2;\r
131       if(spu.spuAddr>0x7ffff) spu.spuAddr=0;\r
132       break;\r
133     //-------------------------------------------------//\r
134     case H_SPUctrl:\r
135       if (!(spu.spuCtrl & CTRL_IRQ)) {\r
136         spu.spuStat&=~STAT_IRQ;\r
137         if (val & CTRL_IRQ)\r
138          schedule_next_irq();\r
139       }\r
140       spu.spuCtrl=val;\r
141       break;\r
142     //-------------------------------------------------//\r
143     case H_SPUstat:\r
144       spu.spuStat=val&0xf800;\r
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
159       goto rvbd;\r
160     //-------------------------------------------------//\r
161     case H_SPUirqAddr:\r
162       spu.pSpuIrq=spu.spuMemC+(((unsigned long) val<<3)&~0xf);\r
163       goto upd_irq;\r
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
217       spu.iLeftXAVol=val  & 0x7fff;\r
218       if(spu.cddavCallback) spu.cddavCallback(0,val);\r
219       break;\r
220     case H_CDRight:\r
221       spu.iRightXAVol=val & 0x7fff;\r
222       if(spu.cddavCallback) spu.cddavCallback(1,val);\r
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
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
281    }\r
282  return;\r
283 \r
284 upd_irq:\r
285  if (spu.spuCtrl & CTRL_IRQ)\r
286   schedule_next_irq();\r
287  return;\r
288 \r
289 rvbd:\r
290  rvb.dirty = 1; // recalculate on next update\r
291 }\r
292 \r
293 ////////////////////////////////////////////////////////////////////////\r
294 // READ REGISTER: called by main emu\r
295 ////////////////////////////////////////////////////////////////////////\r
296 \r
297 unsigned short CALLBACK SPUreadRegister(unsigned long reg)\r
298 {\r
299  const unsigned long r=reg&0xfff;\r
300         \r
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
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
310           !s_chan[ch].ADSRX.EnvelopeVol)\r
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
318        return (unsigned short)((s_chan[ch].pLoop-spu.spuMemC)>>3);\r
319       }\r
320     }\r
321   }\r
322 \r
323  switch(r)\r
324   {\r
325     case H_SPUctrl:\r
326      return spu.spuCtrl;\r
327 \r
328     case H_SPUstat:\r
329      return spu.spuStat;\r
330         \r
331     case H_SPUaddr:\r
332      return (unsigned short)(spu.spuAddr>>3);\r
333 \r
334     case H_SPUdata:\r
335      {\r
336       unsigned short s=spu.spuMem[spu.spuAddr>>1];\r
337       spu.spuAddr+=2;\r
338       if(spu.spuAddr>0x7ffff) spu.spuAddr=0;\r
339       return s;\r
340      }\r
341 \r
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
350  return spu.regArea[(r-0xc00)>>1];\r
351 }\r
352  \r
353 ////////////////////////////////////////////////////////////////////////\r
354 // SOUND ON register write\r
355 ////////////////////////////////////////////////////////////////////////\r
356 \r
357 static void SoundOn(int start,int end,unsigned short val)\r
358 {\r
359  int ch;\r
360 \r
361  for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
362   {\r
363    if((val&1) && regAreaGet(ch,6))                     // mmm... start has to be set before key on !?!\r
364     {\r
365      // do this here, not in StartSound\r
366      // - fixes fussy timing issues\r
367      s_chan[ch].bStop=0;\r
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
370      s_chan[ch].prevflags=2;\r
371 \r
372      spu.dwNewChannel|=(1<<ch);\r
373      spu.dwChannelOn|=1<<ch;\r
374      spu.dwChannelDead&=~(1<<ch);\r
375     }\r
376   }\r
377 }\r
378 \r
379 ////////////////////////////////////////////////////////////////////////\r
380 // SOUND OFF register write\r
381 ////////////////////////////////////////////////////////////////////////\r
382 \r
383 static void SoundOff(int start,int end,unsigned short val)\r
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
391 \r
392      // Jungle Book - Rhythm 'n Groove\r
393      // - turns off buzzing sound (loop hangs)\r
394      spu.dwNewChannel &= ~(1<<ch);\r
395     }                                                  \r
396   }\r
397 }\r
398 \r
399 ////////////////////////////////////////////////////////////////////////\r
400 // FMOD register write\r
401 ////////////////////////////////////////////////////////////////////////\r
402 \r
403 static void FModOn(int start,int end,unsigned short val)\r
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
420      if(ch>0&&s_chan[ch-1].bFMod==2)\r
421       s_chan[ch-1].bFMod=0;\r
422     }\r
423   }\r
424 }\r
425 \r
426 ////////////////////////////////////////////////////////////////////////\r
427 // NOISE register write\r
428 ////////////////////////////////////////////////////////////////////////\r
429 \r
430 static void NoiseOn(int start,int end,unsigned short val)\r
431 {\r
432  int ch;\r
433 \r
434  for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
435   {\r
436    s_chan[ch].bNoise=val&1;                            // -> noise on/off\r
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
447 static void SetVolumeL(unsigned char ch,short vol)     // LEFT VOLUME\r
448 {\r
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
473 static void SetVolumeR(unsigned char ch,short vol)     // RIGHT VOLUME\r
474 {\r
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
499 static void SetPitch(int ch,unsigned short val)               // SET PITCH\r
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
506  s_chan[ch].sinc=(NP<<4)|8;\r
507  s_chan[ch].sinc_inv=0;\r
508  if(spu_config.iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simple interpolation mode: set flag\r
509 }\r
510 \r
511 ////////////////////////////////////////////////////////////////////////\r
512 // REVERB register write\r
513 ////////////////////////////////////////////////////////////////////////\r
514 \r
515 static void ReverbOn(int start,int end,unsigned short val)\r
516 {\r
517  int ch;\r
518 \r
519  for(ch=start;ch<end;ch++,val>>=1)                     // loop channels\r
520   {\r
521    s_chan[ch].bReverb=val&1;                           // -> reverb on/off\r
522   }\r
523 }\r