Mercurial > audlegacy-plugins
view src/sexypsf/spu/registers.c @ 2190:36b9f3e6cbcf
demac: added stub for update_song_tuple() for debugging purposes
author | Eugene Zagidullin <e.asphyx@gmail.com> |
---|---|
date | Tue, 27 Nov 2007 18:03:20 +0300 |
parents | 3da1b8942b8b |
children |
line wrap: on
line source
/*************************************************************************** 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 }