Mercurial > audlegacy-plugins
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Input/sexypsf/spu/registers.c Mon Sep 18 01:11:49 2006 -0700 @@ -0,0 +1,490 @@ +/*************************************************************************** + registers.c - description + ------------------- + begin : Wed May 15 2002 + copyright : (C) 2002 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +/* ChangeLog + + February 8, 2004 - xodnizel + - Fixed setting of reverb volume. Just typecast val("u16") to s16. + Also adjusted the normal channel volume to be one less than what it was before when the + "phase invert" bit is set. I'm assuming it's just in two's complement. + + 2003/02/09 - kode54 + - removed &0x3fff from reverb volume registers, fixes a few games, + hopefully won't be breaking anything + + 2003/01/19 - Pete + - added Neill's reverb + + 2003/01/06 - Pete + - added Neill's ADSR timings + + 2002/05/15 - Pete + - generic cleanup for the Peops release + +*/ + +//#include "stdafx.h" + +#define _IN_REGISTERS + +//#include "externals.h" +//#include "registers.h" +//#include "regs.h" + +//////////////////////////////////////////////////////////////////////// +// WRITE REGISTERS: called by main emu +//////////////////////////////////////////////////////////////////////// + +void SPUwriteRegister(u32 reg, u16 val) +{ + const u32 r=reg&0xfff; + regArea[(r-0xc00)>>1] = val; + + if(r>=0x0c00 && r<0x0d80) // some channel info? + { + int ch=(r>>4)-0xc0; // calc channel + + //if(ch==20) printf("%08x: %04x\n",reg,val); + + switch(r&0x0f) + { + //------------------------------------------------// r volume + case 0: + SetVolumeLR(0,(u8)ch,val); + break; + //------------------------------------------------// l volume + case 2: + SetVolumeLR(1,(u8)ch,val); + break; + //------------------------------------------------// pitch + case 4: + SetPitch(ch,val); + break; + //------------------------------------------------// start + case 6: + s_chan[ch].pStart=spuMemC+((u32) val<<3); + break; + //------------------------------------------------// level with pre-calcs + case 8: + { + const u32 lval=val; // DEBUG CHECK + //---------------------------------------------// + s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; + s_chan[ch].ADSRX.AttackRate=(lval>>8) & 0x007f; + s_chan[ch].ADSRX.DecayRate=(lval>>4) & 0x000f; + s_chan[ch].ADSRX.SustainLevel=lval & 0x000f; + //---------------------------------------------// + } + break; + //------------------------------------------------// adsr times with pre-calcs + case 10: + { + const u32 lval=val; // DEBUG CHECK + + //----------------------------------------------// + s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; + s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; + s_chan[ch].ADSRX.SustainRate = (lval>>6) & 0x007f; + s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; + s_chan[ch].ADSRX.ReleaseRate = lval & 0x001f; + //----------------------------------------------// + } + break; + //------------------------------------------------// adsr volume... mmm have to investigate this + //case 0xC: + // break; + //------------------------------------------------// + case 0xE: // loop? + s_chan[ch].pLoop=spuMemC+((u32) val<<3); + s_chan[ch].bIgnoreLoop=1; + break; + //------------------------------------------------// + } + return; + } + + switch(r) + { + //-------------------------------------------------// + case H_SPUaddr: + spuAddr = (u32) val<<3; + break; + //-------------------------------------------------// + case H_SPUdata: + spuMem[spuAddr>>1] = BFLIP16(val); + spuAddr+=2; + if(spuAddr>0x7ffff) spuAddr=0; + break; + //-------------------------------------------------// + case H_SPUctrl: + spuCtrl=val; + break; + //-------------------------------------------------// + case H_SPUstat: + spuStat=val & 0xf800; + break; + //-------------------------------------------------// + case H_SPUReverbAddr: + if(val==0xFFFF || val<=0x200) + {rvb.StartAddr=rvb.CurrAddr=0;} + else + { + const s32 iv=(u32)val<<2; + if(rvb.StartAddr!=iv) + { + rvb.StartAddr=(u32)val<<2; + rvb.CurrAddr=rvb.StartAddr; + } + } + break; + //-------------------------------------------------// + case H_SPUirqAddr: + spuIrq = val; + pSpuIrq=spuMemC+((u32) val<<3); + break; + //-------------------------------------------------// + /* Volume settings appear to be at least 15-bit unsigned in this case. + Definitely NOT 15-bit signed. Probably 16-bit signed, so s16 type cast. + Check out "Chrono Cross: Shadow's End Forest" + */ + case H_SPUrvolL: + rvb.VolLeft=(s16)val; + //printf("%d\n",val); + break; + //-------------------------------------------------// + case H_SPUrvolR: + rvb.VolRight=(s16)val; + //printf("%d\n",val); + break; + //-------------------------------------------------// + +/* + case H_ExtLeft: + //auxprintf("EL %d\n",val); + break; + //-------------------------------------------------// + case H_ExtRight: + //auxprintf("ER %d\n",val); + break; + //-------------------------------------------------// + case H_SPUmvolL: + //auxprintf("ML %d\n",val); + break; + //-------------------------------------------------// + case H_SPUmvolR: + //auxprintf("MR %d\n",val); + break; + //-------------------------------------------------// + case H_SPUMute1: + //printf("M0 %04x\n",val); + break; + //-------------------------------------------------// + case H_SPUMute2: + // printf("M1 %04x\n",val); + break; +*/ + //-------------------------------------------------// + case H_SPUon1: + SoundOn(0,16,val); + break; + //-------------------------------------------------// + case H_SPUon2: + // printf("Boop: %08x: %04x\n",reg,val); + SoundOn(16,24,val); + break; + //-------------------------------------------------// + case H_SPUoff1: + SoundOff(0,16,val); + break; + //-------------------------------------------------// + case H_SPUoff2: + SoundOff(16,24,val); + // printf("Boop: %08x: %04x\n",reg,val); + break; + //-------------------------------------------------// + case H_FMod1: + FModOn(0,16,val); + break; + //-------------------------------------------------// + case H_FMod2: + FModOn(16,24,val); + break; + //-------------------------------------------------// + case H_Noise1: + NoiseOn(0,16,val); + break; + //-------------------------------------------------// + case H_Noise2: + NoiseOn(16,24,val); + break; + //-------------------------------------------------// + case H_RVBon1: + rvb.Enabled&=~0xFFFF; + rvb.Enabled|=val; + break; + + //-------------------------------------------------// + case H_RVBon2: + rvb.Enabled&=0xFFFF; + rvb.Enabled|=val<<16; + break; + + //-------------------------------------------------// + case H_Reverb+0: + rvb.FB_SRC_A=val; + break; + + case H_Reverb+2 : rvb.FB_SRC_B=(s16)val; break; + case H_Reverb+4 : rvb.IIR_ALPHA=(s16)val; break; + case H_Reverb+6 : rvb.ACC_COEF_A=(s16)val; break; + case H_Reverb+8 : rvb.ACC_COEF_B=(s16)val; break; + case H_Reverb+10 : rvb.ACC_COEF_C=(s16)val; break; + case H_Reverb+12 : rvb.ACC_COEF_D=(s16)val; break; + case H_Reverb+14 : rvb.IIR_COEF=(s16)val; break; + case H_Reverb+16 : rvb.FB_ALPHA=(s16)val; break; + case H_Reverb+18 : rvb.FB_X=(s16)val; break; + case H_Reverb+20 : rvb.IIR_DEST_A0=(s16)val; break; + case H_Reverb+22 : rvb.IIR_DEST_A1=(s16)val; break; + case H_Reverb+24 : rvb.ACC_SRC_A0=(s16)val; break; + case H_Reverb+26 : rvb.ACC_SRC_A1=(s16)val; break; + case H_Reverb+28 : rvb.ACC_SRC_B0=(s16)val; break; + case H_Reverb+30 : rvb.ACC_SRC_B1=(s16)val; break; + case H_Reverb+32 : rvb.IIR_SRC_A0=(s16)val; break; + case H_Reverb+34 : rvb.IIR_SRC_A1=(s16)val; break; + case H_Reverb+36 : rvb.IIR_DEST_B0=(s16)val; break; + case H_Reverb+38 : rvb.IIR_DEST_B1=(s16)val; break; + case H_Reverb+40 : rvb.ACC_SRC_C0=(s16)val; break; + case H_Reverb+42 : rvb.ACC_SRC_C1=(s16)val; break; + case H_Reverb+44 : rvb.ACC_SRC_D0=(s16)val; break; + case H_Reverb+46 : rvb.ACC_SRC_D1=(s16)val; break; + case H_Reverb+48 : rvb.IIR_SRC_B1=(s16)val; break; + case H_Reverb+50 : rvb.IIR_SRC_B0=(s16)val; break; + case H_Reverb+52 : rvb.MIX_DEST_A0=(s16)val; break; + case H_Reverb+54 : rvb.MIX_DEST_A1=(s16)val; break; + case H_Reverb+56 : rvb.MIX_DEST_B0=(s16)val; break; + case H_Reverb+58 : rvb.MIX_DEST_B1=(s16)val; break; + case H_Reverb+60 : rvb.IN_COEF_L=(s16)val; break; + case H_Reverb+62 : rvb.IN_COEF_R=(s16)val; break; + } + +} + +//////////////////////////////////////////////////////////////////////// +// READ REGISTER: called by main emu +//////////////////////////////////////////////////////////////////////// + +u16 SPUreadRegister(u32 reg) +{ + const u32 r=reg&0xfff; + + if(r>=0x0c00 && r<0x0d80) + { + switch(r&0x0f) + { + case 0xC: // get adsr vol + { + const int ch=(r>>4)-0xc0; + if(s_chan[ch].bNew) return 1; // we are started, but not processed? return 1 + if(s_chan[ch].ADSRX.lVolume && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well + !s_chan[ch].ADSRX.EnvelopeVol) + return 1; + return (u16)(s_chan[ch].ADSRX.EnvelopeVol>>16); + } + + case 0xE: // get loop address + { + const int ch=(r>>4)-0xc0; + if(s_chan[ch].pLoop==NULL) return 0; + return (u16)((s_chan[ch].pLoop-spuMemC)>>3); + } + } + } + + switch(r) + { + case H_SPUctrl: + return spuCtrl; + + case H_SPUstat: + return spuStat; + + case H_SPUaddr: + return (u16)(spuAddr>>3); + + case H_SPUdata: + { + u16 s=BFLIP16(spuMem[spuAddr>>1]); + spuAddr+=2; + if(spuAddr>0x7ffff) spuAddr=0; + return s; + } + + case H_SPUirqAddr: + return spuIrq; + + //case H_SPUIsOn1: + // return IsSoundOn(0,16); + + //case H_SPUIsOn2: + // return IsSoundOn(16,24); + + } + + return regArea[(r-0xc00)>>1]; +} + +//////////////////////////////////////////////////////////////////////// +// SOUND ON register write +//////////////////////////////////////////////////////////////////////// + +static void SoundOn(int start,int end,u16 val) // SOUND ON PSX COMAND +{ + int ch; + + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?! + { + s_chan[ch].bIgnoreLoop=0; + s_chan[ch].bNew=1; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// SOUND OFF register write +//////////////////////////////////////////////////////////////////////// + +static void SoundOff(int start,int end,u16 val) // SOUND OFF PSX COMMAND +{ + int ch; + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if(val&1) // && s_chan[i].bOn) mmm... + { + s_chan[ch].bStop=1; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// FMOD register write +//////////////////////////////////////////////////////////////////////// + +static void FModOn(int start,int end,u16 val) // FMOD ON PSX COMMAND +{ + int ch; + + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if(val&1) // -> fmod on/off + { + if(ch>0) + { + s_chan[ch].bFMod=1; // --> sound channel + s_chan[ch-1].bFMod=2; // --> freq channel + } + } + else + { + s_chan[ch].bFMod=0; // --> turn off fmod + } + } +} + +//////////////////////////////////////////////////////////////////////// +// NOISE register write +//////////////////////////////////////////////////////////////////////// + +static void NoiseOn(int start,int end,u16 val) // NOISE ON PSX COMMAND +{ + int ch; + + for(ch=start;ch<end;ch++,val>>=1) // loop channels + { + if(val&1) // -> noise on/off + { + s_chan[ch].bNoise=1; + } + else + { + s_chan[ch].bNoise=0; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// LEFT VOLUME register write +//////////////////////////////////////////////////////////////////////// + +// please note: sweep is wrong. + +static void SetVolumeLR(int right, u8 ch,s16 vol) // LEFT VOLUME +{ + //if(vol&0xc000) + //printf("%d %08x\n",right,vol); + if(right) + s_chan[ch].iRightVolRaw=vol; + else + s_chan[ch].iLeftVolRaw=vol; + + if(vol&0x8000) // sweep? + { + s16 sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + vol&=0x3fff; + //puts("Sweep"); + } + else // no sweep: + { + if(vol&0x4000) + vol=(vol&0x3FFF)-0x4000; + else + vol&=0x3FFF; + + //if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + // vol=0-(0x3fff-(vol&0x3fff)); + //else + // vol&=0x3fff; + } + if(right) + s_chan[ch].iRightVolume=vol; + else + s_chan[ch].iLeftVolume=vol; // store volume +} + +//////////////////////////////////////////////////////////////////////// +// PITCH register write +//////////////////////////////////////////////////////////////////////// + +static void SetPitch(int ch,u16 val) // SET PITCH +{ + int NP; + if(val>0x3fff) NP=0x3fff; // get pitch val + else NP=val; + + s_chan[ch].iRawPitch=NP; + + NP=(44100L*NP)/4096L; // calc frequency + if(NP<1) NP=1; // some security + s_chan[ch].iActFreq=NP; // store frequency +}