release r17
[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
ef79bbde 24\r
7e44d49d 25static void SoundOn(int start,int end,unsigned short val);\r
26static void SoundOff(int start,int end,unsigned short val);\r
27static void FModOn(int start,int end,unsigned short val);\r
28static void NoiseOn(int start,int end,unsigned short val);\r
29static void SetVolumeL(unsigned char ch,short vol);\r
30static void SetVolumeR(unsigned char ch,short vol);\r
31static void SetPitch(int ch,unsigned short val);\r
32static void ReverbOn(int start,int end,unsigned short val);\r
33\r
ef79bbde
P
34////////////////////////////////////////////////////////////////////////\r
35// WRITE REGISTERS: called by main emu\r
36////////////////////////////////////////////////////////////////////////\r
37\r
38void 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
7e44d49d 62 // taken from regArea later\r
ef79bbde
P
63 break;\r
64 //------------------------------------------------// level with pre-calcs\r
65 case 8:\r
66 {\r
6d866bb7 67 const unsigned long lval=val;\r
ef79bbde
P
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
ef79bbde
P
74 }\r
75 break;\r
76 //------------------------------------------------// adsr times with pre-calcs\r
77 case 10:\r
78 {\r
6d866bb7 79 const unsigned long lval=val;\r
ef79bbde
P
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
ef79bbde
P
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
7e44d49d 95 s_chan[ch].pLoop=spuMemC+((val&~1)<<3);\r
ef79bbde
P
96 break;\r
97 //------------------------------------------------//\r
98 }\r
ef79bbde
P
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
3fc2a4c2 116 if(!(spuCtrl & CTRL_IRQ))\r
117 spuStat&=~STAT_IRQ;\r
ef79bbde
P
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
b72f17a1 135 // sync-with-decode-buffers hack..\r
136 if(rvb.StartAddr==0x3ff00)\r
137 rvb.CurrAddr+=decode_pos/2;\r
ef79bbde
P
138 }\r
139 }\r
1775933a 140 rvb.dirty = 1;\r
ef79bbde
P
141 break;\r
142 //-------------------------------------------------//\r
143 case H_SPUirqAddr:\r
144 spuIrq = val;\r
3fc2a4c2 145 pSpuIrq=spuMemC+(((unsigned long) val<<3)&~0xf);\r
ef79bbde
P
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
1775933a 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
ef79bbde
P
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
1775933a 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
ef79bbde
P
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
1775933a 266 if ((r & ~0x3f) == H_Reverb)\r
267 rvb.dirty = 1; // recalculate on next update\r
ef79bbde
P
268}\r
269\r
270////////////////////////////////////////////////////////////////////////\r
271// READ REGISTER: called by main emu\r
272////////////////////////////////////////////////////////////////////////\r
273\r
274unsigned short CALLBACK SPUreadRegister(unsigned long reg)\r
275{\r
276 const unsigned long r=reg&0xfff;\r
277 \r
ef79bbde
P
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
6d866bb7 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
ef79bbde
P
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
ef79bbde
P
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
7e44d49d 337static void SoundOn(int start,int end,unsigned short val)\r
ef79bbde
P
338{\r
339 int ch;\r
340\r
341 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
342 {\r
77d6fd63 343 if((val&1) && regAreaGet(ch,6)) // mmm... start has to be set before key on !?!\r
ef79bbde 344 {\r
b00afb77 345 // do this here, not in StartSound\r
346 // - fixes fussy timing issues\r
347 s_chan[ch].bStop=0;\r
77d6fd63 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
e4f075af 350 s_chan[ch].prevflags=2;\r
b00afb77 351\r
ef79bbde 352 dwNewChannel|=(1<<ch); // bitfield for faster testing\r
6d866bb7 353 dwChannelOn|=1<<ch;\r
174c454a 354 dwChannelDead&=~(1<<ch);\r
ef79bbde
P
355 }\r
356 }\r
357}\r
358\r
359////////////////////////////////////////////////////////////////////////\r
360// SOUND OFF register write\r
361////////////////////////////////////////////////////////////////////////\r
362\r
7e44d49d 363static void SoundOff(int start,int end,unsigned short val)\r
ef79bbde
P
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
b00afb77 371\r
372 // Jungle Book - Rhythm 'n Groove\r
373 // - turns off buzzing sound (loop hangs)\r
b00afb77 374 dwNewChannel &= ~(1<<ch);\r
ef79bbde
P
375 } \r
376 }\r
377}\r
378\r
379////////////////////////////////////////////////////////////////////////\r
380// FMOD register write\r
381////////////////////////////////////////////////////////////////////////\r
382\r
7e44d49d 383static void FModOn(int start,int end,unsigned short val)\r
ef79bbde
P
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
07a6dd2c 400 if(ch>0&&s_chan[ch-1].bFMod==2)\r
401 s_chan[ch-1].bFMod=0;\r
ef79bbde
P
402 }\r
403 }\r
404}\r
405\r
406////////////////////////////////////////////////////////////////////////\r
407// NOISE register write\r
408////////////////////////////////////////////////////////////////////////\r
409\r
7e44d49d 410static void NoiseOn(int start,int end,unsigned short val)\r
ef79bbde
P
411{\r
412 int ch;\r
413\r
414 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
415 {\r
6d866bb7 416 s_chan[ch].bNoise=val&1; // -> noise on/off\r
ef79bbde
P
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
7e44d49d 427static void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME\r
ef79bbde 428{\r
ef79bbde
P
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
7e44d49d 453static void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME\r
ef79bbde 454{\r
ef79bbde
P
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
7e44d49d 479static void SetPitch(int ch,unsigned short val) // SET PITCH\r
ef79bbde
P
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
7e44d49d 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
ef79bbde
P
488}\r
489\r
490////////////////////////////////////////////////////////////////////////\r
491// REVERB register write\r
492////////////////////////////////////////////////////////////////////////\r
493\r
7e44d49d 494static void ReverbOn(int start,int end,unsigned short val)\r
ef79bbde
P
495{\r
496 int ch;\r
497\r
498 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
499 {\r
6d866bb7 500 s_chan[ch].bReverb=val&1; // -> reverb on/off\r
ef79bbde
P
501 }\r
502}\r