X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=bea8414e80e8e11f7c4bb023c5bd31d53af082e4;hp=e6c5449d3cf8f0c657f75d54d5539284a6c8fa4a;hb=587fa7de9b496a0b7fa1d52d393733886602ca83;hpb=07a6dd2ce2c0c8ea2de11c30c134c877e7c7b0fb diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index e6c5449d..bea8414e 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -38,6 +38,16 @@ #define N_(x) (x) #endif +#ifdef __arm__ + #define ssat32_to_16(v) \ + asm("ssat %0,#16,%1" : "=r" (v) : "r" (v)) +#else + #define ssat32_to_16(v) do { \ + if (v < -32768) v = -32768; \ + else if (v > 32767) v = 32767; \ + } while (0) +#endif + /* #if defined (USEMACOSX) static char * libraryName = N_("Mac OS X Sound"); @@ -69,7 +79,7 @@ unsigned char * pMixIrq=0; // user settings -int iVolume=3; +int iVolume=768; // 1024 is 1.0 int iXAPitch=1; int iUseTimer=2; int iSPUIRQWait=1; @@ -83,7 +93,8 @@ int iUseInterpolation=2; SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) REVERBInfo rvb; -unsigned long dwNoiseVal=1; // global noise generator +unsigned int dwNoiseVal; // global noise generator +unsigned int dwNoiseCount; int iSpuAsyncWait=0; unsigned short spuCtrl=0; // some vars to store psx reg infos @@ -111,8 +122,8 @@ static const int f[8][2] = { { 0, 0 }, { 115, -52 }, { 98, -55 }, { 122, -60 } }; -int ChanBuf[NSSIZE]; -int SSumLR[NSSIZE*2]; +int ChanBuf[NSSIZE+3]; +int SSumLR[(NSSIZE+3)*2]; int iFMod[NSSIZE]; int iCycle = 0; short * pS; @@ -257,8 +268,8 @@ INLINE void StartSound(int ch) //s_chan[ch].bStop=0; //s_chan[ch].bOn=1; - s_chan[ch].s_1=0; // init mixing vars - s_chan[ch].s_2=0; + s_chan[ch].SB[26]=0; // init mixing vars + s_chan[ch].SB[27]=0; s_chan[ch].iSBPos=28; s_chan[ch].SB[29]=0; // init our interpolation helpers @@ -310,47 +321,13 @@ INLINE int FModChangeFrequency(int ch,int ns) //////////////////////////////////////////////////////////////////////// -// noise handler... just produces some noise data -// surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used... -// and sometimes the noise will be used as fmod modulation... pfff - -INLINE int iGetNoiseVal(int ch) -{ - int fa; - - if((dwNoiseVal<<=1)&0x80000000L) - { - dwNoiseVal^=0x0040001L; - fa=((dwNoiseVal>>2)&0x7fff); - fa=-fa; - } - else fa=(dwNoiseVal>>2)&0x7fff; - - // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val - fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1)); - if(fa>32767L) fa=32767L; - if(fa<-32767L) fa=-32767L; - s_chan[ch].iOldNoise=fa; - - if(iUseInterpolation<2) // no gauss/cubic interpolation? - s_chan[ch].SB[29] = fa; // -> store noise val in "current sample" slot - return fa; -} - -//////////////////////////////////////////////////////////////////////// - INLINE void StoreInterpolationVal(int ch,int fa) { if(s_chan[ch].bFMod==2) // fmod freq channel s_chan[ch].SB[29]=fa; else { - if((spuCtrl&0x4000)==0) fa=0; // muted? - else // else adjust - { - if(fa>32767L) fa=32767L; - if(fa<-32767L) fa=-32767L; - } + ssat32_to_16(fa); if(iUseInterpolation>=2) // gauss/cubic interpolation { @@ -441,16 +418,40 @@ static void do_irq(void) } } +static void decode_block_data(int *dest, const unsigned char *src, int predict_nr, int shift_factor) +{ + int nSample; + int fa, s_1, s_2, d, s; + + s_1 = dest[27]; + s_2 = dest[26]; + + for (nSample = 0; nSample < 28; src++) + { + d = (int)*src; + s = (int)(signed short)((d & 0x0f) << 12); + + fa = s >> shift_factor; + fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + dest[nSample++] = fa; + + s = (int)(signed short)((d & 0xf0) << 8); + fa = s >> shift_factor; + fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + + dest[nSample++] = fa; + } +} + static int decode_block(int ch) { unsigned char *start; - unsigned int nSample; - int predict_nr,shift_factor,flags,d,s; - int fa,s_1,s_2; + int predict_nr,shift_factor,flags; int ret = 0; - s_chan[ch].iSBPos=0; - start=s_chan[ch].pCurr; // set up the current pos if(start == (unsigned char*)-1 || // special "stop" sign (dwPendingChanOff&(1<>= 4; - flags=(int)*start;start++; - - // -------------------------------------- // - - for (nSample=0;nSample<28;start++) - { - d=(int)*start; - s=((d&0xf)<<12); - if(s&0x8000) s|=0xffff0000; - fa=(s >> shift_factor); - fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2=s_1;s_1=fa; - s=((d & 0xf0) << 8); - - s_chan[ch].SB[nSample++]=fa; - - if(s&0x8000) s|=0xffff0000; - fa=(s>>shift_factor); - fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); - s_2=s_1;s_1=fa; - - s_chan[ch].SB[nSample++]=fa; - } + decode_block_data(s_chan[ch].SB, start + 2, predict_nr, shift_factor); //////////////////////////////////////////// flag handler - if((flags&4) && (!s_chan[ch].bIgnoreLoop)) - s_chan[ch].pLoop=start-16; // loop adress + 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)) @@ -520,9 +498,7 @@ static int decode_block(int ch) if (start - spuMemC >= 0x80000) start = (unsigned char*)-1; - s_chan[ch].pCurr=start; // store values for next cycle - s_chan[ch].s_1=s_1; - s_chan[ch].s_2=s_2; + s_chan[ch].pCurr = start; // store values for next cycle return ret; } @@ -543,7 +519,7 @@ static int skip_block(int ch) ret = 1; } - if((flags & 4) && !s_chan[ch].bIgnoreLoop) + if(flags & 4) s_chan[ch].pLoop=start; s_chan[ch].pCurr += 16; @@ -559,6 +535,8 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ { \ int sinc = s_chan[ch].sinc; \ int spos = s_chan[ch].spos; \ + int sbpos = s_chan[ch].iSBPos; \ + int *SB = s_chan[ch].SB; \ int ret = -1; \ int d, fa; \ interp_start; \ @@ -569,8 +547,9 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ \ while (spos >= 0x10000) \ { \ - if(s_chan[ch].iSBPos == 28) \ + if(sbpos == 28) \ { \ + sbpos = 0; \ d = decode_block(ch); \ if(d && iSPUIRQWait) \ { \ @@ -579,7 +558,7 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ } \ } \ \ - fa = s_chan[ch].SB[s_chan[ch].iSBPos++]; \ + fa = SB[sbpos++]; \ interp1_code; \ spos -= 0x10000; \ } \ @@ -591,6 +570,7 @@ static int do_samples_##name(int ch, int ns, int ns_to) \ out: \ s_chan[ch].sinc = sinc; \ s_chan[ch].spos = spos; \ + s_chan[ch].iSBPos = sbpos; \ interp_end; \ \ return ret; \ @@ -623,6 +603,8 @@ make_do_samples(simple, , , static int do_samples_noise(int ch, int ns, int ns_to) { + int level, shift, bit; + s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns); while (s_chan[ch].spos >= 28*0x10000) { @@ -630,12 +612,72 @@ static int do_samples_noise(int ch, int ns, int ns_to) s_chan[ch].spos -= 28*0x10000; } + // modified from DrHell/shalma, no fraction + level = (spuCtrl >> 10) & 0x0f; + level = 0x8000 >> level; + for (; ns < ns_to; ns++) - ChanBuf[ns] = iGetNoiseVal(ch); + { + dwNoiseCount += 2; + if (dwNoiseCount >= level) + { + dwNoiseCount -= level; + shift = (dwNoiseVal >> 10) & 0x1f; + bit = (0x69696969 >> shift) & 1; + if (dwNoiseVal & 0x8000) + bit ^= 1; + dwNoiseVal = (dwNoiseVal << 1) | bit; + } + + ChanBuf[ns] = (signed short)dwNoiseVal; + } return -1; } +#ifdef __arm__ +// asm code +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 +static void mix_chan(int start, int count, int lv, int rv) +{ + int *dst = SSumLR + start * 2; + const int *src = ChanBuf + start; + int l, r; + + while (count--) + { + int sval = *src++; + + l = (sval * lv) >> 14; + r = (sval * rv) >> 14; + *dst++ += l; + *dst++ += r; + } +} + +static void mix_chan_rvb(int start, int count, int lv, int rv) +{ + int *dst = SSumLR + start * 2; + int *drvb = sRVBStart + start * 2; + const int *src = ChanBuf + start; + int l, r; + + while (count--) + { + int sval = *src++; + + l = (sval * lv) >> 14; + r = (sval * rv) >> 14; + *dst++ += l; + *dst++ += r; + *drvb++ += l; + *drvb++ += r; + } +} +#endif + //////////////////////////////////////////////////////////////////////// // MAIN SPU FUNCTION // here is the main job handler... thread, timer or direct func call @@ -653,12 +695,8 @@ static int do_samples_noise(int ch, int ns, int ns_to) static void *MAINThread(void *arg) { + int volmult = iVolume; int ns,ns_from,ns_to; -#if !defined(_MACOSX) && !defined(__arm__) - int voldiv = iVolume; -#else - const int voldiv = 2; -#endif int ch,d; int bIRQReturn=0; @@ -724,29 +762,18 @@ static void *MAINThread(void *arg) bIRQReturn=1; lastch=ch; lastns=ns_to=d; + if(d==0) + break; } MixADSR(ch, ns_from, ns_to); if(s_chan[ch].bFMod==2) // fmod freq channel memcpy(iFMod, ChanBuf, sizeof(iFMod)); - else for(ns=ns_from;ns 32767) d = 32767; + d = SSumLR[ns]; SSumLR[ns] = 0; + d = d * volmult >> 10; + ssat32_to_16(d); *pS++ = d; ns++; - SSumLR[ns] += MixREVERBRight(); - - d = SSumLR[ns] / voldiv; SSumLR[ns] = 0; - if(d < -32767) d = -32767; if(d > 32767) d = 32767; + d = SSumLR[ns]; SSumLR[ns] = 0; + d = d * volmult >> 10; + ssat32_to_16(d); *pS++ = d; ns++; } @@ -866,7 +901,7 @@ static void *MAINThread(void *arg) // feed the sound // wanna have around 1/60 sec (16.666 ms) updates - if (iCycle++ > 16) + if (iCycle++ > 16/FRAG_MSECS) { SoundFeedStreamData((unsigned char *)pSpuBuffer, ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer)); @@ -890,7 +925,7 @@ void CALLBACK SPUasync(unsigned long cycle) if(iSpuAsyncWait) { iSpuAsyncWait++; - if(iSpuAsyncWait<=16) return; + if(iSpuAsyncWait<=16/FRAG_MSECS) return; iSpuAsyncWait=0; } @@ -1036,8 +1071,6 @@ long CALLBACK SPUinit(void) memset((void *)&rvb, 0, sizeof(REVERBInfo)); InitADSR(); - iVolume = 3; - iReverbOff = -1; spuIrq = 0; spuAddr = 0xffffffff; bEndThread = 0;