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