X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=69d6217c749baa17c5dc0d19de47cb7ced870655;hp=4930e53af446b1fcbe79af5b0a9cb692b25c72af;hb=89cb20587977b8702a1f96591852feac394ecc4b;hpb=fb552464f06137102fd9ca69a05492265bbdcea7 diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index 4930e53a..69d6217c 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 ***************************************************************************/ /*************************************************************************** @@ -75,15 +75,11 @@ unsigned short spuMem[256*1024]; unsigned char * spuMemC; unsigned char * pSpuIrq=0; unsigned char * pSpuBuffer; -unsigned char * pMixIrq=0; // user settings int iVolume=768; // 1024 is 1.0 int iXAPitch=1; -int iSPUIRQWait=1; -int iDebugMode=0; -int iRecordMode=0; int iUseReverb=2; int iUseInterpolation=2; @@ -123,6 +119,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 @@ -253,6 +251,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 //////////////////////////////////////////////////////////////////////// @@ -393,15 +411,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; @@ -437,24 +446,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; @@ -462,29 +467,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; } @@ -494,23 +492,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; } @@ -535,11 +532,8 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ { \ sbpos = 0; \ d = decode_block(ch); \ - if(d && iSPUIRQWait) \ - { \ - ret = ns; \ - goto out; \ - } \ + if(d) \ + ret = ns_to = ns + 1; \ } \ \ fa = SB[sbpos++]; \ @@ -551,7 +545,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; \ @@ -588,11 +581,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; } @@ -616,7 +612,7 @@ static int do_samples_noise(int ch, int ns, int ns_to) ChanBuf[ns] = (signed short)dwNoiseVal; } - return -1; + return ret; } #ifdef __arm__ @@ -662,6 +658,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... @@ -727,12 +740,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< 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; @@ -771,9 +788,19 @@ static int do_samples(int forced_updates) } } - if(bIRQReturn && iSPUIRQWait) // special return for "spu irq - wait for cpu action" + if(bIRQReturn) // special return for "spu irq - wait for cpu action" return 0; + if(unlikely(silentch & decode_dirty_ch & (1<<1))) // must clear silent channel decode buffers + { + memset(&spuMem[0x800/2], 0, 0x400); + decode_dirty_ch &= ~(1<<1); + } + if(unlikely(silentch & decode_dirty_ch & (1<<3))) + { + memset(&spuMem[0xc00/2], 0, 0x400); + decode_dirty_ch &= ~(1<<3); + } //---------------------------------------------------// //- here we have another 1 ms of sound data @@ -827,21 +854,17 @@ static int do_samples(int forced_updates) // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here // in some of Peops timer modes. So: we ignore this option here (for now). - if(pMixIrq) + if(unlikely((spuCtrl&CTRL_IRQ) && pSpuIrq && pSpuIrq 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(); } } + decode_pos = (decode_pos + NSSIZE) & 0x1ff; InitREVERB(); @@ -866,6 +889,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; @@ -880,9 +904,16 @@ 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); @@ -966,8 +997,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 @@ -998,10 +1027,9 @@ 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; - //iSPUIRQWait = 0; lastch = -1; SetupStreams(); // prepare streaming