comparison src/Input/sexypsf/spu/registers.c @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
1 /***************************************************************************
2 registers.c - description
3 -------------------
4 begin : Wed May 15 2002
5 copyright : (C) 2002 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. See also the license.txt file for *
15 * additional informations. *
16 * *
17 ***************************************************************************/
18
19 /* ChangeLog
20
21 February 8, 2004 - xodnizel
22 - Fixed setting of reverb volume. Just typecast val("u16") to s16.
23 Also adjusted the normal channel volume to be one less than what it was before when the
24 "phase invert" bit is set. I'm assuming it's just in two's complement.
25
26 2003/02/09 - kode54
27 - removed &0x3fff from reverb volume registers, fixes a few games,
28 hopefully won't be breaking anything
29
30 2003/01/19 - Pete
31 - added Neill's reverb
32
33 2003/01/06 - Pete
34 - added Neill's ADSR timings
35
36 2002/05/15 - Pete
37 - generic cleanup for the Peops release
38
39 */
40
41 //#include "stdafx.h"
42
43 #define _IN_REGISTERS
44
45 //#include "externals.h"
46 //#include "registers.h"
47 //#include "regs.h"
48
49 ////////////////////////////////////////////////////////////////////////
50 // WRITE REGISTERS: called by main emu
51 ////////////////////////////////////////////////////////////////////////
52
53 void SPUwriteRegister(u32 reg, u16 val)
54 {
55 const u32 r=reg&0xfff;
56 regArea[(r-0xc00)>>1] = val;
57
58 if(r>=0x0c00 && r<0x0d80) // some channel info?
59 {
60 int ch=(r>>4)-0xc0; // calc channel
61
62 //if(ch==20) printf("%08x: %04x\n",reg,val);
63
64 switch(r&0x0f)
65 {
66 //------------------------------------------------// r volume
67 case 0:
68 SetVolumeLR(0,(u8)ch,val);
69 break;
70 //------------------------------------------------// l volume
71 case 2:
72 SetVolumeLR(1,(u8)ch,val);
73 break;
74 //------------------------------------------------// pitch
75 case 4:
76 SetPitch(ch,val);
77 break;
78 //------------------------------------------------// start
79 case 6:
80 s_chan[ch].pStart=spuMemC+((u32) val<<3);
81 break;
82 //------------------------------------------------// level with pre-calcs
83 case 8:
84 {
85 const u32 lval=val; // DEBUG CHECK
86 //---------------------------------------------//
87 s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0;
88 s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;
89 s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;
90 s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;
91 //---------------------------------------------//
92 }
93 break;
94 //------------------------------------------------// adsr times with pre-calcs
95 case 10:
96 {
97 const u32 lval=val; // DEBUG CHECK
98
99 //----------------------------------------------//
100 s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;
101 s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;
102 s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;
103 s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;
104 s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;
105 //----------------------------------------------//
106 }
107 break;
108 //------------------------------------------------// adsr volume... mmm have to investigate this
109 //case 0xC:
110 // break;
111 //------------------------------------------------//
112 case 0xE: // loop?
113 s_chan[ch].pLoop=spuMemC+((u32) val<<3);
114 s_chan[ch].bIgnoreLoop=1;
115 break;
116 //------------------------------------------------//
117 }
118 return;
119 }
120
121 switch(r)
122 {
123 //-------------------------------------------------//
124 case H_SPUaddr:
125 spuAddr = (u32) val<<3;
126 break;
127 //-------------------------------------------------//
128 case H_SPUdata:
129 spuMem[spuAddr>>1] = BFLIP16(val);
130 spuAddr+=2;
131 if(spuAddr>0x7ffff) spuAddr=0;
132 break;
133 //-------------------------------------------------//
134 case H_SPUctrl:
135 spuCtrl=val;
136 break;
137 //-------------------------------------------------//
138 case H_SPUstat:
139 spuStat=val & 0xf800;
140 break;
141 //-------------------------------------------------//
142 case H_SPUReverbAddr:
143 if(val==0xFFFF || val<=0x200)
144 {rvb.StartAddr=rvb.CurrAddr=0;}
145 else
146 {
147 const s32 iv=(u32)val<<2;
148 if(rvb.StartAddr!=iv)
149 {
150 rvb.StartAddr=(u32)val<<2;
151 rvb.CurrAddr=rvb.StartAddr;
152 }
153 }
154 break;
155 //-------------------------------------------------//
156 case H_SPUirqAddr:
157 spuIrq = val;
158 pSpuIrq=spuMemC+((u32) val<<3);
159 break;
160 //-------------------------------------------------//
161 /* Volume settings appear to be at least 15-bit unsigned in this case.
162 Definitely NOT 15-bit signed. Probably 16-bit signed, so s16 type cast.
163 Check out "Chrono Cross: Shadow's End Forest"
164 */
165 case H_SPUrvolL:
166 rvb.VolLeft=(s16)val;
167 //printf("%d\n",val);
168 break;
169 //-------------------------------------------------//
170 case H_SPUrvolR:
171 rvb.VolRight=(s16)val;
172 //printf("%d\n",val);
173 break;
174 //-------------------------------------------------//
175
176 /*
177 case H_ExtLeft:
178 //auxprintf("EL %d\n",val);
179 break;
180 //-------------------------------------------------//
181 case H_ExtRight:
182 //auxprintf("ER %d\n",val);
183 break;
184 //-------------------------------------------------//
185 case H_SPUmvolL:
186 //auxprintf("ML %d\n",val);
187 break;
188 //-------------------------------------------------//
189 case H_SPUmvolR:
190 //auxprintf("MR %d\n",val);
191 break;
192 //-------------------------------------------------//
193 case H_SPUMute1:
194 //printf("M0 %04x\n",val);
195 break;
196 //-------------------------------------------------//
197 case H_SPUMute2:
198 // printf("M1 %04x\n",val);
199 break;
200 */
201 //-------------------------------------------------//
202 case H_SPUon1:
203 SoundOn(0,16,val);
204 break;
205 //-------------------------------------------------//
206 case H_SPUon2:
207 // printf("Boop: %08x: %04x\n",reg,val);
208 SoundOn(16,24,val);
209 break;
210 //-------------------------------------------------//
211 case H_SPUoff1:
212 SoundOff(0,16,val);
213 break;
214 //-------------------------------------------------//
215 case H_SPUoff2:
216 SoundOff(16,24,val);
217 // printf("Boop: %08x: %04x\n",reg,val);
218 break;
219 //-------------------------------------------------//
220 case H_FMod1:
221 FModOn(0,16,val);
222 break;
223 //-------------------------------------------------//
224 case H_FMod2:
225 FModOn(16,24,val);
226 break;
227 //-------------------------------------------------//
228 case H_Noise1:
229 NoiseOn(0,16,val);
230 break;
231 //-------------------------------------------------//
232 case H_Noise2:
233 NoiseOn(16,24,val);
234 break;
235 //-------------------------------------------------//
236 case H_RVBon1:
237 rvb.Enabled&=~0xFFFF;
238 rvb.Enabled|=val;
239 break;
240
241 //-------------------------------------------------//
242 case H_RVBon2:
243 rvb.Enabled&=0xFFFF;
244 rvb.Enabled|=val<<16;
245 break;
246
247 //-------------------------------------------------//
248 case H_Reverb+0:
249 rvb.FB_SRC_A=val;
250 break;
251
252 case H_Reverb+2 : rvb.FB_SRC_B=(s16)val; break;
253 case H_Reverb+4 : rvb.IIR_ALPHA=(s16)val; break;
254 case H_Reverb+6 : rvb.ACC_COEF_A=(s16)val; break;
255 case H_Reverb+8 : rvb.ACC_COEF_B=(s16)val; break;
256 case H_Reverb+10 : rvb.ACC_COEF_C=(s16)val; break;
257 case H_Reverb+12 : rvb.ACC_COEF_D=(s16)val; break;
258 case H_Reverb+14 : rvb.IIR_COEF=(s16)val; break;
259 case H_Reverb+16 : rvb.FB_ALPHA=(s16)val; break;
260 case H_Reverb+18 : rvb.FB_X=(s16)val; break;
261 case H_Reverb+20 : rvb.IIR_DEST_A0=(s16)val; break;
262 case H_Reverb+22 : rvb.IIR_DEST_A1=(s16)val; break;
263 case H_Reverb+24 : rvb.ACC_SRC_A0=(s16)val; break;
264 case H_Reverb+26 : rvb.ACC_SRC_A1=(s16)val; break;
265 case H_Reverb+28 : rvb.ACC_SRC_B0=(s16)val; break;
266 case H_Reverb+30 : rvb.ACC_SRC_B1=(s16)val; break;
267 case H_Reverb+32 : rvb.IIR_SRC_A0=(s16)val; break;
268 case H_Reverb+34 : rvb.IIR_SRC_A1=(s16)val; break;
269 case H_Reverb+36 : rvb.IIR_DEST_B0=(s16)val; break;
270 case H_Reverb+38 : rvb.IIR_DEST_B1=(s16)val; break;
271 case H_Reverb+40 : rvb.ACC_SRC_C0=(s16)val; break;
272 case H_Reverb+42 : rvb.ACC_SRC_C1=(s16)val; break;
273 case H_Reverb+44 : rvb.ACC_SRC_D0=(s16)val; break;
274 case H_Reverb+46 : rvb.ACC_SRC_D1=(s16)val; break;
275 case H_Reverb+48 : rvb.IIR_SRC_B1=(s16)val; break;
276 case H_Reverb+50 : rvb.IIR_SRC_B0=(s16)val; break;
277 case H_Reverb+52 : rvb.MIX_DEST_A0=(s16)val; break;
278 case H_Reverb+54 : rvb.MIX_DEST_A1=(s16)val; break;
279 case H_Reverb+56 : rvb.MIX_DEST_B0=(s16)val; break;
280 case H_Reverb+58 : rvb.MIX_DEST_B1=(s16)val; break;
281 case H_Reverb+60 : rvb.IN_COEF_L=(s16)val; break;
282 case H_Reverb+62 : rvb.IN_COEF_R=(s16)val; break;
283 }
284
285 }
286
287 ////////////////////////////////////////////////////////////////////////
288 // READ REGISTER: called by main emu
289 ////////////////////////////////////////////////////////////////////////
290
291 u16 SPUreadRegister(u32 reg)
292 {
293 const u32 r=reg&0xfff;
294
295 if(r>=0x0c00 && r<0x0d80)
296 {
297 switch(r&0x0f)
298 {
299 case 0xC: // get adsr vol
300 {
301 const int ch=(r>>4)-0xc0;
302 if(s_chan[ch].bNew) return 1; // we are started, but not processed? return 1
303 if(s_chan[ch].ADSRX.lVolume && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well
304 !s_chan[ch].ADSRX.EnvelopeVol)
305 return 1;
306 return (u16)(s_chan[ch].ADSRX.EnvelopeVol>>16);
307 }
308
309 case 0xE: // get loop address
310 {
311 const int ch=(r>>4)-0xc0;
312 if(s_chan[ch].pLoop==NULL) return 0;
313 return (u16)((s_chan[ch].pLoop-spuMemC)>>3);
314 }
315 }
316 }
317
318 switch(r)
319 {
320 case H_SPUctrl:
321 return spuCtrl;
322
323 case H_SPUstat:
324 return spuStat;
325
326 case H_SPUaddr:
327 return (u16)(spuAddr>>3);
328
329 case H_SPUdata:
330 {
331 u16 s=BFLIP16(spuMem[spuAddr>>1]);
332 spuAddr+=2;
333 if(spuAddr>0x7ffff) spuAddr=0;
334 return s;
335 }
336
337 case H_SPUirqAddr:
338 return spuIrq;
339
340 //case H_SPUIsOn1:
341 // return IsSoundOn(0,16);
342
343 //case H_SPUIsOn2:
344 // return IsSoundOn(16,24);
345
346 }
347
348 return regArea[(r-0xc00)>>1];
349 }
350
351 ////////////////////////////////////////////////////////////////////////
352 // SOUND ON register write
353 ////////////////////////////////////////////////////////////////////////
354
355 static void SoundOn(int start,int end,u16 val) // SOUND ON PSX COMAND
356 {
357 int ch;
358
359 for(ch=start;ch<end;ch++,val>>=1) // loop channels
360 {
361 if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?!
362 {
363 s_chan[ch].bIgnoreLoop=0;
364 s_chan[ch].bNew=1;
365 }
366 }
367 }
368
369 ////////////////////////////////////////////////////////////////////////
370 // SOUND OFF register write
371 ////////////////////////////////////////////////////////////////////////
372
373 static void SoundOff(int start,int end,u16 val) // SOUND OFF PSX COMMAND
374 {
375 int ch;
376 for(ch=start;ch<end;ch++,val>>=1) // loop channels
377 {
378 if(val&1) // && s_chan[i].bOn) mmm...
379 {
380 s_chan[ch].bStop=1;
381 }
382 }
383 }
384
385 ////////////////////////////////////////////////////////////////////////
386 // FMOD register write
387 ////////////////////////////////////////////////////////////////////////
388
389 static void FModOn(int start,int end,u16 val) // FMOD ON PSX COMMAND
390 {
391 int ch;
392
393 for(ch=start;ch<end;ch++,val>>=1) // loop channels
394 {
395 if(val&1) // -> fmod on/off
396 {
397 if(ch>0)
398 {
399 s_chan[ch].bFMod=1; // --> sound channel
400 s_chan[ch-1].bFMod=2; // --> freq channel
401 }
402 }
403 else
404 {
405 s_chan[ch].bFMod=0; // --> turn off fmod
406 }
407 }
408 }
409
410 ////////////////////////////////////////////////////////////////////////
411 // NOISE register write
412 ////////////////////////////////////////////////////////////////////////
413
414 static void NoiseOn(int start,int end,u16 val) // NOISE ON PSX COMMAND
415 {
416 int ch;
417
418 for(ch=start;ch<end;ch++,val>>=1) // loop channels
419 {
420 if(val&1) // -> noise on/off
421 {
422 s_chan[ch].bNoise=1;
423 }
424 else
425 {
426 s_chan[ch].bNoise=0;
427 }
428 }
429 }
430
431 ////////////////////////////////////////////////////////////////////////
432 // LEFT VOLUME register write
433 ////////////////////////////////////////////////////////////////////////
434
435 // please note: sweep is wrong.
436
437 static void SetVolumeLR(int right, u8 ch,s16 vol) // LEFT VOLUME
438 {
439 //if(vol&0xc000)
440 //printf("%d %08x\n",right,vol);
441 if(right)
442 s_chan[ch].iRightVolRaw=vol;
443 else
444 s_chan[ch].iLeftVolRaw=vol;
445
446 if(vol&0x8000) // sweep?
447 {
448 s16 sInc=1; // -> sweep up?
449 if(vol&0x2000) sInc=-1; // -> or down?
450 if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this
451 vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64
452 vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!
453 vol*=128;
454 vol&=0x3fff;
455 //puts("Sweep");
456 }
457 else // no sweep:
458 {
459 if(vol&0x4000)
460 vol=(vol&0x3FFF)-0x4000;
461 else
462 vol&=0x3FFF;
463
464 //if(vol&0x4000) // -> mmm... phase inverted? have to investigate this
465 // vol=0-(0x3fff-(vol&0x3fff));
466 //else
467 // vol&=0x3fff;
468 }
469 if(right)
470 s_chan[ch].iRightVolume=vol;
471 else
472 s_chan[ch].iLeftVolume=vol; // store volume
473 }
474
475 ////////////////////////////////////////////////////////////////////////
476 // PITCH register write
477 ////////////////////////////////////////////////////////////////////////
478
479 static void SetPitch(int ch,u16 val) // SET PITCH
480 {
481 int NP;
482 if(val>0x3fff) NP=0x3fff; // get pitch val
483 else NP=val;
484
485 s_chan[ch].iRawPitch=NP;
486
487 NP=(44100L*NP)/4096L; // calc frequency
488 if(NP<1) NP=1; // some security
489 s_chan[ch].iActFreq=NP; // store frequency
490 }