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