X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=4759f3fc2c8ed1592f6c141a8b9fa549d05d1885;hp=06cc4761c0356fa6199b806fcf6c85c2ec8cc98c;hb=f2aec10aa8e3befe7e89070e8559d070835cc23e;hpb=be1cb678c445cb8d9a4d707c698f0dc600a490ea diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index 06cc4761..4759f3fc 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -24,7 +24,6 @@ #include "externals.h" #include "registers.h" -#include "cfg.h" #include "dsoundoss.h" #ifdef ENABLE_NLS @@ -37,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 @@ -47,6 +46,8 @@ } while (0) #endif +#define PSXCLK 33868800 /* 33.8688 MHz */ + /* #if defined (USEMACOSX) static char * libraryName = N_("Mac OS X Sound"); @@ -80,10 +81,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; int iUseReverb=2; int iUseInterpolation=2; @@ -94,19 +91,14 @@ REVERBInfo rvb; unsigned int dwNoiseVal; // global noise generator unsigned int dwNoiseCount; -int iSpuAsyncWait=0; unsigned short spuCtrl=0; // some vars to store psx reg infos 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 int dwNewChannel=0; // flags for faster testing, if new channel starts unsigned int dwChannelOn=0; // not silent channels unsigned int dwPendingChanOff=0; @@ -128,9 +120,12 @@ int iFMod[NSSIZE]; int iCycle = 0; short * pS; +int had_dma; 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 +static int cycles_since_update; + +#define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2 //////////////////////////////////////////////////////////////////////// // CODE AREA @@ -220,9 +215,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]; @@ -336,7 +332,7 @@ INLINE void StoreInterpolationVal(int ch,int fa) //////////////////////////////////////////////////////////////////////// -INLINE int iGetInterpolationVal(int ch) +INLINE int iGetInterpolationVal(int ch, int spos) { int fa; @@ -348,7 +344,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; @@ -367,7 +363,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; @@ -396,9 +392,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(); } } @@ -536,7 +532,7 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ { \ sbpos = 0; \ d = decode_block(ch); \ - if(d && iSPUIRQWait) \ + if(d) \ { \ ret = ns; \ goto out; \ @@ -567,7 +563,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 \ @@ -621,7 +617,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 @@ -665,27 +661,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(int forced_updates) { int volmult = iVolume; int ns,ns_from,ns_to; 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 @@ -694,24 +681,15 @@ static void *MAINThread(void *arg) // until enuff free place is available/a new channel gets // started - if(dwNewChannel) // new channel should start immedately? - { // (at least one bit 0 ... MAXCHANNEL is set?) - iSecureStart++; // -> set iSecure - if(iSecureStart>5) iSecureStart=0; // (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance) - } - else iSecureStart=0; // 0: no new channel should start - - while(!iSecureStart && !bEndThread && // no new start? no thread end? - (SoundGetBytesBuffered()>TESTSIZE)) // and still enuff data in sound buffer? + if(!forced_updates && SoundGetBytesBuffered()) // 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; } + cycles_since_update = 0; + if(forced_updates > 0) + forced_updates--; + //--------------------------------------------------// continue from irq handling in timer mode? ns_from=0; @@ -763,7 +741,7 @@ static void *MAINThread(void *arg) // advance "stopped" channels that can cause irqs // (all chans are always playing on the real thing..) - if(!bIRQReturn && (spuCtrl&CTRL_IRQ)) + if(spuCtrl&CTRL_IRQ) for(ch=0;ch pSpuIrq && s_chan[ch].pLoop > pSpuIrq) continue; - s_chan[ch].spos += s_chan[ch].sinc * NSSIZE; + s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns_from); while(s_chan[ch].spos >= 28 * 0x10000) { unsigned char *start = s_chan[ch].pCurr; // no need for bIRQReturn since the channel is silent - iSpuAsyncWait |= skip_block(ch); + skip_block(ch); if(start == s_chan[ch].pCurr) { // looping on self @@ -790,24 +768,8 @@ static void *MAINThread(void *arg) } } - if(bIRQReturn && iSPUIRQWait) // special return for "spu irq - wait for cpu action" - { - iSpuAsyncWait=1; - bIRQReturn=0; - if(iUseTimer!=2) - { - DWORD dwWatchTime=timeGetTime_spu()+2500; - - while(iSpuAsyncWait && !bEndThread && - timeGetTime_spu() no init, no call + if(!bSpuInit) return; // -> no init, no call - MAINThread(0); // -> linux high-compat mode + cycles_since_update += cycle; - // 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; + if(dwNewChannel || had_dma) + { + forced_updates = 1; + do_update = 1; + had_dma = 0; } + + // once per frame should be fine (using a bit more because of BIAS) + if(cycles_since_update > PSXCLK/60 * 5/4) + do_update = 1; + + if(do_update) + do_samples(forced_updates); } // SPU UPDATE... new epsxe func @@ -948,45 +910,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 @@ -1011,7 +948,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; @@ -1026,7 +963,11 @@ void SetupStreams(void) 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 @@ -1053,16 +994,12 @@ 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)); pSpuIrq = 0; - //iSPUIRQWait = 0; lastch = -1; - //ReadConfigSPU(); // read user stuff SetupStreams(); // prepare streaming return 0; @@ -1074,7 +1011,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; @@ -1088,7 +1024,6 @@ long CALLBACK SPUclose(void) bSPUIsOpen = 0; // no more open - RemoveTimer(); // no more feeding RemoveSound(); // no more sound handling return 0; @@ -1099,6 +1034,7 @@ long CALLBACK SPUshutdown(void) { SPUclose(); RemoveStreams(); // no more streaming + bSpuInit=0; return 0; }