Mercurial > audlegacy-plugins
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 } |