X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=df95f35db8578e70ae16912c6f3b292c8029bc9a;hp=e6c5449d3cf8f0c657f75d54d5539284a6c8fa4a;hb=554a2220f2413cc29d7912ad3f7d91c9e64284cf;hpb=07a6dd2ce2c0c8ea2de11c30c134c877e7c7b0fb diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index e6c5449d..df95f35d 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -26,7 +26,6 @@ #include "registers.h" #include "cfg.h" #include "dsoundoss.h" -#include "regs.h" #ifdef ENABLE_NLS #include @@ -38,6 +37,16 @@ #define N_(x) (x) #endif +#ifdef __ARM_ARCH_7A__ + #define ssat32_to_16(v) \ + asm("ssat %0,#16,%1" : "=r" (v) : "r" (v)) +#else + #define ssat32_to_16(v) do { \ + if (v < -32768) v = -32768; \ + else if (v > 32767) v = 32767; \ + } while (0) +#endif + /* #if defined (USEMACOSX) static char * libraryName = N_("Mac OS X Sound"); @@ -69,7 +78,7 @@ unsigned char * pMixIrq=0; // user settings -int iVolume=3; +int iVolume=768; // 1024 is 1.0 int iXAPitch=1; int iUseTimer=2; int iSPUIRQWait=1; @@ -83,7 +92,8 @@ int iUseInterpolation=2; SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) REVERBInfo rvb; -unsigned long dwNoiseVal=1; // global noise generator +unsigned int dwNoiseVal; // global noise generator +unsigned int dwNoiseCount; int iSpuAsyncWait=0; unsigned short spuCtrl=0; // some vars to store psx reg infos @@ -97,9 +107,10 @@ int bSPUIsOpen=0; static pthread_t thread = (pthread_t)-1; // thread id (linux) -unsigned long dwNewChannel=0; // flags for faster testing, if new channel starts -unsigned long dwChannelOn=0; -unsigned long dwPendingChanOff=0; +unsigned int dwNewChannel=0; // flags for faster testing, if new channel starts +unsigned int dwChannelOn=0; // not silent channels +unsigned int dwPendingChanOff=0; +unsigned int dwChannelDead=0; // silent+not useful channels void (CALLBACK *irqCallback)(void)=0; // func of main emu, called on spu irq void (CALLBACK *cddavCallback)(unsigned short,unsigned short)=0; @@ -111,8 +122,8 @@ static const int f[8][2] = { { 0, 0 }, { 115, -52 }, { 98, -55 }, { 122, -60 } }; -int ChanBuf[NSSIZE]; -int SSumLR[NSSIZE*2]; +int ChanBuf[NSSIZE+3]; +int SSumLR[(NSSIZE+3)*2]; int iFMod[NSSIZE]; int iCycle = 0; short * pS; @@ -121,6 +132,8 @@ int lastch=-1; // last channel processed on spu irq in timer mode static int lastns=0; // last ns pos static int iSecureStart=0; // secure start counter +#define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2 + //////////////////////////////////////////////////////////////////////// // CODE AREA //////////////////////////////////////////////////////////////////////// @@ -209,9 +222,10 @@ INLINE void InterpolateUp(int ch) s_chan[ch].SB[32]=0; s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L; - if(s_chan[ch].sinc<=0x8000) - s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1)); - else s_chan[ch].SB[29]+=s_chan[ch].SB[28]; + //if(s_chan[ch].sinc<=0x8000) + // s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1)); + //else + s_chan[ch].SB[29]+=s_chan[ch].SB[28]; } else // no flags? add bigger val (if possible), calc smaller step, set flag1 s_chan[ch].SB[29]+=s_chan[ch].SB[28]; @@ -257,8 +271,8 @@ INLINE void StartSound(int ch) //s_chan[ch].bStop=0; //s_chan[ch].bOn=1; - s_chan[ch].s_1=0; // init mixing vars - s_chan[ch].s_2=0; + s_chan[ch].SB[26]=0; // init mixing vars + s_chan[ch].SB[27]=0; s_chan[ch].iSBPos=28; s_chan[ch].SB[29]=0; // init our interpolation helpers @@ -275,19 +289,9 @@ INLINE void StartSound(int ch) // ALL KIND OF HELPERS //////////////////////////////////////////////////////////////////////// -INLINE void VoiceChangeFrequency(int ch) -{ - s_chan[ch].iUsedFreq=s_chan[ch].iActFreq; // -> take it and calc steps - s_chan[ch].sinc=s_chan[ch].iRawPitch<<4; - if(!s_chan[ch].sinc) s_chan[ch].sinc=1; - if(iUseInterpolation==1) s_chan[ch].SB[32]=1; // -> freq change in simle imterpolation mode: set flag -} - -//////////////////////////////////////////////////////////////////////// - INLINE int FModChangeFrequency(int ch,int ns) { - int NP=s_chan[ch].iRawPitch; + unsigned int NP=s_chan[ch].iRawPitch; int sinc; NP=((32768L+iFMod[ns])*NP)/32768L; @@ -295,12 +299,7 @@ INLINE int FModChangeFrequency(int ch,int ns) if(NP>0x3fff) NP=0x3fff; if(NP<0x1) NP=0x1; - NP=(44100L*NP)/(4096L); // calc frequency - - s_chan[ch].iActFreq=NP; - s_chan[ch].iUsedFreq=NP; - sinc=(((NP/10)<<16)/4410); - if(!sinc) sinc=1; + sinc=NP<<4; // calc frequency if(iUseInterpolation==1) // freq change in simple interpolation mode s_chan[ch].SB[32]=1; iFMod[ns]=0; @@ -310,47 +309,13 @@ INLINE int FModChangeFrequency(int ch,int ns) //////////////////////////////////////////////////////////////////////// -// noise handler... just produces some noise data -// surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... -// and sometimes the noise will be used as fmod modulation... pfff - -INLINE int iGetNoiseVal(int ch) -{ - int fa; - - if((dwNoiseVal<<=1)&0x80000000L) - { - dwNoiseVal^=0x0040001L; - fa=((dwNoiseVal>>2)&0x7fff); - fa=-fa; - } - else fa=(dwNoiseVal>>2)&0x7fff; - - // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val - fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1)); - if(fa>32767L) fa=32767L; - if(fa<-32767L) fa=-32767L; - s_chan[ch].iOldNoise=fa; - - if(iUseInterpolation<2) // no gauss/cubic interpolation? - s_chan[ch].SB[29] = fa; // -> store noise val in "current sample" slot - return fa; -} - -//////////////////////////////////////////////////////////////////////// - INLINE void StoreInterpolationVal(int ch,int fa) { if(s_chan[ch].bFMod==2) // fmod freq channel s_chan[ch].SB[29]=fa; else { - if((spuCtrl&0x4000)==0) fa=0; // muted? - else // else adjust - { - if(fa>32767L) fa=32767L; - if(fa<-32767L) fa=-32767L; - } + ssat32_to_16(fa); if(iUseInterpolation>=2) // gauss/cubic interpolation { @@ -441,25 +406,47 @@ static void do_irq(void) } } +static void decode_block_data(int *dest, const unsigned char *src, int predict_nr, int shift_factor) +{ + int nSample; + int fa, s_1, s_2, d, s; + + s_1 = dest[27]; + s_2 = dest[26]; + + for (nSample = 0; nSample < 28; src++) + { + d = (int)*src; + s = (int)(signed short)((d & 0x0f) << 12); + + fa = s >> shift_factor; + fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + dest[nSample++] = fa; + + s = (int)(signed short)((d & 0xf0) << 8); + fa = s >> shift_factor; + fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + dest[nSample++] = fa; + } +} + static int decode_block(int ch) { unsigned char *start; - unsigned int nSample; - int predict_nr,shift_factor,flags,d,s; - int fa,s_1,s_2; + int predict_nr,shift_factor,flags; int ret = 0; - s_chan[ch].iSBPos=0; - start=s_chan[ch].pCurr; // set up the current pos - if(start == (unsigned char*)-1 || // special "stop" sign - (dwPendingChanOff&(1< turn everything off dwPendingChanOff&=~(1< and done for this channel } //////////////////////////////////////////// irq check @@ -473,42 +460,19 @@ static int decode_block(int ch) } } - s_1=s_chan[ch].s_1; - s_2=s_chan[ch].s_2; - - predict_nr=(int)*start;start++; + predict_nr=(int)start[0]; shift_factor=predict_nr&0xf; predict_nr >>= 4; - flags=(int)*start;start++; - // -------------------------------------- // - - for (nSample=0;nSample<28;start++) - { - d=(int)*start; - s=((d&0xf)<<12); - if(s&0x8000) s|=0xffff0000; - - fa=(s >> shift_factor); - fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2=s_1;s_1=fa; - s=((d & 0xf0) << 8); - - s_chan[ch].SB[nSample++]=fa; - - if(s&0x8000) s|=0xffff0000; - fa=(s>>shift_factor); - fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2=s_1;s_1=fa; - - s_chan[ch].SB[nSample++]=fa; - } + decode_block_data(s_chan[ch].SB, start + 2, predict_nr, shift_factor); //////////////////////////////////////////// flag handler - if((flags&4) && (!s_chan[ch].bIgnoreLoop)) - s_chan[ch].pLoop=start-16; // loop adress + flags=(int)start[1]; + if(flags&4) + s_chan[ch].pLoop=start; // loop adress + start+=16; if(flags&1) // 1: stop/loop { if(!(flags&2)) @@ -517,12 +481,14 @@ static int decode_block(int ch) start = s_chan[ch].pLoop; } - if (start - spuMemC >= 0x80000) - start = (unsigned char*)-1; + if (start - spuMemC >= 0x80000) { + // most likely wrong + start = spuMemC; + printf("ch%d oflow\n", ch); + } - s_chan[ch].pCurr=start; // store values for next cycle - s_chan[ch].s_1=s_1; - s_chan[ch].s_2=s_2; + s_chan[ch].pCurr = start; // store values for next cycle + s_chan[ch].bJump = flags & 1; return ret; } @@ -534,23 +500,21 @@ static int skip_block(int ch) int flags = start[1]; int ret = 0; - // Tron Bonne hack, probably wrong (could be wrong memory contents..) - if(flags & ~7) flags = 0; - if(start == pSpuIrq) { do_irq(); ret = 1; } - if((flags & 4) && !s_chan[ch].bIgnoreLoop) - s_chan[ch].pLoop=start; + if(flags & 4) + s_chan[ch].pLoop = start; s_chan[ch].pCurr += 16; if(flags & 1) s_chan[ch].pCurr = s_chan[ch].pLoop; + s_chan[ch].bJump = flags & 1; return ret; } @@ -559,6 +523,8 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ { \ int sinc = s_chan[ch].sinc; \ int spos = s_chan[ch].spos; \ + int sbpos = s_chan[ch].iSBPos; \ + int *SB = s_chan[ch].SB; \ int ret = -1; \ int d, fa; \ interp_start; \ @@ -569,8 +535,9 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ \ while (spos >= 0x10000) \ { \ - if(s_chan[ch].iSBPos == 28) \ + if(sbpos == 28) \ { \ + sbpos = 0; \ d = decode_block(ch); \ if(d && iSPUIRQWait) \ { \ @@ -579,7 +546,7 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ } \ } \ \ - fa = s_chan[ch].SB[s_chan[ch].iSBPos++]; \ + fa = SB[sbpos++]; \ interp1_code; \ spos -= 0x10000; \ } \ @@ -591,6 +558,7 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ out: \ s_chan[ch].sinc = sinc; \ s_chan[ch].spos = spos; \ + s_chan[ch].iSBPos = sbpos; \ interp_end; \ \ return ret; \ @@ -623,6 +591,8 @@ make_do_samples(simple, , , static int do_samples_noise(int ch, int ns, int ns_to) { + int level, shift, bit; + s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns); while (s_chan[ch].spos >= 28*0x10000) { @@ -630,12 +600,72 @@ static int do_samples_noise(int ch, int ns, int ns_to) s_chan[ch].spos -= 28*0x10000; } + // modified from DrHell/shalma, no fraction + level = (spuCtrl >> 10) & 0x0f; + level = 0x8000 >> level; + for (; ns < ns_to; ns++) - ChanBuf[ns] = iGetNoiseVal(ch); + { + dwNoiseCount += 2; + if (dwNoiseCount >= level) + { + dwNoiseCount -= level; + shift = (dwNoiseVal >> 10) & 0x1f; + bit = (0x69696969 >> shift) & 1; + if (dwNoiseVal & 0x8000) + bit ^= 1; + dwNoiseVal = (dwNoiseVal << 1) | bit; + } + + ChanBuf[ns] = (signed short)dwNoiseVal; + } return -1; } +#ifdef __ARM_ARCH_7A__ +// asm code +extern void mix_chan(int start, int count, int lv, int rv); +extern void mix_chan_rvb(int start, int count, int lv, int rv); +#else +static void mix_chan(int start, int count, int lv, int rv) +{ + int *dst = SSumLR + start * 2; + const int *src = ChanBuf + start; + int l, r; + + while (count--) + { + int sval = *src++; + + l = (sval * lv) >> 14; + r = (sval * rv) >> 14; + *dst++ += l; + *dst++ += r; + } +} + +static void mix_chan_rvb(int start, int count, int lv, int rv) +{ + int *dst = SSumLR + start * 2; + int *drvb = sRVBStart + start * 2; + const int *src = ChanBuf + start; + int l, r; + + while (count--) + { + int sval = *src++; + + l = (sval * lv) >> 14; + r = (sval * rv) >> 14; + *dst++ += l; + *dst++ += r; + *drvb++ += l; + *drvb++ += r; + } +} +#endif + //////////////////////////////////////////////////////////////////////// // MAIN SPU FUNCTION // here is the main job handler... thread, timer or direct func call @@ -653,13 +683,9 @@ static int do_samples_noise(int ch, int ns, int ns_to) static void *MAINThread(void *arg) { + int volmult = iVolume; int ns,ns_from,ns_to; -#if !defined(_MACOSX) && !defined(__arm__) - int voldiv = iVolume; -#else - const int voldiv = 2; -#endif - int ch,d; + int ch,d,silentch; int bIRQReturn=0; while(!bEndThread) // until we are shutting down @@ -699,6 +725,8 @@ static void *MAINThread(void *arg) ch=lastch; ns_from=lastns; lastch=-1; // -> setup all kind of vars to continue } + silentch=~(dwChannelOn|dwNewChannel); + //--------------------------------------------------// //- main channel loop -// //--------------------------------------------------// @@ -708,9 +736,6 @@ static void *MAINThread(void *arg) if(dwNewChannel&(1< pSpuIrq && s_chan[ch].pLoop > pSpuIrq) continue; - if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq) // new psx frequency? - VoiceChangeFrequency(ch); - s_chan[ch].spos += s_chan[ch].sinc * NSSIZE; while(s_chan[ch].spos >= 28 * 0x10000) { - unsigned char *start=s_chan[ch].pCurr; + unsigned char *start = s_chan[ch].pCurr; - bIRQReturn |= skip_block(ch); + // no need for bIRQReturn since the channel is silent + iSpuAsyncWait |= skip_block(ch); if(start == s_chan[ch].pCurr) { // looping on self - s_chan[ch].pCurr=(unsigned char *)-1; + dwChannelDead |= 1< 32767) d = 32767; + d = SSumLR[ns]; SSumLR[ns] = 0; + d = d * volmult >> 10; + ssat32_to_16(d); *pS++ = d; ns++; - SSumLR[ns] += MixREVERBRight(); - - d = SSumLR[ns] / voldiv; SSumLR[ns] = 0; - if(d < -32767) d = -32767; if(d > 32767) d = 32767; + d = SSumLR[ns]; SSumLR[ns] = 0; + d = d * volmult >> 10; + ssat32_to_16(d); *pS++ = d; ns++; } @@ -866,7 +885,7 @@ static void *MAINThread(void *arg) // feed the sound // wanna have around 1/60 sec (16.666 ms) updates - if (iCycle++ > 16) + if (iCycle++ > 16/FRAG_MSECS) { SoundFeedStreamData((unsigned char *)pSpuBuffer, ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer)); @@ -885,12 +904,14 @@ static void *MAINThread(void *arg) // SPU ASYNC... even newer epsxe func // 1 time every 'cycle' cycles... harhar +// rearmed: called every 2ms now + void CALLBACK SPUasync(unsigned long cycle) { if(iSpuAsyncWait) { iSpuAsyncWait++; - if(iSpuAsyncWait<=16) return; + if(iSpuAsyncWait<=16/2) return; iSpuAsyncWait=0; } @@ -932,12 +953,12 @@ void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap) } // CDDA AUDIO -void CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes) +int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes) { - if (!pcm) return; - if (nbytes<=0) return; + if (!pcm) return -1; + if (nbytes<=0) return -1; - FeedCDDA((unsigned char *)pcm, nbytes); + return FeedCDDA((unsigned char *)pcm, nbytes); } // SETUPTIMER: init of certain buffers and threads/timers @@ -995,7 +1016,7 @@ void SetupStreams(void) XAFeed = XAStart; CDDAStart = // alloc cdda buffer - (uint32_t *)malloc(16384 * sizeof(uint32_t)); + (uint32_t *)malloc(CDDA_BUFFER_SIZE); CDDAEnd = CDDAStart + 16384; CDDAPlay = CDDAStart; CDDAFeed = CDDAStart; @@ -1007,7 +1028,6 @@ void SetupStreams(void) // s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL); s_chan[i].ADSRX.SustainLevel = 0xf; // -> init sustain s_chan[i].pLoop=spuMemC; - s_chan[i].pStart=spuMemC; s_chan[i].pCurr=spuMemC; } @@ -1036,8 +1056,6 @@ long CALLBACK SPUinit(void) memset((void *)&rvb, 0, sizeof(REVERBInfo)); InitADSR(); - iVolume = 3; - iReverbOff = -1; spuIrq = 0; spuAddr = 0xffffffff; bEndThread = 0; @@ -1154,9 +1172,9 @@ char * SPUgetLibInfos(void) */ // debug -void spu_get_debug_info(int *chans_out, int *fmod_chans_out, int *noise_chans_out) +void spu_get_debug_info(int *chans_out, int *run_chans, int *fmod_chans_out, int *noise_chans_out) { - int ch = 0, fmod_chans = 0, noise_chans = 0; + int ch = 0, fmod_chans = 0, noise_chans = 0, irq_chans = 0; for(;ch