1
/***************************************************************************
2
registers.c - description
4
begin : Wed May 15 2002
5
copyright : (C) 2002 by Pete Bernert
6
email : BlackDove@addcom.de
7
***************************************************************************/
9
/***************************************************************************
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. *
17
***************************************************************************/
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.
27
- removed &0x3fff from reverb volume registers, fixes a few games,
28
hopefully won't be breaking anything
31
- added Neill's reverb
34
- added Neill's ADSR timings
37
- generic cleanup for the Peops release
45
#include "../peops/externals.h"
46
#include "../peops/registers.h"
47
#include "../peops/regs.h"
49
static void SoundOn(int start,int end,u16 val);
50
static void SoundOff(int start,int end,u16 val);
51
static void FModOn(int start,int end,u16 val);
52
static void NoiseOn(int start,int end,u16 val);
53
static void SetVolumeLR(int right, u8 ch,s16 vol);
54
static void SetPitch(int ch,u16 val);
56
////////////////////////////////////////////////////////////////////////
57
// WRITE REGISTERS: called by main emu
58
////////////////////////////////////////////////////////////////////////
60
void SPUwriteRegister(u32 reg, u16 val)
62
const u32 r=reg&0xfff;
63
regArea[(r-0xc00)>>1] = val;
65
// printf("SPUwrite: r %x val %x\n", r, val);
67
if(r>=0x0c00 && r<0x0d80) // some channel info?
69
int ch=(r>>4)-0xc0; // calc channel
71
//if(ch==20) printf("%08x: %04x\n",reg,val);
75
//------------------------------------------------// r volume
77
SetVolumeLR(0,(u8)ch,val);
79
//------------------------------------------------// l volume
81
SetVolumeLR(1,(u8)ch,val);
83
//------------------------------------------------// pitch
87
//------------------------------------------------// start
89
s_chan[ch].pStart=spuMemC+((u32) val<<3);
91
//------------------------------------------------// level with pre-calcs
94
const u32 lval=val; // DEBUG CHECK
95
//---------------------------------------------//
96
s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0;
97
s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f;
98
s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f;
99
s_chan[ch].ADSRX.SustainLevel=lval & 0x000f;
100
//---------------------------------------------//
103
//------------------------------------------------// adsr times with pre-calcs
106
const u32 lval=val; // DEBUG CHECK
108
//----------------------------------------------//
109
s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0;
110
s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1;
111
s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f;
112
s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0;
113
s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f;
114
//----------------------------------------------//
117
//------------------------------------------------// adsr volume... mmm have to investigate this
120
//------------------------------------------------//
122
s_chan[ch].pLoop=spuMemC+((u32) val<<3);
123
s_chan[ch].bIgnoreLoop=1;
125
//------------------------------------------------//
132
//-------------------------------------------------//
134
spuAddr = (u32) val<<3;
136
//-------------------------------------------------//
138
spuMem[spuAddr>>1] = BFLIP16(val);
140
if(spuAddr>0x7ffff) spuAddr=0;
142
//-------------------------------------------------//
146
//-------------------------------------------------//
148
spuStat=val & 0xf800;
150
//-------------------------------------------------//
151
case H_SPUReverbAddr:
152
if(val==0xFFFF || val<=0x200)
153
{rvb.StartAddr=rvb.CurrAddr=0;}
156
const s32 iv=(u32)val<<2;
157
if(rvb.StartAddr!=iv)
159
rvb.StartAddr=(u32)val<<2;
160
rvb.CurrAddr=rvb.StartAddr;
164
//-------------------------------------------------//
167
pSpuIrq=spuMemC+((u32) val<<3);
169
//-------------------------------------------------//
170
/* Volume settings appear to be at least 15-bit unsigned in this case.
171
Definitely NOT 15-bit signed. Probably 16-bit signed, so s16 type cast.
172
Check out "Chrono Cross: Shadow's End Forest"
175
rvb.VolLeft=(s16)val;
176
//printf("%d\n",val);
178
//-------------------------------------------------//
180
rvb.VolRight=(s16)val;
181
//printf("%d\n",val);
183
//-------------------------------------------------//
187
//auxprintf("EL %d\n",val);
189
//-------------------------------------------------//
191
//auxprintf("ER %d\n",val);
193
//-------------------------------------------------//
195
//auxprintf("ML %d\n",val);
197
//-------------------------------------------------//
199
//auxprintf("MR %d\n",val);
201
//-------------------------------------------------//
203
//printf("M0 %04x\n",val);
205
//-------------------------------------------------//
207
// printf("M1 %04x\n",val);
210
//-------------------------------------------------//
214
//-------------------------------------------------//
216
// printf("Boop: %08x: %04x\n",reg,val);
219
//-------------------------------------------------//
223
//-------------------------------------------------//
226
// printf("Boop: %08x: %04x\n",reg,val);
228
//-------------------------------------------------//
232
//-------------------------------------------------//
236
//-------------------------------------------------//
240
//-------------------------------------------------//
244
//-------------------------------------------------//
246
rvb.Enabled&=~0xFFFF;
250
//-------------------------------------------------//
253
rvb.Enabled|=val<<16;
256
//-------------------------------------------------//
261
case H_Reverb+2 : rvb.FB_SRC_B=(s16)val; break;
262
case H_Reverb+4 : rvb.IIR_ALPHA=(s16)val; break;
263
case H_Reverb+6 : rvb.ACC_COEF_A=(s16)val; break;
264
case H_Reverb+8 : rvb.ACC_COEF_B=(s16)val; break;
265
case H_Reverb+10 : rvb.ACC_COEF_C=(s16)val; break;
266
case H_Reverb+12 : rvb.ACC_COEF_D=(s16)val; break;
267
case H_Reverb+14 : rvb.IIR_COEF=(s16)val; break;
268
case H_Reverb+16 : rvb.FB_ALPHA=(s16)val; break;
269
case H_Reverb+18 : rvb.FB_X=(s16)val; break;
270
case H_Reverb+20 : rvb.IIR_DEST_A0=(s16)val; break;
271
case H_Reverb+22 : rvb.IIR_DEST_A1=(s16)val; break;
272
case H_Reverb+24 : rvb.ACC_SRC_A0=(s16)val; break;
273
case H_Reverb+26 : rvb.ACC_SRC_A1=(s16)val; break;
274
case H_Reverb+28 : rvb.ACC_SRC_B0=(s16)val; break;
275
case H_Reverb+30 : rvb.ACC_SRC_B1=(s16)val; break;
276
case H_Reverb+32 : rvb.IIR_SRC_A0=(s16)val; break;
277
case H_Reverb+34 : rvb.IIR_SRC_A1=(s16)val; break;
278
case H_Reverb+36 : rvb.IIR_DEST_B0=(s16)val; break;
279
case H_Reverb+38 : rvb.IIR_DEST_B1=(s16)val; break;
280
case H_Reverb+40 : rvb.ACC_SRC_C0=(s16)val; break;
281
case H_Reverb+42 : rvb.ACC_SRC_C1=(s16)val; break;
282
case H_Reverb+44 : rvb.ACC_SRC_D0=(s16)val; break;
283
case H_Reverb+46 : rvb.ACC_SRC_D1=(s16)val; break;
284
case H_Reverb+48 : rvb.IIR_SRC_B1=(s16)val; break;
285
case H_Reverb+50 : rvb.IIR_SRC_B0=(s16)val; break;
286
case H_Reverb+52 : rvb.MIX_DEST_A0=(s16)val; break;
287
case H_Reverb+54 : rvb.MIX_DEST_A1=(s16)val; break;
288
case H_Reverb+56 : rvb.MIX_DEST_B0=(s16)val; break;
289
case H_Reverb+58 : rvb.MIX_DEST_B1=(s16)val; break;
290
case H_Reverb+60 : rvb.IN_COEF_L=(s16)val; break;
291
case H_Reverb+62 : rvb.IN_COEF_R=(s16)val; break;
296
////////////////////////////////////////////////////////////////////////
297
// READ REGISTER: called by main emu
298
////////////////////////////////////////////////////////////////////////
300
u16 SPUreadRegister(u32 reg)
302
const u32 r=reg&0xfff;
304
if(r>=0x0c00 && r<0x0d80)
308
case 0xC: // get adsr vol
310
const int ch=(r>>4)-0xc0;
311
if(s_chan[ch].bNew) return 1; // we are started, but not processed? return 1
312
if(s_chan[ch].ADSRX.lVolume && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well
313
!s_chan[ch].ADSRX.EnvelopeVol)
315
return (u16)(s_chan[ch].ADSRX.EnvelopeVol>>16);
318
case 0xE: // get loop address
320
const int ch=(r>>4)-0xc0;
321
if(s_chan[ch].pLoop==NULL) return 0;
322
return (u16)((s_chan[ch].pLoop-spuMemC)>>3);
336
return (u16)(spuAddr>>3);
340
u16 s=BFLIP16(spuMem[spuAddr>>1]);
342
if(spuAddr>0x7ffff) spuAddr=0;
350
// return IsSoundOn(0,16);
353
// return IsSoundOn(16,24);
357
return regArea[(r-0xc00)>>1];
360
////////////////////////////////////////////////////////////////////////
361
// SOUND ON register write
362
////////////////////////////////////////////////////////////////////////
364
static void SoundOn(int start,int end,u16 val) // SOUND ON PSX COMAND
368
for(ch=start;ch<end;ch++,val>>=1) // loop channels
370
if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?!
372
s_chan[ch].bIgnoreLoop=0;
378
////////////////////////////////////////////////////////////////////////
379
// SOUND OFF register write
380
////////////////////////////////////////////////////////////////////////
382
static void SoundOff(int start,int end,u16 val) // SOUND OFF PSX COMMAND
385
for(ch=start;ch<end;ch++,val>>=1) // loop channels
387
if(val&1) // && s_chan[i].bOn) mmm...
394
////////////////////////////////////////////////////////////////////////
395
// FMOD register write
396
////////////////////////////////////////////////////////////////////////
398
static void FModOn(int start,int end,u16 val) // FMOD ON PSX COMMAND
402
for(ch=start;ch<end;ch++,val>>=1) // loop channels
404
if(val&1) // -> fmod on/off
408
s_chan[ch].bFMod=1; // --> sound channel
409
s_chan[ch-1].bFMod=2; // --> freq channel
414
s_chan[ch].bFMod=0; // --> turn off fmod
419
////////////////////////////////////////////////////////////////////////
420
// NOISE register write
421
////////////////////////////////////////////////////////////////////////
423
static void NoiseOn(int start,int end,u16 val) // NOISE ON PSX COMMAND
427
for(ch=start;ch<end;ch++,val>>=1) // loop channels
429
if(val&1) // -> noise on/off
440
////////////////////////////////////////////////////////////////////////
441
// LEFT VOLUME register write
442
////////////////////////////////////////////////////////////////////////
444
// please note: sweep is wrong.
446
static void SetVolumeLR(int right, u8 ch,s16 vol) // LEFT VOLUME
449
//printf("%d %08x\n",right,vol);
451
s_chan[ch].iRightVolRaw=vol;
453
s_chan[ch].iLeftVolRaw=vol;
455
if(vol&0x8000) // sweep?
457
s16 sInc=1; // -> sweep up?
458
if(vol&0x2000) sInc=-1; // -> or down?
459
if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this
460
vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64
461
vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half!
469
vol=(vol&0x3FFF)-0x4000;
473
//if(vol&0x4000) // -> mmm... phase inverted? have to investigate this
474
// vol=0-(0x3fff-(vol&0x3fff));
479
s_chan[ch].iRightVolume=vol;
481
s_chan[ch].iLeftVolume=vol; // store volume
484
////////////////////////////////////////////////////////////////////////
485
// PITCH register write
486
////////////////////////////////////////////////////////////////////////
488
static void SetPitch(int ch,u16 val) // SET PITCH
491
if(val>0x3fff) NP=0x3fff; // get pitch val
494
s_chan[ch].iRawPitch=NP;
496
NP=(44100L*NP)/4096L; // calc frequency
497
if(NP<1) NP=1; // some security
498
s_chan[ch].iActFreq=NP; // store frequency