add some missing license headers
[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
63a4f6b6 60 do_samples_if_needed(cycles, 0);\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 87 //---------------------------------------------//\r
5514a050 88 spu.s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0;\r
89 spu.s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;\r
90 spu.s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;\r
91 spu.s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;\r
ef79bbde 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
5514a050 101 spu.s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;\r
102 spu.s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;\r
103 spu.s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;\r
104 spu.s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;\r
105 spu.s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;\r
ef79bbde 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
5514a050 114 spu.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
5514a050 129 *(unsigned short *)(spu.spuMemC + spu.spuAddr) = val;\r
130 spu.spuAddr += 2;\r
131 spu.spuAddr &= 0x7fffe;\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
650adfd2 148 goto rvbd;\r
ef79bbde
P
149 //-------------------------------------------------//\r
150 case H_SPUirqAddr:\r
3154bfab 151 spu.pSpuIrq=spu.spuMemC+(((unsigned long) val<<3)&~0xf);\r
650adfd2 152 goto upd_irq;\r
ef79bbde
P
153 //-------------------------------------------------//\r
154 case H_SPUrvolL:\r
05c7cec7 155 spu.rvb->VolLeft=val;\r
ef79bbde
P
156 break;\r
157 //-------------------------------------------------//\r
158 case H_SPUrvolR:\r
05c7cec7 159 spu.rvb->VolRight=val;\r
ef79bbde
P
160 break;\r
161 //-------------------------------------------------//\r
162\r
163/*\r
164 case H_ExtLeft:\r
165 //auxprintf("EL %d\n",val);\r
166 break;\r
167 //-------------------------------------------------//\r
168 case H_ExtRight:\r
169 //auxprintf("ER %d\n",val);\r
170 break;\r
171 //-------------------------------------------------//\r
172 case H_SPUmvolL:\r
173 //auxprintf("ML %d\n",val);\r
174 break;\r
175 //-------------------------------------------------//\r
176 case H_SPUmvolR:\r
177 //auxprintf("MR %d\n",val);\r
178 break;\r
179 //-------------------------------------------------//\r
180 case H_SPUMute1:\r
181 //auxprintf("M0 %04x\n",val);\r
182 break;\r
183 //-------------------------------------------------//\r
184 case H_SPUMute2:\r
185 //auxprintf("M1 %04x\n",val);\r
186 break;\r
187*/\r
188 //-------------------------------------------------//\r
189 case H_SPUon1:\r
190 SoundOn(0,16,val);\r
191 break;\r
192 //-------------------------------------------------//\r
193 case H_SPUon2:\r
194 SoundOn(16,24,val);\r
195 break;\r
196 //-------------------------------------------------//\r
197 case H_SPUoff1:\r
198 SoundOff(0,16,val);\r
199 break;\r
200 //-------------------------------------------------//\r
201 case H_SPUoff2:\r
202 SoundOff(16,24,val);\r
203 break;\r
204 //-------------------------------------------------//\r
205 case H_CDLeft:\r
3154bfab 206 spu.iLeftXAVol=val & 0x7fff;\r
207 if(spu.cddavCallback) spu.cddavCallback(0,val);\r
ef79bbde
P
208 break;\r
209 case H_CDRight:\r
3154bfab 210 spu.iRightXAVol=val & 0x7fff;\r
211 if(spu.cddavCallback) spu.cddavCallback(1,val);\r
ef79bbde
P
212 break;\r
213 //-------------------------------------------------//\r
214 case H_FMod1:\r
215 FModOn(0,16,val);\r
216 break;\r
217 //-------------------------------------------------//\r
218 case H_FMod2:\r
219 FModOn(16,24,val);\r
220 break;\r
221 //-------------------------------------------------//\r
222 case H_Noise1:\r
223 NoiseOn(0,16,val);\r
224 break;\r
225 //-------------------------------------------------//\r
226 case H_Noise2:\r
227 NoiseOn(16,24,val);\r
228 break;\r
229 //-------------------------------------------------//\r
230 case H_RVBon1:\r
231 ReverbOn(0,16,val);\r
232 break;\r
233 //-------------------------------------------------//\r
234 case H_RVBon2:\r
235 ReverbOn(16,24,val);\r
236 break;\r
237 //-------------------------------------------------//\r
7b2c4897 238 case H_Reverb+0 : goto rvbd;\r
239 case H_Reverb+2 : goto rvbd;\r
240 case H_Reverb+4 : spu.rvb->IIR_ALPHA=(short)val; break;\r
241 case H_Reverb+6 : spu.rvb->ACC_COEF_A=(short)val; break;\r
242 case H_Reverb+8 : spu.rvb->ACC_COEF_B=(short)val; break;\r
243 case H_Reverb+10 : spu.rvb->ACC_COEF_C=(short)val; break;\r
244 case H_Reverb+12 : spu.rvb->ACC_COEF_D=(short)val; break;\r
245 case H_Reverb+14 : spu.rvb->IIR_COEF=(short)val; break;\r
246 case H_Reverb+16 : spu.rvb->FB_ALPHA=(short)val; break;\r
247 case H_Reverb+18 : spu.rvb->FB_X=(short)val; break;\r
248 case H_Reverb+20 : goto rvbd;\r
249 case H_Reverb+22 : goto rvbd;\r
250 case H_Reverb+24 : goto rvbd;\r
251 case H_Reverb+26 : goto rvbd;\r
252 case H_Reverb+28 : goto rvbd;\r
253 case H_Reverb+30 : goto rvbd;\r
254 case H_Reverb+32 : goto rvbd;\r
255 case H_Reverb+34 : goto rvbd;\r
256 case H_Reverb+36 : goto rvbd;\r
257 case H_Reverb+38 : goto rvbd;\r
258 case H_Reverb+40 : goto rvbd;\r
259 case H_Reverb+42 : goto rvbd;\r
260 case H_Reverb+44 : goto rvbd;\r
261 case H_Reverb+46 : goto rvbd;\r
262 case H_Reverb+48 : goto rvbd;\r
263 case H_Reverb+50 : goto rvbd;\r
264 case H_Reverb+52 : goto rvbd;\r
265 case H_Reverb+54 : goto rvbd;\r
266 case H_Reverb+56 : goto rvbd;\r
267 case H_Reverb+58 : goto rvbd;\r
268 case H_Reverb+60 : spu.rvb->IN_COEF_L=(short)val; break;\r
269 case H_Reverb+62 : spu.rvb->IN_COEF_R=(short)val; break;\r
ef79bbde 270 }\r
650adfd2 271 return;\r
272\r
273upd_irq:\r
3154bfab 274 if (spu.spuCtrl & CTRL_IRQ)\r
650adfd2 275 schedule_next_irq();\r
276 return;\r
ef79bbde 277\r
650adfd2 278rvbd:\r
05c7cec7 279 spu.rvb->dirty = 1; // recalculate on next update\r
ef79bbde
P
280}\r
281\r
282////////////////////////////////////////////////////////////////////////\r
283// READ REGISTER: called by main emu\r
284////////////////////////////////////////////////////////////////////////\r
285\r
286unsigned short CALLBACK SPUreadRegister(unsigned long reg)\r
287{\r
288 const unsigned long r=reg&0xfff;\r
289 \r
ef79bbde
P
290 if(r>=0x0c00 && r<0x0d80)\r
291 {\r
292 switch(r&0x0f)\r
293 {\r
294 case 12: // get adsr vol\r
295 {\r
296 const int ch=(r>>4)-0xc0;\r
3154bfab 297 if(spu.dwNewChannel&(1<<ch)) return 1; // we are started, but not processed? return 1\r
298 if((spu.dwChannelOn&(1<<ch)) && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well\r
5514a050 299 !spu.s_chan[ch].ADSRX.EnvelopeVol)\r
ef79bbde 300 return 1;\r
5514a050 301 return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol>>16);\r
ef79bbde
P
302 }\r
303\r
304 case 14: // get loop address\r
305 {\r
306 const int ch=(r>>4)-0xc0;\r
5514a050 307 return (unsigned short)((spu.s_chan[ch].pLoop-spu.spuMemC)>>3);\r
ef79bbde
P
308 }\r
309 }\r
310 }\r
311\r
312 switch(r)\r
313 {\r
314 case H_SPUctrl:\r
3154bfab 315 return spu.spuCtrl;\r
ef79bbde
P
316\r
317 case H_SPUstat:\r
3154bfab 318 return spu.spuStat;\r
ef79bbde
P
319 \r
320 case H_SPUaddr:\r
3154bfab 321 return (unsigned short)(spu.spuAddr>>3);\r
ef79bbde
P
322\r
323 case H_SPUdata:\r
324 {\r
5514a050 325 unsigned short s = *(unsigned short *)(spu.spuMemC + spu.spuAddr);\r
326 spu.spuAddr += 2;\r
327 spu.spuAddr &= 0x7fffe;\r
ef79bbde
P
328 return s;\r
329 }\r
330\r
ef79bbde
P
331 //case H_SPUIsOn1:\r
332 // return IsSoundOn(0,16);\r
333\r
334 //case H_SPUIsOn2:\r
335 // return IsSoundOn(16,24);\r
336 \r
337 }\r
338\r
3154bfab 339 return spu.regArea[(r-0xc00)>>1];\r
ef79bbde
P
340}\r
341 \r
342////////////////////////////////////////////////////////////////////////\r
343// SOUND ON register write\r
344////////////////////////////////////////////////////////////////////////\r
345\r
7e44d49d 346static void SoundOn(int start,int end,unsigned short val)\r
ef79bbde
P
347{\r
348 int ch;\r
349\r
350 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
351 {\r
77d6fd63 352 if((val&1) && regAreaGet(ch,6)) // mmm... start has to be set before key on !?!\r
ef79bbde 353 {\r
5514a050 354 spu.s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned\r
210476c7 355 if (spu_config.idiablofix == 0) spu.s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3);\r
3154bfab 356 spu.dwNewChannel|=(1<<ch);\r
ef79bbde
P
357 }\r
358 }\r
359}\r
360\r
361////////////////////////////////////////////////////////////////////////\r
362// SOUND OFF register write\r
363////////////////////////////////////////////////////////////////////////\r
364\r
7e44d49d 365static void SoundOff(int start,int end,unsigned short val)\r
ef79bbde
P
366{\r
367 int ch;\r
368 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
369 {\r
9ad8abfa 370 if(val&1)\r
ef79bbde 371 {\r
5514a050 372 spu.s_chan[ch].ADSRX.State = ADSR_RELEASE;\r
b00afb77 373\r
374 // Jungle Book - Rhythm 'n Groove\r
375 // - turns off buzzing sound (loop hangs)\r
3154bfab 376 spu.dwNewChannel &= ~(1<<ch);\r
ef79bbde
P
377 } \r
378 }\r
379}\r
380\r
381////////////////////////////////////////////////////////////////////////\r
382// FMOD register write\r
383////////////////////////////////////////////////////////////////////////\r
384\r
7e44d49d 385static void FModOn(int start,int end,unsigned short val)\r
ef79bbde
P
386{\r
387 int ch;\r
388\r
389 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
390 {\r
391 if(val&1) // -> fmod on/off\r
392 {\r
393 if(ch>0) \r
394 {\r
5514a050 395 spu.s_chan[ch].bFMod=1; // --> sound channel\r
396 spu.s_chan[ch-1].bFMod=2; // --> freq channel\r
ef79bbde
P
397 }\r
398 }\r
399 else\r
400 {\r
5514a050 401 spu.s_chan[ch].bFMod=0; // --> turn off fmod\r
402 if(ch>0&&spu.s_chan[ch-1].bFMod==2)\r
403 spu.s_chan[ch-1].bFMod=0;\r
ef79bbde
P
404 }\r
405 }\r
406}\r
407\r
408////////////////////////////////////////////////////////////////////////\r
409// NOISE register write\r
410////////////////////////////////////////////////////////////////////////\r
411\r
7e44d49d 412static void NoiseOn(int start,int end,unsigned short val)\r
ef79bbde
P
413{\r
414 int ch;\r
415\r
416 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
417 {\r
5514a050 418 spu.s_chan[ch].bNoise=val&1; // -> noise on/off\r
ef79bbde
P
419 }\r
420}\r
421\r
422////////////////////////////////////////////////////////////////////////\r
423// LEFT VOLUME register write\r
424////////////////////////////////////////////////////////////////////////\r
425\r
426// please note: sweep and phase invert are wrong... but I've never seen\r
427// them used\r
428\r
7e44d49d 429static void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME\r
ef79bbde 430{\r
ef79bbde
P
431 if(vol&0x8000) // sweep?\r
432 {\r
433 short sInc=1; // -> sweep up?\r
434 if(vol&0x2000) sInc=-1; // -> or down?\r
435 if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this\r
436 vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64\r
437 vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!\r
438 vol*=128;\r
439 }\r
440 else // no sweep:\r
441 {\r
442 if(vol&0x4000) // -> mmm... phase inverted? have to investigate this\r
443 //vol^=0xffff;\r
444 vol=0x3fff-(vol&0x3fff);\r
445 }\r
446\r
447 vol&=0x3fff;\r
5514a050 448 spu.s_chan[ch].iLeftVolume=vol; // store volume\r
ef79bbde
P
449}\r
450\r
451////////////////////////////////////////////////////////////////////////\r
452// RIGHT VOLUME register write\r
453////////////////////////////////////////////////////////////////////////\r
454\r
7e44d49d 455static void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME\r
ef79bbde 456{\r
ef79bbde
P
457 if(vol&0x8000) // comments... see above :)\r
458 {\r
459 short sInc=1;\r
460 if(vol&0x2000) sInc=-1;\r
461 if(vol&0x1000) vol^=0xffff;\r
462 vol=((vol&0x7f)+1)/2; \r
463 vol+=vol/(2*sInc);\r
464 vol*=128;\r
465 }\r
466 else \r
467 {\r
468 if(vol&0x4000) //vol=vol^=0xffff;\r
469 vol=0x3fff-(vol&0x3fff);\r
470 }\r
471\r
472 vol&=0x3fff;\r
473\r
5514a050 474 spu.s_chan[ch].iRightVolume=vol;\r
ef79bbde
P
475}\r
476\r
477////////////////////////////////////////////////////////////////////////\r
478// PITCH register write\r
479////////////////////////////////////////////////////////////////////////\r
480\r
7e44d49d 481static void SetPitch(int ch,unsigned short val) // SET PITCH\r
ef79bbde
P
482{\r
483 int NP;\r
484 if(val>0x3fff) NP=0x3fff; // get pitch val\r
485 else NP=val;\r
486\r
5514a050 487 spu.s_chan[ch].iRawPitch=NP;\r
488 spu.s_chan[ch].sinc=(NP<<4)|8;\r
489 spu.s_chan[ch].sinc_inv=0;\r
de4a0279 490 if (spu_config.iUseInterpolation == 1)\r
491 spu.SB[ch * SB_SIZE + 32] = 1; // -> freq change in simple interpolation mode: set flag\r
ef79bbde
P
492}\r
493\r
494////////////////////////////////////////////////////////////////////////\r
495// REVERB register write\r
496////////////////////////////////////////////////////////////////////////\r
497\r
7e44d49d 498static void ReverbOn(int start,int end,unsigned short val)\r
ef79bbde
P
499{\r
500 int ch;\r
501\r
502 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
503 {\r
5514a050 504 spu.s_chan[ch].bReverb=val&1; // -> reverb on/off\r
ef79bbde
P
505 }\r
506}\r