X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=1456a21cd92834d7e78ae01bef319223d2c575a9;hp=4759f3fc2c8ed1592f6c141a8b9fa549d05d1885;hb=e34a4bd3b3eec3f95f5ce0cac1c4d47bf03a0409;hpb=f2aec10aa8e3befe7e89070e8559d070835cc23e diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index 4759f3fc..1456a21c 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -5,7 +5,7 @@ copyright : (C) 2002 by Pete Bernert email : BlackDove@addcom.de - Portions (C) Gražvydas "notaz" Ignotas, 2010-2011 + Portions (C) Gražvydas "notaz" Ignotas, 2010-2012 ***************************************************************************/ /*************************************************************************** @@ -24,7 +24,8 @@ #include "externals.h" #include "registers.h" -#include "dsoundoss.h" +#include "out.h" +#include "arm_features.h" #ifdef ENABLE_NLS #include @@ -75,7 +76,6 @@ unsigned short spuMem[256*1024]; unsigned char * spuMemC; unsigned char * pSpuIrq=0; unsigned char * pSpuBuffer; -unsigned char * pMixIrq=0; // user settings @@ -120,6 +120,8 @@ int iFMod[NSSIZE]; int iCycle = 0; short * pS; +static int decode_dirty_ch; +int decode_pos; int had_dma; int lastch=-1; // last channel processed on spu irq in timer mode static int lastns=0; // last ns pos @@ -242,7 +244,7 @@ INLINE void InterpolateDown(int ch) // helpers for gauss interpolation #define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos]) -#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3]) +#define gval(x) ((int)((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3]) #include "gauss_i.h" @@ -250,6 +252,26 @@ INLINE void InterpolateDown(int ch) #include "xa.c" +static void do_irq(void) +{ + //if(!(spuStat & STAT_IRQ)) + { + spuStat |= STAT_IRQ; // asserted status? + if(irqCallback) irqCallback(); + } +} + +static int check_irq(int ch, unsigned char *pos) +{ + if((spuCtrl & CTRL_IRQ) && pos == pSpuIrq) + { + //printf("ch%d irq %04x\n", ch, pos - spuMemC); + do_irq(); + return 1; + } + return 0; +} + //////////////////////////////////////////////////////////////////////// // START SOUND... called by main thread to setup a new sound on a channel //////////////////////////////////////////////////////////////////////// @@ -365,7 +387,7 @@ INLINE int iGetInterpolationVal(int ch, int spos) int vl, vr;int gpos; vl = (spos >> 6) & ~3; gpos = s_chan[ch].SB[28]; - vr=(gauss[vl]*gval0)&~2047; + vr=(gauss[vl]*(int)gval0)&~2047; vr+=(gauss[vl+1]*gval(1))&~2047; vr+=(gauss[vl+2]*gval(2))&~2047; vr+=(gauss[vl+3]*gval(3))&~2047; @@ -390,15 +412,6 @@ INLINE int iGetInterpolationVal(int ch, int spos) return fa; } -static void do_irq(void) -{ - //if(!(spuStat & STAT_IRQ)) - { - spuStat |= STAT_IRQ; // asserted status? - if(irqCallback) irqCallback(); - } -} - static void decode_block_data(int *dest, const unsigned char *src, int predict_nr, int shift_factor) { int nSample; @@ -434,24 +447,20 @@ static int decode_block(int ch) int ret = 0; start=s_chan[ch].pCurr; // set up the current pos - if(dwPendingChanOff&(1< turn everything off - dwPendingChanOff&=~(1< call main emu - ret = 1; + dwChannelOn&=~(1< turn everything off + s_chan[ch].bStop=1; + s_chan[ch].ADSRX.EnvelopeVol=0; } + + start = s_chan[ch].pLoop; } + else + ret = check_irq(ch, start); // hack, see check_irq below.. predict_nr=(int)start[0]; shift_factor=predict_nr&0xf; @@ -459,29 +468,22 @@ static int decode_block(int ch) decode_block_data(s_chan[ch].SB, start + 2, predict_nr, shift_factor); - //////////////////////////////////////////// flag handler - 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)) - dwPendingChanOff|=1<= 0x80000) { - // most likely wrong + if (start - spuMemC >= 0x80000) start = spuMemC; - printf("ch%d oflow\n", ch); - } s_chan[ch].pCurr = start; // store values for next cycle - s_chan[ch].bJump = flags & 1; + s_chan[ch].prevflags = flags; return ret; } @@ -491,23 +493,22 @@ static int skip_block(int ch) { unsigned char *start = s_chan[ch].pCurr; int flags = start[1]; - int ret = 0; + int ret = check_irq(ch, start); - if(start == pSpuIrq) - { - do_irq(); - ret = 1; - } + if(s_chan[ch].prevflags & 1) + start = s_chan[ch].pLoop; if(flags & 4) s_chan[ch].pLoop = start; - s_chan[ch].pCurr += 16; + start += 16; if(flags & 1) - s_chan[ch].pCurr = s_chan[ch].pLoop; + start = s_chan[ch].pLoop; + + s_chan[ch].pCurr = start; + s_chan[ch].prevflags = flags; - s_chan[ch].bJump = flags & 1; return ret; } @@ -533,10 +534,7 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ sbpos = 0; \ d = decode_block(ch); \ if(d) \ - { \ - ret = ns; \ - goto out; \ - } \ + ret = ns_to = ns + 1; \ } \ \ fa = SB[sbpos++]; \ @@ -548,7 +546,6 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ spos += sinc; \ } \ \ -out: \ s_chan[ch].sinc = sinc; \ s_chan[ch].spos = spos; \ s_chan[ch].iSBPos = sbpos; \ @@ -585,11 +582,14 @@ make_do_samples(simple, , , static int do_samples_noise(int ch, int ns, int ns_to) { int level, shift, bit; + int ret = -1, d; s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns); while (s_chan[ch].spos >= 28*0x10000) { - skip_block(ch); + d = skip_block(ch); + if (d) + ret = ns_to; s_chan[ch].spos -= 28*0x10000; } @@ -613,10 +613,10 @@ static int do_samples_noise(int ch, int ns, int ns_to) ChanBuf[ns] = (signed short)dwNoiseVal; } - return -1; + return ret; } -#ifdef __arm__ +#ifdef HAVE_ARMV5 // 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); @@ -659,6 +659,23 @@ static void mix_chan_rvb(int start, int count, int lv, int rv) } #endif +// 0x0800-0x0bff Voice 1 +// 0x0c00-0x0fff Voice 3 +static void noinline do_decode_bufs(int which, int start, int count) +{ + const int *src = ChanBuf + start; + unsigned short *dst = &spuMem[0x800/2 + which*0x400/2]; + int cursor = decode_pos; + + while (count-- > 0) + { + dst[cursor] = *src++; + cursor = (cursor + 1) & 0x1ff; + } + + // decode_pos is updated and irqs are checked later, after voice loop +} + //////////////////////////////////////////////////////////////////////// // MAIN SPU FUNCTION // here is the main job handler... @@ -672,25 +689,18 @@ static int do_samples(int forced_updates) int ch,d,silentch; int bIRQReturn=0; - while(1) - { - // ok, at the beginning we are looking if there is - // enuff free place in the dsound/oss buffer to - // fill in new data, or if there is a new channel to start. - // if not, we wait (thread) or return (timer/spuasync) - // until enuff free place is available/a new channel gets - // started - - if(!forced_updates && SoundGetBytesBuffered()) // still enuff data in sound buffer? - { - return 0; - } + // ok, at the beginning we are looking if there is + // enuff free place in the dsound/oss buffer to + // fill in new data, or if there is a new channel to start. + // if not, we return until enuff free place is available + // /a new channel gets started - cycles_since_update = 0; - if(forced_updates > 0) - forced_updates--; + if(!forced_updates && out_current->busy()) // still enuff data in sound buffer? + return 0; - //--------------------------------------------------// continue from irq handling in timer mode? + while(!bIRQReturn) + { + cycles_since_update = 0; ns_from=0; ns_to=NSSIZE; @@ -724,12 +734,16 @@ static int do_samples(int forced_updates) bIRQReturn=1; lastch=ch; lastns=ns_to=d; - if(d==0) - break; } MixADSR(ch, ns_from, ns_to); + if(ch==1 || ch==3) + { + do_decode_bufs(ch/2, ns_from, ns_to-ns_from); + decode_dirty_ch |= 1< 0x200 && irq_pos < ((decode_pos+NSSIZE) & 0x1ff))) { - if((spuCtrl&0x40) && pSpuIrq && pSpuIrq=pMixIrq+(ch*0x400) && pSpuIrqspuMemC+0x3ff) pMixIrq=spuMemC; + //printf("decoder irq %x\n", decode_pos); + do_irq(); + bIRQReturn = 1; } } + decode_pos = (decode_pos + NSSIZE) & 0x1ff; InitREVERB(); // feed the sound // wanna have around 1/60 sec (16.666 ms) updates - if (iCycle++ > 16/FRAG_MSECS) + if (iCycle++ >= 16/FRAG_MSECS) { - SoundFeedStreamData((unsigned char *)pSpuBuffer, - ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer)); + out_current->feed(pSpuBuffer, (unsigned char *)pS - pSpuBuffer); pS = (short *)pSpuBuffer; iCycle = 0; + + if(!forced_updates && out_current->busy()) + break; + } + + if(forced_updates > 0) + { + forced_updates--; + if(forced_updates == 0 && out_current->busy()) + break; } } @@ -863,6 +893,7 @@ static int do_samples(int forced_updates) void CALLBACK SPUasync(unsigned long cycle) { + static int old_ctrl; int forced_updates = 0; int do_update = 0; @@ -877,10 +908,17 @@ void CALLBACK SPUasync(unsigned long cycle) had_dma = 0; } - // once per frame should be fine (using a bit more because of BIAS) - if(cycles_since_update > PSXCLK/60 * 5/4) + if((spuCtrl&CTRL_IRQ) && (((spuCtrl^old_ctrl)&CTRL_IRQ) // irq was enabled + || cycles_since_update > PSXCLK/60 / 4)) { + do_update = 1; + forced_updates = cycles_since_update / (PSXCLK/44100) / NSSIZE; + } + // with no irqs, once per frame should be fine (using a bit more because of BIAS) + else if(cycles_since_update > PSXCLK/60 * 5/4) do_update = 1; + old_ctrl = spuCtrl; + if(do_update) do_samples(forced_updates); } @@ -963,8 +1001,6 @@ void SetupStreams(void) s_chan[i].pCurr=spuMemC; } - pMixIrq=spuMemC; // enable decoded buffer irqs by setting the address - ClearWorkingState(); bSpuInit=1; // flag: we are inited @@ -995,7 +1031,7 @@ long CALLBACK SPUinit(void) spuIrq = 0; spuAddr = 0xffffffff; spuMemC = (unsigned char *)spuMem; - pMixIrq = 0; + decode_pos = 0; memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN)); pSpuIrq = 0; lastch = -1; @@ -1024,7 +1060,7 @@ long CALLBACK SPUclose(void) bSPUIsOpen = 0; // no more open - RemoveSound(); // no more sound handling + out_current->finish(); // no more sound handling return 0; }