frontend: update libpicofe, fix missed callbacks
[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
a4621d43 25#include "spu.h"\r
ef79bbde 26\r
7e44d49d 27static void SoundOn(int start,int end,unsigned short val);\r
28static void SoundOff(int start,int end,unsigned short val);\r
29static void FModOn(int start,int end,unsigned short val);\r
30static void NoiseOn(int start,int end,unsigned short val);\r
31static void SetVolumeL(unsigned char ch,short vol);\r
32static void SetVolumeR(unsigned char ch,short vol);\r
33static void SetPitch(int ch,unsigned short val);\r
34static void ReverbOn(int start,int end,unsigned short val);\r
35\r
ef79bbde
P
36////////////////////////////////////////////////////////////////////////\r
37// WRITE REGISTERS: called by main emu\r
38////////////////////////////////////////////////////////////////////////\r
39\r
4b22d950 40static const uint32_t ignore_dupe[16] = {\r
650adfd2 41 // ch 0-15 c40 c80 cc0\r
42 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,\r
43 // ch 16-24 d40 control reverb\r
4b22d950 44 0x7f7f7f7f, 0x7f7f7f7f, 0xff05ff0f, 0xffffffff,\r
45 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,\r
46 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff\r
650adfd2 47};\r
48\r
49void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,\r
50 unsigned int cycles)\r
ef79bbde 51{\r
4b22d950 52 int r = reg & 0xffe;\r
650adfd2 53 int rofs = (r - 0xc00) >> 1;\r
3154bfab 54 int changed = spu.regArea[rofs] != val;\r
55 spu.regArea[rofs] = val;\r
650adfd2 56\r
f707f14b 57 if (!changed && (ignore_dupe[rofs >> 5] & (1u << (rofs & 0x1f))))\r
650adfd2 58 return;\r
59 // zero keyon/keyoff?\r
60 if (val == 0 && (r & 0xff8) == 0xd88)\r
61 return;\r
62\r
d358733b 63 do_samples_if_needed(cycles, 0, 16);\r
ef79bbde
P
64\r
65 if(r>=0x0c00 && r<0x0d80) // some channel info?\r
66 {\r
67 int ch=(r>>4)-0xc0; // calc channel\r
68 switch(r&0x0f)\r
69 {\r
70 //------------------------------------------------// r volume\r
71 case 0: \r
72 SetVolumeL((unsigned char)ch,val);\r
73 break;\r
74 //------------------------------------------------// l volume\r
75 case 2: \r
76 SetVolumeR((unsigned char)ch,val);\r
77 break;\r
78 //------------------------------------------------// pitch\r
79 case 4: \r
80 SetPitch(ch,val);\r
650adfd2 81 goto upd_irq;\r
ef79bbde
P
82 //------------------------------------------------// start\r
83 case 6: \r
7e44d49d 84 // taken from regArea later\r
ef79bbde
P
85 break;\r
86 //------------------------------------------------// level with pre-calcs\r
87 case 8:\r
88 {\r
6d866bb7 89 const unsigned long lval=val;\r
ef79bbde 90 //---------------------------------------------//\r
5514a050 91 spu.s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0;\r
92 spu.s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;\r
93 spu.s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;\r
94 spu.s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;\r
ef79bbde 95 //---------------------------------------------//\r
ef79bbde
P
96 }\r
97 break;\r
98 //------------------------------------------------// adsr times with pre-calcs\r
99 case 10:\r
100 {\r
6d866bb7 101 const unsigned long lval=val;\r
ef79bbde
P
102\r
103 //----------------------------------------------//\r
5514a050 104 spu.s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;\r
105 spu.s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;\r
106 spu.s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;\r
107 spu.s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;\r
108 spu.s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;\r
ef79bbde 109 //----------------------------------------------//\r
ef79bbde
P
110 }\r
111 break;\r
112 //------------------------------------------------// adsr volume... mmm have to investigate this\r
113 case 12:\r
114 break;\r
115 //------------------------------------------------//\r
116 case 14: // loop?\r
5514a050 117 spu.s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
16f3ca66 118 spu.s_chan[ch].bIgnoreLoop = 1;\r
650adfd2 119 goto upd_irq;\r
ef79bbde
P
120 //------------------------------------------------//\r
121 }\r
ef79bbde
P
122 return;\r
123 }\r
4b22d950 124 else if (0x0e00 <= r && r < 0x0e60)\r
125 {\r
126 int ch = (r >> 2) & 0x1f;\r
127 log_unhandled("c%02d w %cvol %04x\n", ch, (r & 2) ? 'r' : 'l', val);\r
128 spu.s_chan[ch].iVolume[(r >> 1) & 1] = (signed short)val >> 1;\r
129 }\r
ef79bbde
P
130\r
131 switch(r)\r
132 {\r
133 //-------------------------------------------------//\r
134 case H_SPUaddr:\r
25f460ec 135 spu.spuAddr = (unsigned int)val << 3;\r
3c7a8977 136 //check_irq_io(spu.spuAddr);\r
ef79bbde
P
137 break;\r
138 //-------------------------------------------------//\r
139 case H_SPUdata:\r
a4621d43 140 *(unsigned short *)(spu.spuMemC + spu.spuAddr) = HTOLE16(val);\r
5514a050 141 spu.spuAddr += 2;\r
142 spu.spuAddr &= 0x7fffe;\r
3c7a8977 143 check_irq_io(spu.spuAddr);\r
ef79bbde
P
144 break;\r
145 //-------------------------------------------------//\r
146 case H_SPUctrl:\r
3047daea 147 spu.spuStat = (spu.spuStat & ~0xbf) | (val & 0x3f) | ((val << 2) & 0x80);\r
25f460ec 148 spu.spuStat &= ~STAT_IRQ | val;\r
3154bfab 149 if (!(spu.spuCtrl & CTRL_IRQ)) {\r
650adfd2 150 if (val & CTRL_IRQ)\r
151 schedule_next_irq();\r
152 }\r
3154bfab 153 spu.spuCtrl=val;\r
ef79bbde
P
154 break;\r
155 //-------------------------------------------------//\r
156 case H_SPUstat:\r
25f460ec 157 //spu.spuStat=val&0xf800;\r
ef79bbde
P
158 break;\r
159 //-------------------------------------------------//\r
160 case H_SPUReverbAddr:\r
650adfd2 161 goto rvbd;\r
ef79bbde
P
162 //-------------------------------------------------//\r
163 case H_SPUirqAddr:\r
a5ff8be2 164 //if (val & 1)\r
165 // log_unhandled("w irq with lsb: %08lx %04x\n", reg, val);\r
3c7a8977 166 spu.pSpuIrq = spu.spuMemC + (((int)val << 3) & ~0xf);\r
167 //check_irq_io(spu.spuAddr);\r
650adfd2 168 goto upd_irq;\r
ef79bbde
P
169 //-------------------------------------------------//\r
170 case H_SPUrvolL:\r
de41998a 171 spu.rvb->VolLeft = (int16_t)val;\r
ef79bbde
P
172 break;\r
173 //-------------------------------------------------//\r
174 case H_SPUrvolR:\r
de41998a 175 spu.rvb->VolRight = (int16_t)val;\r
ef79bbde
P
176 break;\r
177 //-------------------------------------------------//\r
178\r
6c9db47c 179 case H_SPUmvolL:\r
7d06f3e5 180 case H_SPUmvolR: {\r
181 int ofs = H_SPUcmvolL - H_SPUmvolL;\r
182 unsigned short *cur = &regAreaGet(r + ofs);\r
183 if (val & 0x8000) {\r
184 // this (for now?) lacks an update mechanism, so is instant\r
6c9db47c 185 log_unhandled("w master sweep: %08lx %04x\n", reg, val);\r
7d06f3e5 186 int was_neg = (*cur >> 14) & 1;\r
187 int dec = (val >> 13) & 1;\r
188 int inv = (val >> 12) & 1;\r
189 *cur = (was_neg ^ dec ^ inv) ? 0x7fff : 0;\r
190 }\r
191 else\r
192 *cur = val << 1;\r
6c9db47c 193 break;\r
7d06f3e5 194 }\r
6c9db47c 195\r
196 case 0x0dac:\r
197 if (val != 4)\r
198 log_unhandled("1f801dac %04x\n", val);\r
199 break;\r
200\r
ef79bbde
P
201/*\r
202 case H_ExtLeft:\r
203 //auxprintf("EL %d\n",val);\r
204 break;\r
205 //-------------------------------------------------//\r
206 case H_ExtRight:\r
207 //auxprintf("ER %d\n",val);\r
208 break;\r
209 //-------------------------------------------------//\r
ef79bbde
P
210 case H_SPUMute1:\r
211 //auxprintf("M0 %04x\n",val);\r
212 break;\r
213 //-------------------------------------------------//\r
214 case H_SPUMute2:\r
215 //auxprintf("M1 %04x\n",val);\r
216 break;\r
217*/\r
218 //-------------------------------------------------//\r
219 case H_SPUon1:\r
561aa7a9 220 spu.last_keyon_cycles = cycles;\r
d358733b 221 do_samples_if_needed(cycles, 0, 2);\r
ef79bbde
P
222 SoundOn(0,16,val);\r
223 break;\r
224 //-------------------------------------------------//\r
d358733b 225 case H_SPUon2:\r
561aa7a9 226 spu.last_keyon_cycles = cycles;\r
d358733b 227 do_samples_if_needed(cycles, 0, 2);\r
ef79bbde
P
228 SoundOn(16,24,val);\r
229 break;\r
230 //-------------------------------------------------//\r
231 case H_SPUoff1:\r
561aa7a9 232 if (cycles - spu.last_keyon_cycles < 786u) {\r
233 if (val & regAreaGet(H_SPUon1))\r
234 log_unhandled("koff1 %04x %d\n", val, cycles - spu.last_keyon_cycles);\r
235 val &= ~regAreaGet(H_SPUon1);\r
236 }\r
32fbd56b 237 do_samples_if_needed(cycles, 0, 2);\r
ef79bbde
P
238 SoundOff(0,16,val);\r
239 break;\r
240 //-------------------------------------------------//\r
241 case H_SPUoff2:\r
561aa7a9 242 if (cycles - spu.last_keyon_cycles < 786u) {\r
243 if (val & regAreaGet(H_SPUon1))\r
244 log_unhandled("koff2 %04x %d\n", val, cycles - spu.last_keyon_cycles);\r
245 val &= ~regAreaGet(H_SPUon2);\r
246 }\r
32fbd56b 247 do_samples_if_needed(cycles, 0, 2);\r
ef79bbde
P
248 SoundOff(16,24,val);\r
249 break;\r
250 //-------------------------------------------------//\r
251 case H_CDLeft:\r
b64fb891 252 spu.iLeftXAVol=(int16_t)val;\r
7285d7ad 253 //if(spu.cddavCallback) spu.cddavCallback(0,(int16_t)val);\r
ef79bbde
P
254 break;\r
255 case H_CDRight:\r
b64fb891 256 spu.iRightXAVol=(int16_t)val;\r
7285d7ad 257 //if(spu.cddavCallback) spu.cddavCallback(1,(int16_t)val);\r
ef79bbde
P
258 break;\r
259 //-------------------------------------------------//\r
260 case H_FMod1:\r
261 FModOn(0,16,val);\r
262 break;\r
263 //-------------------------------------------------//\r
264 case H_FMod2:\r
265 FModOn(16,24,val);\r
266 break;\r
267 //-------------------------------------------------//\r
268 case H_Noise1:\r
269 NoiseOn(0,16,val);\r
270 break;\r
271 //-------------------------------------------------//\r
272 case H_Noise2:\r
273 NoiseOn(16,24,val);\r
274 break;\r
275 //-------------------------------------------------//\r
276 case H_RVBon1:\r
277 ReverbOn(0,16,val);\r
278 break;\r
279 //-------------------------------------------------//\r
280 case H_RVBon2:\r
281 ReverbOn(16,24,val);\r
282 break;\r
283 //-------------------------------------------------//\r
f79ea779 284 case H_Reverb + 0x00 : goto rvbd;\r
285 case H_Reverb + 0x02 : goto rvbd;\r
286 case H_Reverb + 0x04 : spu.rvb->vIIR = (signed short)val; break;\r
287 case H_Reverb + 0x06 : spu.rvb->vCOMB1 = (signed short)val; break;\r
288 case H_Reverb + 0x08 : spu.rvb->vCOMB2 = (signed short)val; break;\r
289 case H_Reverb + 0x0a : spu.rvb->vCOMB3 = (signed short)val; break;\r
290 case H_Reverb + 0x0c : spu.rvb->vCOMB4 = (signed short)val; break;\r
291 case H_Reverb + 0x0e : spu.rvb->vWALL = (signed short)val; break;\r
292 case H_Reverb + 0x10 : spu.rvb->vAPF1 = (signed short)val; break;\r
293 case H_Reverb + 0x12 : spu.rvb->vAPF2 = (signed short)val; break;\r
294 case H_Reverb + 0x14 : goto rvbd;\r
295 case H_Reverb + 0x16 : goto rvbd;\r
296 case H_Reverb + 0x18 : goto rvbd;\r
297 case H_Reverb + 0x1a : goto rvbd;\r
298 case H_Reverb + 0x1c : goto rvbd;\r
299 case H_Reverb + 0x1e : goto rvbd;\r
300 case H_Reverb + 0x20 : goto rvbd;\r
301 case H_Reverb + 0x22 : goto rvbd;\r
302 case H_Reverb + 0x24 : goto rvbd;\r
303 case H_Reverb + 0x26 : goto rvbd;\r
304 case H_Reverb + 0x28 : goto rvbd;\r
305 case H_Reverb + 0x2a : goto rvbd;\r
306 case H_Reverb + 0x2c : goto rvbd;\r
307 case H_Reverb + 0x2e : goto rvbd;\r
308 case H_Reverb + 0x30 : goto rvbd;\r
309 case H_Reverb + 0x32 : goto rvbd;\r
310 case H_Reverb + 0x34 : goto rvbd;\r
311 case H_Reverb + 0x36 : goto rvbd;\r
312 case H_Reverb + 0x38 : goto rvbd;\r
313 case H_Reverb + 0x3a : goto rvbd;\r
314 case H_Reverb + 0x3c : spu.rvb->vLIN = (signed short)val; break;\r
315 case H_Reverb + 0x3e : spu.rvb->vRIN = (signed short)val; break;\r
ef79bbde 316 }\r
650adfd2 317 return;\r
318\r
319upd_irq:\r
3154bfab 320 if (spu.spuCtrl & CTRL_IRQ)\r
650adfd2 321 schedule_next_irq();\r
322 return;\r
ef79bbde 323\r
650adfd2 324rvbd:\r
05c7cec7 325 spu.rvb->dirty = 1; // recalculate on next update\r
ef79bbde
P
326}\r
327\r
328////////////////////////////////////////////////////////////////////////\r
329// READ REGISTER: called by main emu\r
330////////////////////////////////////////////////////////////////////////\r
331\r
d358733b 332unsigned short CALLBACK SPUreadRegister(unsigned long reg, unsigned int cycles)\r
ef79bbde 333{\r
4b22d950 334 const unsigned long r = reg & 0xffe;\r
ef79bbde 335 \r
ef79bbde
P
336 if(r>=0x0c00 && r<0x0d80)\r
337 {\r
338 switch(r&0x0f)\r
339 {\r
340 case 12: // get adsr vol\r
341 {\r
d358733b 342 // this used to return 1 immediately after keyon to deal with\r
343 // some poor timing, but that causes Rayman 2 to lose track of\r
344 // it's channels on busy scenes and start looping some of them forever\r
345 const int ch = (r>>4) - 0xc0;\r
346 if (spu.s_chan[ch].bStarting)\r
347 do_samples_if_needed(cycles, 0, 2);\r
348 return (unsigned short)(spu.s_chan[ch].ADSRX.EnvelopeVol >> 16);\r
ef79bbde
P
349 }\r
350\r
351 case 14: // get loop address\r
352 {\r
353 const int ch=(r>>4)-0xc0;\r
5514a050 354 return (unsigned short)((spu.s_chan[ch].pLoop-spu.spuMemC)>>3);\r
ef79bbde
P
355 }\r
356 }\r
357 }\r
4b22d950 358 else if (0x0e00 <= r && r < 0x0e60)\r
359 {\r
360 int ch = (r >> 2) & 0x1f;\r
361 int v = spu.s_chan[ch].iVolume[(r >> 1) & 1] << 1;\r
362 log_unhandled("c%02d r %cvol %04x\n", ch, (r & 2) ? 'r' : 'l', v);\r
363 return v;\r
364 }\r
ef79bbde
P
365\r
366 switch(r)\r
367 {\r
368 case H_SPUctrl:\r
3154bfab 369 return spu.spuCtrl;\r
ef79bbde
P
370\r
371 case H_SPUstat:\r
20ed712f 372 return spu.spuStat;\r
ef79bbde
P
373 \r
374 case H_SPUaddr:\r
3154bfab 375 return (unsigned short)(spu.spuAddr>>3);\r
ef79bbde 376\r
3c7a8977 377 // this reportedly doesn't work on real hw\r
ef79bbde
P
378 case H_SPUdata:\r
379 {\r
a4621d43 380 unsigned short s = LE16TOH(*(unsigned short *)(spu.spuMemC + spu.spuAddr));\r
5514a050 381 spu.spuAddr += 2;\r
382 spu.spuAddr &= 0x7fffe;\r
3c7a8977 383 //check_irq_io(spu.spuAddr);\r
ef79bbde
P
384 return s;\r
385 }\r
386\r
ef79bbde
P
387 //case H_SPUIsOn1:\r
388 // return IsSoundOn(0,16);\r
389\r
390 //case H_SPUIsOn2:\r
391 // return IsSoundOn(16,24);\r
392 \r
6c9db47c 393 case H_SPUMute1:\r
394 case H_SPUMute2:\r
7d06f3e5 395 log_unhandled("spu r isOn: %08lx %04x\n", reg, regAreaGet(r));\r
396 break;\r
397\r
398 case H_SPUmvolL:\r
399 case H_SPUmvolR:\r
400 log_unhandled("spu r mvol: %08lx %04x\n", reg, regAreaGet(r));\r
6c9db47c 401 break;\r
906b1599 402\r
403 case 0x0dac:\r
404 case H_SPUirqAddr:\r
405 case H_CDLeft:\r
406 case H_CDRight:\r
407 case H_ExtLeft:\r
408 case H_ExtRight:\r
409 break;\r
410\r
411 default:\r
412 if (r >= 0xda0)\r
7d06f3e5 413 log_unhandled("spu r %08lx %04x\n", reg, regAreaGet(r));\r
906b1599 414 break;\r
ef79bbde
P
415 }\r
416\r
3154bfab 417 return spu.regArea[(r-0xc00)>>1];\r
ef79bbde
P
418}\r
419 \r
420////////////////////////////////////////////////////////////////////////\r
421// SOUND ON register write\r
422////////////////////////////////////////////////////////////////////////\r
423\r
7e44d49d 424static void SoundOn(int start,int end,unsigned short val)\r
ef79bbde
P
425{\r
426 int ch;\r
427\r
428 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
429 {\r
5fdcf5cd 430 if((val&1) && regAreaGetCh(ch, 6)) // mmm... start has to be set before key on !?!\r
ef79bbde 431 {\r
16f3ca66 432 spu.s_chan[ch].bIgnoreLoop = 0;\r
d358733b 433 spu.s_chan[ch].bStarting = 1;\r
3154bfab 434 spu.dwNewChannel|=(1<<ch);\r
ef79bbde
P
435 }\r
436 }\r
437}\r
438\r
439////////////////////////////////////////////////////////////////////////\r
440// SOUND OFF register write\r
441////////////////////////////////////////////////////////////////////////\r
442\r
7e44d49d 443static void SoundOff(int start,int end,unsigned short val)\r
ef79bbde
P
444{\r
445 int ch;\r
561aa7a9 446 for (ch = start; val && ch < end; ch++, val >>= 1) // loop channels\r
ef79bbde 447 {\r
9ad8abfa 448 if(val&1)\r
ef79bbde 449 {\r
5514a050 450 spu.s_chan[ch].ADSRX.State = ADSR_RELEASE;\r
b00afb77 451\r
452 // Jungle Book - Rhythm 'n Groove\r
453 // - turns off buzzing sound (loop hangs)\r
3154bfab 454 spu.dwNewChannel &= ~(1<<ch);\r
ef79bbde
P
455 } \r
456 }\r
457}\r
458\r
459////////////////////////////////////////////////////////////////////////\r
460// FMOD register write\r
461////////////////////////////////////////////////////////////////////////\r
462\r
7e44d49d 463static void FModOn(int start,int end,unsigned short val)\r
ef79bbde
P
464{\r
465 int ch;\r
466\r
467 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
468 {\r
469 if(val&1) // -> fmod on/off\r
470 {\r
471 if(ch>0) \r
472 {\r
5514a050 473 spu.s_chan[ch].bFMod=1; // --> sound channel\r
474 spu.s_chan[ch-1].bFMod=2; // --> freq channel\r
ef79bbde
P
475 }\r
476 }\r
477 else\r
478 {\r
5514a050 479 spu.s_chan[ch].bFMod=0; // --> turn off fmod\r
480 if(ch>0&&spu.s_chan[ch-1].bFMod==2)\r
481 spu.s_chan[ch-1].bFMod=0;\r
ef79bbde
P
482 }\r
483 }\r
484}\r
485\r
486////////////////////////////////////////////////////////////////////////\r
487// NOISE register write\r
488////////////////////////////////////////////////////////////////////////\r
489\r
7e44d49d 490static void NoiseOn(int start,int end,unsigned short val)\r
ef79bbde
P
491{\r
492 int ch;\r
493\r
494 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
495 {\r
5514a050 496 spu.s_chan[ch].bNoise=val&1; // -> noise on/off\r
ef79bbde
P
497 }\r
498}\r
499\r
500////////////////////////////////////////////////////////////////////////\r
501// LEFT VOLUME register write\r
502////////////////////////////////////////////////////////////////////////\r
503\r
504// please note: sweep and phase invert are wrong... but I've never seen\r
505// them used\r
506\r
7e44d49d 507static void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME\r
ef79bbde 508{\r
ef79bbde
P
509 if(vol&0x8000) // sweep?\r
510 {\r
511 short sInc=1; // -> sweep up?\r
6c9db47c 512 log_unhandled("ch%d sweepl %04x\n", ch, vol);\r
ef79bbde
P
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
5514a050 527 spu.s_chan[ch].iLeftVolume=vol; // store volume\r
4b22d950 528 //spu.regArea[(0xe00-0xc00)/2 + ch*2 + 0] = vol << 1;\r
ef79bbde
P
529}\r
530\r
531////////////////////////////////////////////////////////////////////////\r
532// RIGHT VOLUME register write\r
533////////////////////////////////////////////////////////////////////////\r
534\r
7e44d49d 535static void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME\r
ef79bbde 536{\r
ef79bbde
P
537 if(vol&0x8000) // comments... see above :)\r
538 {\r
539 short sInc=1;\r
6c9db47c 540 log_unhandled("ch%d sweepr %04x\n", ch, vol);\r
ef79bbde
P
541 if(vol&0x2000) sInc=-1;\r
542 if(vol&0x1000) vol^=0xffff;\r
543 vol=((vol&0x7f)+1)/2; \r
544 vol+=vol/(2*sInc);\r
545 vol*=128;\r
546 }\r
547 else \r
548 {\r
549 if(vol&0x4000) //vol=vol^=0xffff;\r
550 vol=0x3fff-(vol&0x3fff);\r
551 }\r
552\r
553 vol&=0x3fff;\r
554\r
5514a050 555 spu.s_chan[ch].iRightVolume=vol;\r
4b22d950 556 //spu.regArea[(0xe00-0xc00)/2 + ch*2 + 1] = vol << 1;\r
ef79bbde
P
557}\r
558\r
559////////////////////////////////////////////////////////////////////////\r
560// PITCH register write\r
561////////////////////////////////////////////////////////////////////////\r
562\r
7e44d49d 563static void SetPitch(int ch,unsigned short val) // SET PITCH\r
ef79bbde
P
564{\r
565 int NP;\r
566 if(val>0x3fff) NP=0x3fff; // get pitch val\r
567 else NP=val;\r
568\r
f3fa20c2 569 spu.s_chan[ch].iRawPitch = NP;\r
570 spu.s_chan[ch].sinc = NP << 4;\r
571 spu.s_chan[ch].sinc_inv = 0;\r
1d5d35bc 572\r
573 // don't mess spu.dwChannelsAudible as adsr runs independently\r
ef79bbde
P
574}\r
575\r
576////////////////////////////////////////////////////////////////////////\r
577// REVERB register write\r
578////////////////////////////////////////////////////////////////////////\r
579\r
7e44d49d 580static void ReverbOn(int start,int end,unsigned short val)\r
ef79bbde
P
581{\r
582 int ch;\r
583\r
584 for(ch=start;ch<end;ch++,val>>=1) // loop channels\r
585 {\r
5514a050 586 spu.s_chan[ch].bReverb=val&1; // -> reverb on/off\r
ef79bbde
P
587 }\r
588}\r
561aa7a9 589\r
590// vim:shiftwidth=1:expandtab\r