X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=f5aab9f1f925bb6f6a8f45685d6f090a28003579;hp=bea8414e80e8e11f7c4bb023c5bd31d53af082e4;hb=6d75977b13fede33db381324c610561c6e723a8b;hpb=587fa7de9b496a0b7fa1d52d393733886602ca83 diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index bea8414e..f5aab9f1 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -24,9 +24,7 @@ #include "externals.h" #include "registers.h" -#include "cfg.h" #include "dsoundoss.h" -#include "regs.h" #ifdef ENABLE_NLS #include @@ -38,7 +36,7 @@ #define N_(x) (x) #endif -#ifdef __arm__ +#ifdef __ARM_ARCH_7A__ #define ssat32_to_16(v) \ asm("ssat %0,#16,%1" : "=r" (v) : "r" (v)) #else @@ -81,7 +79,6 @@ unsigned char * pMixIrq=0; int iVolume=768; // 1024 is 1.0 int iXAPitch=1; -int iUseTimer=2; int iSPUIRQWait=1; int iDebugMode=0; int iRecordMode=0; @@ -101,16 +98,13 @@ unsigned short spuCtrl=0; // some vars to store psx unsigned short spuStat=0; unsigned short spuIrq=0; unsigned long spuAddr=0xffffffff; // address into spu mem -int bEndThread=0; // thread handlers -int bThreadEnded=0; int bSpuInit=0; 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; @@ -132,6 +126,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 //////////////////////////////////////////////////////////////////////// @@ -220,9 +216,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]; @@ -286,19 +283,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; @@ -306,12 +293,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; @@ -351,7 +333,7 @@ INLINE void StoreInterpolationVal(int ch,int fa) //////////////////////////////////////////////////////////////////////// -INLINE int iGetInterpolationVal(int ch) +INLINE int iGetInterpolationVal(int ch, int spos) { int fa; @@ -363,7 +345,7 @@ INLINE int iGetInterpolationVal(int ch) case 3: // cubic interpolation { long xd;int gpos; - xd = ((s_chan[ch].spos) >> 1)+1; + xd = (spos >> 1)+1; gpos = s_chan[ch].SB[28]; fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0; @@ -382,7 +364,7 @@ INLINE int iGetInterpolationVal(int ch) case 2: // gauss interpolation { int vl, vr;int gpos; - vl = (s_chan[ch].spos >> 6) & ~3; + vl = (spos >> 6) & ~3; gpos = s_chan[ch].SB[28]; vr=(gauss[vl]*gval0)&~2047; vr+=(gauss[vl+1]*gval(1))&~2047; @@ -411,9 +393,9 @@ INLINE int iGetInterpolationVal(int ch) static void do_irq(void) { - if(!(spuStat & STAT_IRQ)) + //if(!(spuStat & STAT_IRQ)) { - spuStat |= STAT_IRQ; + spuStat |= STAT_IRQ; // asserted status? if(irqCallback) irqCallback(); } } @@ -453,14 +435,12 @@ static int decode_block(int ch) int ret = 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 @@ -495,10 +475,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].bJump = flags & 1; return ret; } @@ -510,9 +494,6 @@ 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(); @@ -520,13 +501,14 @@ static int skip_block(int ch) } if(flags & 4) - s_chan[ch].pLoop=start; + 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; } @@ -582,7 +564,7 @@ out: \ make_do_samples(default, fmod_recv_check, , StoreInterpolationVal(ch, fa), - ChanBuf[ns] = iGetInterpolationVal(ch), ) + ChanBuf[ns] = iGetInterpolationVal(ch, spos), ) make_do_samples(noint, , fa = s_chan[ch].SB[29], , ChanBuf[ns] = fa, s_chan[ch].SB[29] = fa) #define simple_interp_store \ @@ -636,7 +618,7 @@ static int do_samples_noise(int ch, int ns, int ns_to) } #ifdef __arm__ -// asm code +// asm code; lv and rv must be 0-3fff 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 @@ -680,27 +662,18 @@ static void mix_chan_rvb(int start, int count, int lv, int rv) //////////////////////////////////////////////////////////////////////// // MAIN SPU FUNCTION -// here is the main job handler... thread, timer or direct func call +// here is the main job handler... // basically the whole sound processing is done in this fat func! //////////////////////////////////////////////////////////////////////// -// 5 ms waiting phase, if buffer is full and no new sound has to get started -// .. can be made smaller (smallest val: 1 ms), but bigger waits give -// better performance - -#define PAUSE_W 5 -#define PAUSE_L 5000 - -//////////////////////////////////////////////////////////////////////// - -static void *MAINThread(void *arg) +static int do_samples(void) { int volmult = iVolume; int ns,ns_from,ns_to; - int ch,d; + int ch,d,silentch; int bIRQReturn=0; - while(!bEndThread) // until we are shutting down + while(1) { // ok, at the beginning we are looking if there is // enuff free place in the dsound/oss buffer to @@ -716,15 +689,10 @@ static void *MAINThread(void *arg) } else iSecureStart=0; // 0: no new channel should start - while(!iSecureStart && !bEndThread && // no new start? no thread end? + if(!iSecureStart && // no new start? (SoundGetBytesBuffered()>TESTSIZE)) // and still enuff data in sound buffer? { - iSecureStart=0; // reset secure - - if(iUseTimer) return 0; // linux no-thread mode? bye - usleep(PAUSE_L); // else sleep for x ms (linux) - - if(dwNewChannel) iSecureStart=1; // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop + return 0; } //--------------------------------------------------// continue from irq handling in timer mode? @@ -737,6 +705,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 -// //--------------------------------------------------// @@ -746,9 +716,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; // 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< no init, no call + if(!bSpuInit) return; // -> no init, no call - MAINThread(0); // -> linux high-compat mode + do_samples(); - // abuse iSpuAsyncWait mechanism to reduce calls to above function - // to make it do larger chunks - // note: doing it less often than once per frame causes skips - iSpuAsyncWait=1; - } + // abuse iSpuAsyncWait mechanism to reduce calls to above function + // to make it do larger chunks + // note: doing it less often than once per frame causes skips + iSpuAsyncWait=1; } // SPU UPDATE... new epsxe func @@ -967,45 +914,20 @@ 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 -void SetupTimer(void) +// to be called after state load +void ClearWorkingState(void) { memset(SSumLR,0,sizeof(SSumLR)); // init some mixing buffers - memset(iFMod,0,NSSIZE*sizeof(int)); + memset(iFMod,0,sizeof(iFMod)); pS=(short *)pSpuBuffer; // setup soundbuffer pointer - - bEndThread=0; // init thread vars - bThreadEnded=0; - bSpuInit=1; // flag: we are inited - - if(!iUseTimer) // linux: use thread - { - pthread_create(&thread, NULL, MAINThread, NULL); - } -} - -// REMOVETIMER: kill threads/timers -void RemoveTimer(void) -{ - bEndThread=1; // raise flag to end thread - - if(!iUseTimer) // linux tread? - { - int i=0; - while(!bThreadEnded && i<2000) {usleep(1000L);i++;} // -> wait until thread has ended - if(thread!=(pthread_t)-1) {pthread_cancel(thread);thread=(pthread_t)-1;} // -> cancel thread anyway - } - - bThreadEnded=0; // no more spu is running - bSpuInit=0; } // SETUPSTREAMS: init most of the spu buffers @@ -1030,7 +952,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; @@ -1042,11 +964,14 @@ 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; } - pMixIrq=spuMemC; // enable decoded buffer irqs by setting the address + pMixIrq=spuMemC; // enable decoded buffer irqs by setting the address + + ClearWorkingState(); + + bSpuInit=1; // flag: we are inited } // REMOVESTREAMS: free most buffer @@ -1073,8 +998,6 @@ long CALLBACK SPUinit(void) spuIrq = 0; spuAddr = 0xffffffff; - bEndThread = 0; - bThreadEnded = 0; spuMemC = (unsigned char *)spuMem; pMixIrq = 0; memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN)); @@ -1082,7 +1005,6 @@ long CALLBACK SPUinit(void) //iSPUIRQWait = 0; lastch = -1; - //ReadConfigSPU(); // read user stuff SetupStreams(); // prepare streaming return 0; @@ -1094,7 +1016,6 @@ long CALLBACK SPUopen(void) if (bSPUIsOpen) return 0; // security for some stupid main emus SetupSound(); // setup sound (before init!) - SetupTimer(); // timer for feeding data bSPUIsOpen = 1; @@ -1108,7 +1029,6 @@ long CALLBACK SPUclose(void) bSPUIsOpen = 0; // no more open - RemoveTimer(); // no more feeding RemoveSound(); // no more sound handling return 0; @@ -1119,6 +1039,7 @@ long CALLBACK SPUshutdown(void) { SPUclose(); RemoveStreams(); // no more streaming + bSpuInit=0; return 0; } @@ -1187,9 +1108,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