X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=d5a821599c2adcafaf633486220c2a6d89ba65b4;hb=e4f075af4e4ba79332c72809d3bb4ba6e2895253;hp=b087cdfd674dad32d151ebc8e791aa69cb62fe8a;hpb=f8edb5bc279ba09aa7bc762da51236fd368827b0;p=pcsx_rearmed.git diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index b087cdfd..d5a82159 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 ***************************************************************************/ /*************************************************************************** @@ -46,6 +46,8 @@ } while (0) #endif +#define PSXCLK 33868800 /* 33.8688 MHz */ + /* #if defined (USEMACOSX) static char * libraryName = N_("Mac OS X Sound"); @@ -79,9 +81,6 @@ unsigned char * pMixIrq=0; 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; @@ -92,7 +91,6 @@ 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; @@ -122,8 +120,10 @@ 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 cycles_since_update; #define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2 @@ -250,6 +250,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 //////////////////////////////////////////////////////////////////////// @@ -275,6 +295,8 @@ INLINE void StartSound(int ch) {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;} // -> start with more decoding else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;} // -> no/simple interpolation starts with one 44100 decoding + check_irq(ch, s_chan[ch].pCurr); // just in case + dwNewChannel&=~(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; } predict_nr=(int)start[0]; @@ -459,29 +466,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); - } + + ret = check_irq(ch, start); s_chan[ch].pCurr = start; // store values for next cycle - s_chan[ch].bJump = flags & 1; + s_chan[ch].prevflags = flags; return ret; } @@ -491,24 +491,22 @@ static int skip_block(int ch) { unsigned char *start = s_chan[ch].pCurr; int flags = start[1]; - int ret = 0; - 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].bJump = flags & 1; - return ret; + s_chan[ch].pCurr = start; + s_chan[ch].prevflags = flags; + + return check_irq(ch, start); } #define make_do_samples(name, fmod_code, interp_start, interp1_code, interp2_code, interp_end) \ @@ -532,7 +530,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; \ @@ -665,7 +663,7 @@ static void mix_chan_rvb(int start, int count, int lv, int rv) // basically the whole sound processing is done in this fat func! //////////////////////////////////////////////////////////////////////// -static int do_samples(void) +static int do_samples(int forced_updates) { int volmult = iVolume; int ns,ns_from,ns_to; @@ -681,11 +679,15 @@ static int do_samples(void) // until enuff free place is available/a new channel gets // started - if(!dwNewChannel && SoundGetBytesBuffered()) // still enuff data in sound buffer? + if(!forced_updates && SoundGetBytesBuffered()) // still enuff data in sound buffer? { return 0; } + cycles_since_update = 0; + if(forced_updates > 0) + forced_updates--; + //--------------------------------------------------// continue from irq handling in timer mode? ns_from=0; @@ -737,7 +739,7 @@ static int do_samples(void) // 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 @@ -764,12 +766,8 @@ static int do_samples(void) } } - if(bIRQReturn && iSPUIRQWait) // special return for "spu irq - wait for cpu action" - { - iSpuAsyncWait=1; - bIRQReturn=0; + if(bIRQReturn) // special return for "spu irq - wait for cpu action" return 0; - } //---------------------------------------------------// @@ -824,18 +822,15 @@ static int do_samples(void) // 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(pMixIrq && (spuCtrl&CTRL_IRQ) && pSpuIrq && pSpuIrq=pMixIrq+(ch*0x400) && pSpuIrqspuMemC+0x3ff) pMixIrq=spuMemC; } } @@ -863,16 +858,34 @@ static int do_samples(void) void CALLBACK SPUasync(unsigned long cycle) { + static int old_ctrl; + int forced_updates = 0; + int do_update = 0; + if(!bSpuInit) return; // -> no init, no call - if(iSpuAsyncWait) + cycles_since_update += cycle; + + if(dwNewChannel || had_dma) { - iSpuAsyncWait++; - if(iSpuAsyncWait<=16/FRAG_MSECS) return; - iSpuAsyncWait=0; + forced_updates = 1; + do_update = 1; + had_dma = 0; } - do_samples(); + 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); } // SPU UPDATE... new epsxe func @@ -988,7 +1001,6 @@ long CALLBACK SPUinit(void) pMixIrq = 0; memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN)); pSpuIrq = 0; - //iSPUIRQWait = 0; lastch = -1; SetupStreams(); // prepare streaming