gpu_unai: avoid useless blits
[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
24#include "regs.h"\r
25#include "reverb.h"\r
26\r
27/*\r
28// adsr time values (in ms) by James Higgs ... see the end of\r
29// the adsr.c source for details\r
30\r
31#define ATTACK_MS 514L\r
32#define DECAYHALF_MS 292L\r
33#define DECAY_MS 584L\r
34#define SUSTAIN_MS 450L\r
35#define RELEASE_MS 446L\r
36*/\r
37\r
38// we have a timebase of 1.020408f ms, not 1 ms... so adjust adsr defines\r
39#define ATTACK_MS 494L\r
40#define DECAYHALF_MS 286L\r
41#define DECAY_MS 572L\r
42#define SUSTAIN_MS 441L\r
43#define RELEASE_MS 437L\r
44\r
45////////////////////////////////////////////////////////////////////////\r
46// WRITE REGISTERS: called by main emu\r
47////////////////////////////////////////////////////////////////////////\r
48\r
49void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val)\r
50{\r
51 const unsigned long r=reg&0xfff;\r
52 regArea[(r-0xc00)>>1] = val;\r
53\r
54 if(r>=0x0c00 && r<0x0d80) // some channel info?\r
55 {\r
56 int ch=(r>>4)-0xc0; // calc channel\r
57 switch(r&0x0f)\r
58 {\r
59 //------------------------------------------------// r volume\r
60 case 0: \r
61 SetVolumeL((unsigned char)ch,val);\r
62 break;\r
63 //------------------------------------------------// l volume\r
64 case 2: \r
65 SetVolumeR((unsigned char)ch,val);\r
66 break;\r
67 //------------------------------------------------// pitch\r
68 case 4: \r
69 SetPitch(ch,val);\r
70 break;\r
71 //------------------------------------------------// start\r
72 case 6: \r
73 s_chan[ch].pStart=spuMemC+((unsigned long) val<<3);\r
74 break;\r
75 //------------------------------------------------// level with pre-calcs\r
76 case 8:\r
77 {\r
78 const unsigned long lval=val;unsigned long lx;\r
79 //---------------------------------------------//\r
80 s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; \r
81 s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;\r
82 s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;\r
83 s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;\r
84 //---------------------------------------------//\r
85 if(!iDebugMode) break;\r
86 //---------------------------------------------// stuff below is only for debug mode\r
87\r
88 s_chan[ch].ADSR.AttackModeExp=(lval&0x8000)?1:0; //0x007f\r
89\r
90 lx=(((lval>>8) & 0x007f)>>2); // attack time to run from 0 to 100% volume\r
91 lx=min(31,lx); // no overflow on shift!\r
92 if(lx) \r
93 { \r
94 lx = (1<<lx);\r
95 if(lx<2147483) lx=(lx*ATTACK_MS)/10000L; // another overflow check\r
96 else lx=(lx/10000L)*ATTACK_MS;\r
97 if(!lx) lx=1;\r
98 }\r
99 s_chan[ch].ADSR.AttackTime=lx; \r
100\r
101 s_chan[ch].ADSR.SustainLevel= // our adsr vol runs from 0 to 1024, so scale the sustain level\r
102 (1024*((lval) & 0x000f))/15;\r
103\r
104 lx=(lval>>4) & 0x000f; // decay:\r
105 if(lx) // our const decay value is time it takes from 100% to 0% of volume\r
106 {\r
107 lx = ((1<<(lx))*DECAY_MS)/10000L;\r
108 if(!lx) lx=1;\r
109 }\r
110 s_chan[ch].ADSR.DecayTime = // so calc how long does it take to run from 100% to the wanted sus level\r
111 (lx*(1024-s_chan[ch].ADSR.SustainLevel))/1024;\r
112 }\r
113 break;\r
114 //------------------------------------------------// adsr times with pre-calcs\r
115 case 10:\r
116 {\r
117 const unsigned long lval=val;unsigned long lx;\r
118\r
119 //----------------------------------------------//\r
120 s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;\r
121 s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;\r
122 s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;\r
123 s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;\r
124 s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;\r
125 //----------------------------------------------//\r
126 if(!iDebugMode) break;\r
127 //----------------------------------------------// stuff below is only for debug mode\r
128\r
129 s_chan[ch].ADSR.SustainModeExp = (lval&0x8000)?1:0;\r
130 s_chan[ch].ADSR.ReleaseModeExp = (lval&0x0020)?1:0;\r
131 \r
132 lx=((((lval>>6) & 0x007f)>>2)); // sustain time... often very high\r
133 lx=min(31,lx); // values are used to hold the volume\r
134 if(lx) // until a sound stop occurs\r
135 { // the highest value we reach (due to \r
136 lx = (1<<lx); // overflow checking) is: \r
137 if(lx<2147483) lx=(lx*SUSTAIN_MS)/10000L; // 94704 seconds = 1578 minutes = 26 hours... \r
138 else lx=(lx/10000L)*SUSTAIN_MS; // should be enuff... if the stop doesn't \r
139 if(!lx) lx=1; // come in this time span, I don't care :)\r
140 }\r
141 s_chan[ch].ADSR.SustainTime = lx;\r
142\r
143 lx=(lval & 0x001f);\r
144 s_chan[ch].ADSR.ReleaseVal =lx;\r
145 if(lx) // release time from 100% to 0%\r
146 { // note: the release time will be\r
147 lx = (1<<lx); // adjusted when a stop is coming,\r
148 if(lx<2147483) lx=(lx*RELEASE_MS)/10000L; // so at this time the adsr vol will \r
149 else lx=(lx/10000L)*RELEASE_MS; // run from (current volume) to 0%\r
150 if(!lx) lx=1;\r
151 }\r
152 s_chan[ch].ADSR.ReleaseTime=lx;\r
153\r
154 if(lval & 0x4000) // add/dec flag\r
155 s_chan[ch].ADSR.SustainModeDec=-1;\r
156 else s_chan[ch].ADSR.SustainModeDec=1;\r
157 }\r
158 break;\r
159 //------------------------------------------------// adsr volume... mmm have to investigate this\r
160 case 12:\r
161 break;\r
162 //------------------------------------------------//\r
163 case 14: // loop?\r
164 //WaitForSingleObject(s_chan[ch].hMutex,2000); // -> no multithread fuckups\r
165 s_chan[ch].pLoop=spuMemC+((unsigned long) val<<3);\r
166 s_chan[ch].bIgnoreLoop=1;\r
167 //ReleaseMutex(s_chan[ch].hMutex); // -> oki, on with the thread\r
168 break;\r
169 //------------------------------------------------//\r
170 }\r
171 iSpuAsyncWait=0;\r
172 return;\r
173 }\r
174\r
175 switch(r)\r
176 {\r
177 //-------------------------------------------------//\r
178 case H_SPUaddr:\r
179 spuAddr = (unsigned long) val<<3;\r
180 break;\r
181 //-------------------------------------------------//\r
182 case H_SPUdata:\r
183 spuMem[spuAddr>>1] = val;\r
184 spuAddr+=2;\r
185 if(spuAddr>0x7ffff) spuAddr=0;\r
186 break;\r
187 //-------------------------------------------------//\r
188 case H_SPUctrl:\r
189 spuCtrl=val;\r
190 break;\r
191 //-------------------------------------------------//\r
192 case H_SPUstat:\r
193 spuStat=val & 0xf800;\r
194 break;\r
195 //-------------------------------------------------//\r
196 case H_SPUReverbAddr:\r
197 if(val==0xFFFF || val<=0x200)\r
198 {rvb.StartAddr=rvb.CurrAddr=0;}\r
199 else\r
200 {\r
201 const long iv=(unsigned long)val<<2;\r
202 if(rvb.StartAddr!=iv)\r
203 {\r
204 rvb.StartAddr=(unsigned long)val<<2;\r
205 rvb.CurrAddr=rvb.StartAddr;\r
206 }\r
207 }\r
208 break;\r
209 //-------------------------------------------------//\r
210 case H_SPUirqAddr:\r
211 spuIrq = val;\r
212 pSpuIrq=spuMemC+((unsigned long) val<<3);\r
213 break;\r
214 //-------------------------------------------------//\r
215 case H_SPUrvolL:\r
216 rvb.VolLeft=val;\r
217 break;\r
218 //-------------------------------------------------//\r
219 case H_SPUrvolR:\r
220 rvb.VolRight=val;\r
221 break;\r
222 //-------------------------------------------------//\r
223\r
224/*\r
225 case H_ExtLeft:\r
226 //auxprintf("EL %d\n",val);\r
227 break;\r
228 //-------------------------------------------------//\r
229 case H_ExtRight:\r
230 //auxprintf("ER %d\n",val);\r
231 break;\r
232 //-------------------------------------------------//\r
233 case H_SPUmvolL:\r
234 //auxprintf("ML %d\n",val);\r
235 break;\r
236 //-------------------------------------------------//\r
237 case H_SPUmvolR:\r
238 //auxprintf("MR %d\n",val);\r
239 break;\r
240 //-------------------------------------------------//\r
241 case H_SPUMute1:\r
242 //auxprintf("M0 %04x\n",val);\r
243 break;\r
244 //-------------------------------------------------//\r
245 case H_SPUMute2:\r
246 //auxprintf("M1 %04x\n",val);\r
247 break;\r
248*/\r
249 //-------------------------------------------------//\r
250 case H_SPUon1:\r
251 SoundOn(0,16,val);\r
252 break;\r
253 //-------------------------------------------------//\r
254 case H_SPUon2:\r
255 SoundOn(16,24,val);\r
256 break;\r
257 //-------------------------------------------------//\r
258 case H_SPUoff1:\r
259 SoundOff(0,16,val);\r
260 break;\r
261 //-------------------------------------------------//\r
262 case H_SPUoff2:\r
263 SoundOff(16,24,val);\r
264 break;\r
265 //-------------------------------------------------//\r
266 case H_CDLeft:\r
267 iLeftXAVol=val & 0x7fff;\r
268 if(cddavCallback) cddavCallback(0,val);\r
269 break;\r
270 case H_CDRight:\r
271 iRightXAVol=val & 0x7fff;\r
272 if(cddavCallback) cddavCallback(1,val);\r
273 break;\r
274 //-------------------------------------------------//\r
275 case H_FMod1:\r
276 FModOn(0,16,val);\r
277 break;\r
278 //-------------------------------------------------//\r
279 case H_FMod2:\r
280 FModOn(16,24,val);\r
281 break;\r
282 //-------------------------------------------------//\r
283 case H_Noise1:\r
284 NoiseOn(0,16,val);\r
285 break;\r
286 //-------------------------------------------------//\r
287 case H_Noise2:\r
288 NoiseOn(16,24,val);\r
289 break;\r
290 //-------------------------------------------------//\r
291 case H_RVBon1:\r
292 ReverbOn(0,16,val);\r
293 break;\r
294 //-------------------------------------------------//\r
295 case H_RVBon2:\r
296 ReverbOn(16,24,val);\r
297 break;\r
298 //-------------------------------------------------//\r
299 case H_Reverb+0:\r
300\r
301 rvb.FB_SRC_A=val;\r
302\r
303 // OK, here's the fake REVERB stuff...\r
304 // depending on effect we do more or less delay and repeats... bah\r
305 // still... better than nothing :)\r
306\r
307 SetREVERB(val);\r
308 break;\r
309\r
310\r
311 case H_Reverb+2 : rvb.FB_SRC_B=(short)val; break;\r
312 case H_Reverb+4 : rvb.IIR_ALPHA=(short)val; break;\r
313 case H_Reverb+6 : rvb.ACC_COEF_A=(short)val; break;\r
314 case H_Reverb+8 : rvb.ACC_COEF_B=(short)val; break;\r
315 case H_Reverb+10 : rvb.ACC_COEF_C=(short)val; break;\r
316 case H_Reverb+12 : rvb.ACC_COEF_D=(short)val; break;\r
317 case H_Reverb+14 : rvb.IIR_COEF=(short)val; break;\r
318 case H_Reverb+16 : rvb.FB_ALPHA=(short)val; break;\r
319 case H_Reverb+18 : rvb.FB_X=(short)val; break;\r
320 case H_Reverb+20 : rvb.IIR_DEST_A0=(short)val; break;\r
321 case H_Reverb+22 : rvb.IIR_DEST_A1=(short)val; break;\r
322 case H_Reverb+24 : rvb.ACC_SRC_A0=(short)val; break;\r
323 case H_Reverb+26 : rvb.ACC_SRC_A1=(short)val; break;\r
324 case H_Reverb+28 : rvb.ACC_SRC_B0=(short)val; break;\r
325 case H_Reverb+30 : rvb.ACC_SRC_B1=(short)val; break;\r
326 case H_Reverb+32 : rvb.IIR_SRC_A0=(short)val; break;\r
327 case H_Reverb+34 : rvb.IIR_SRC_A1=(short)val; break;\r
328 case H_Reverb+36 : rvb.IIR_DEST_B0=(short)val; break;\r
329 case H_Reverb+38 : rvb.IIR_DEST_B1=(short)val; break;\r
330 case H_Reverb+40 : rvb.ACC_SRC_C0=(short)val; break;\r
331 case H_Reverb+42 : rvb.ACC_SRC_C1=(short)val; break;\r
332 case H_Reverb+44 : rvb.ACC_SRC_D0=(short)val; break;\r
333 case H_Reverb+46 : rvb.ACC_SRC_D1=(short)val; break;\r
334 case H_Reverb+48 : rvb.IIR_SRC_B1=(short)val; break;\r
335 case H_Reverb+50 : rvb.IIR_SRC_B0=(short)val; break;\r
336 case H_Reverb+52 : rvb.MIX_DEST_A0=(short)val; break;\r
337 case H_Reverb+54 : rvb.MIX_DEST_A1=(short)val; break;\r
338 case H_Reverb+56 : rvb.MIX_DEST_B0=(short)val; break;\r
339 case H_Reverb+58 : rvb.MIX_DEST_B1=(short)val; break;\r
340 case H_Reverb+60 : rvb.IN_COEF_L=(short)val; break;\r
341 case H_Reverb+62 : rvb.IN_COEF_R=(short)val; break;\r
342 }\r
343\r
344 iSpuAsyncWait=0;\r
345}\r
346\r
347////////////////////////////////////////////////////////////////////////\r
348// READ REGISTER: called by main emu\r
349////////////////////////////////////////////////////////////////////////\r
350\r
351unsigned short CALLBACK SPUreadRegister(unsigned long reg)\r
352{\r
353 const unsigned long r=reg&0xfff;\r
354 \r
355 iSpuAsyncWait=0;\r
356\r
357 if(r>=0x0c00 && r<0x0d80)\r
358 {\r
359 switch(r&0x0f)\r
360 {\r
361 case 12: // get adsr vol\r
362 {\r
363 const int ch=(r>>4)-0xc0;\r
364 if(s_chan[ch].bNew) return 1; // we are started, but not processed? return 1\r
365 if(s_chan[ch].ADSRX.lVolume && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well\r
366 !s_chan[ch].ADSRX.EnvelopeVol) \r
367 return 1;\r
368 return (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16);\r
369 }\r
370\r
371 case 14: // get loop address\r
372 {\r
373 const int ch=(r>>4)-0xc0;\r
374 if(s_chan[ch].pLoop==NULL) return 0;\r
375 return (unsigned short)((s_chan[ch].pLoop-spuMemC)>>3);\r
376 }\r
377 }\r
378 }\r
379\r
380 switch(r)\r
381 {\r
382 case H_SPUctrl:\r
383 return spuCtrl;\r
384\r
385 case H_SPUstat:\r
386 return spuStat;\r
387 \r
388 case H_SPUaddr:\r
389 return (unsigned short)(spuAddr>>3);\r
390\r
391 case H_SPUdata:\r
392 {\r
393 unsigned short s=spuMem[spuAddr>>1];\r
394 spuAddr+=2;\r
395 if(spuAddr>0x7ffff) spuAddr=0;\r
396 return s;\r
397 }\r
398\r
399 case H_SPUirqAddr:\r
400 return spuIrq;\r
401\r
402 //case H_SPUIsOn1:\r
403 // return IsSoundOn(0,16);\r
404\r
405 //case H_SPUIsOn2:\r
406 // return IsSoundOn(16,24);\r
407 \r
408 }\r
409\r
410 return regArea[(r-0xc00)>>1];\r
411}\r
412 \r
413////////////////////////////////////////////////////////////////////////\r
414// SOUND ON register write\r
415////////////////////////////////////////////////////////////////////////\r
416\r
417void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND\r
418{\r
419 int ch;\r
420\r
421 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
422 {\r
423 if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?!\r
424 {\r
425 s_chan[ch].bIgnoreLoop=0;\r
426 s_chan[ch].bNew=1;\r
427 dwNewChannel|=(1<<ch); // bitfield for faster testing\r
428 }\r
429 }\r
430}\r
431\r
432////////////////////////////////////////////////////////////////////////\r
433// SOUND OFF register write\r
434////////////////////////////////////////////////////////////////////////\r
435\r
436void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND\r
437{\r
438 int ch;\r
439 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
440 {\r
441 if(val&1) // && s_chan[i].bOn) mmm...\r
442 {\r
443 s_chan[ch].bStop=1;\r
444 } \r
445 }\r
446}\r
447\r
448////////////////////////////////////////////////////////////////////////\r
449// FMOD register write\r
450////////////////////////////////////////////////////////////////////////\r
451\r
452void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND\r
453{\r
454 int ch;\r
455\r
456 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
457 {\r
458 if(val&1) // -> fmod on/off\r
459 {\r
460 if(ch>0) \r
461 {\r
462 s_chan[ch].bFMod=1; // --> sound channel\r
463 s_chan[ch-1].bFMod=2; // --> freq channel\r
464 }\r
465 }\r
466 else\r
467 {\r
468 s_chan[ch].bFMod=0; // --> turn off fmod\r
469 }\r
470 }\r
471}\r
472\r
473////////////////////////////////////////////////////////////////////////\r
474// NOISE register write\r
475////////////////////////////////////////////////////////////////////////\r
476\r
477void NoiseOn(int start,int end,unsigned short val) // NOISE ON PSX COMMAND\r
478{\r
479 int ch;\r
480\r
481 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
482 {\r
483 if(val&1) // -> noise on/off\r
484 {\r
485 s_chan[ch].bNoise=1;\r
486 }\r
487 else \r
488 {\r
489 s_chan[ch].bNoise=0;\r
490 }\r
491 }\r
492}\r
493\r
494////////////////////////////////////////////////////////////////////////\r
495// LEFT VOLUME register write\r
496////////////////////////////////////////////////////////////////////////\r
497\r
498// please note: sweep and phase invert are wrong... but I've never seen\r
499// them used\r
500\r
501void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME\r
502{\r
503 s_chan[ch].iLeftVolRaw=vol;\r
504\r
505 if(vol&0x8000) // sweep?\r
506 {\r
507 short sInc=1; // -> sweep up?\r
508 if(vol&0x2000) sInc=-1; // -> or down?\r
509 if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this\r
510 vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64\r
511 vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!\r
512 vol*=128;\r
513 }\r
514 else // no sweep:\r
515 {\r
516 if(vol&0x4000) // -> mmm... phase inverted? have to investigate this\r
517 //vol^=0xffff;\r
518 vol=0x3fff-(vol&0x3fff);\r
519 }\r
520\r
521 vol&=0x3fff;\r
522 s_chan[ch].iLeftVolume=vol; // store volume\r
523}\r
524\r
525////////////////////////////////////////////////////////////////////////\r
526// RIGHT VOLUME register write\r
527////////////////////////////////////////////////////////////////////////\r
528\r
529void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME\r
530{\r
531 s_chan[ch].iRightVolRaw=vol;\r
532\r
533 if(vol&0x8000) // comments... see above :)\r
534 {\r
535 short sInc=1;\r
536 if(vol&0x2000) sInc=-1;\r
537 if(vol&0x1000) vol^=0xffff;\r
538 vol=((vol&0x7f)+1)/2; \r
539 vol+=vol/(2*sInc);\r
540 vol*=128;\r
541 }\r
542 else \r
543 {\r
544 if(vol&0x4000) //vol=vol^=0xffff;\r
545 vol=0x3fff-(vol&0x3fff);\r
546 }\r
547\r
548 vol&=0x3fff;\r
549\r
550 s_chan[ch].iRightVolume=vol;\r
551}\r
552\r
553////////////////////////////////////////////////////////////////////////\r
554// PITCH register write\r
555////////////////////////////////////////////////////////////////////////\r
556\r
557void SetPitch(int ch,unsigned short val) // SET PITCH\r
558{\r
559 int NP;\r
560 if(val>0x3fff) NP=0x3fff; // get pitch val\r
561 else NP=val;\r
562\r
563 s_chan[ch].iRawPitch=NP;\r
564\r
565 NP=(44100L*NP)/4096L; // calc frequency\r
566 if(NP<1) NP=1; // some security\r
567 s_chan[ch].iActFreq=NP; // store frequency\r
568}\r
569\r
570////////////////////////////////////////////////////////////////////////\r
571// REVERB register write\r
572////////////////////////////////////////////////////////////////////////\r
573\r
574void ReverbOn(int start,int end,unsigned short val) // REVERB ON PSX COMMAND\r
575{\r
576 int ch;\r
577\r
578 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
579 {\r
580 if(val&1) // -> reverb on/off\r
581 {\r
582 s_chan[ch].bReverb=1;\r
583 }\r
584 else \r
585 {\r
586 s_chan[ch].bReverb=0;\r
587 }\r
588 }\r
589}\r