X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=plugins%2Fdfsound%2Fspu.c;h=9e1e83f20983091873638fa354ad548469b42383;hb=38e4048faeaccf7fdc6084f64866f2ea52bb97f1;hp=04997baac40e3f8a22136dd42310d1eae1260368;hpb=893f780e3ec8eb0b83fa4fc374c361ffffab0cff;p=pcsx_rearmed.git diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index 04997baa..9e1e83f2 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -126,8 +126,14 @@ int ChanBuf[NSSIZE]; // / // -static void InterpolateUp(int *SB, int sinc) +static void InterpolateUp(sample_buf *sb, int sinc) { + int *SB = sb->SB; + if (sb->sinc_old != sinc) + { + sb->sinc_old = sinc; + SB[32] = 1; + } if(SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass { const int id1=SB[30]-SB[29]; // curr delta to next val @@ -175,8 +181,9 @@ static void InterpolateUp(int *SB, int sinc) // even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm // -static void InterpolateDown(int *SB, int sinc) +static void InterpolateDown(sample_buf *sb, int sinc) { + int *SB = sb->SB; if(sinc>=0x20000L) // we would skip at least one val? { SB[29]+=(SB[30]-SB[29])/2; // add easy weight @@ -186,15 +193,8 @@ static void InterpolateDown(int *SB, int sinc) } //////////////////////////////////////////////////////////////////////// -// helpers for gauss interpolation - -#define gval0 (((short*)(&SB[29]))[gpos&3]) -#define gval(x) ((int)((short*)(&SB[29]))[(gpos+x)&3]) #include "gauss_i.h" - -//////////////////////////////////////////////////////////////////////// - #include "xa.c" static void do_irq(void) @@ -232,15 +232,17 @@ void check_irq_io(unsigned int addr) // START SOUND... called by main thread to setup a new sound on a channel //////////////////////////////////////////////////////////////////////// -static void StartSoundSB(int *SB) +static void ResetInterpolation(sample_buf *sb) { - SB[26]=0; // init mixing vars - SB[27]=0; + memset(&sb->interp, 0, sizeof(sb->interp)); + sb->sinc_old = -1; +} - SB[28]=0; - SB[29]=0; // init our interpolation helpers - SB[30]=0; - SB[31]=0; +static void StartSoundSB(sample_buf *sb) +{ + sb->SB[26] = 0; // init mixing vars + sb->SB[27] = 0; + ResetInterpolation(sb); } static void StartSoundMain(int ch) @@ -265,14 +267,14 @@ static void StartSoundMain(int ch) static void StartSound(int ch) { StartSoundMain(ch); - StartSoundSB(spu.SB + ch * SB_SIZE); + StartSoundSB(&spu.sb[ch]); } //////////////////////////////////////////////////////////////////////// // ALL KIND OF HELPERS //////////////////////////////////////////////////////////////////////// -INLINE int FModChangeFrequency(int *SB, int pitch, int ns) +INLINE int FModChangeFrequency(int pitch, int ns) { pitch = (signed short)pitch; pitch = ((32768 + iFMod[ns]) * pitch) >> 15; @@ -281,101 +283,50 @@ INLINE int FModChangeFrequency(int *SB, int pitch, int ns) pitch = 0x3fff; iFMod[ns] = 0; - SB[32] = 1; // reset interpolation return pitch << 4; } -//////////////////////////////////////////////////////////////////////// - -INLINE void StoreInterpolationVal(int *SB, int sinc, int fa, int fmod_freq) +INLINE void StoreInterpolationGaussCubic(sample_buf *sb, int fa) { - if(fmod_freq) // fmod freq channel - SB[29]=fa; - else - { - ssat32_to_16(fa); - - if(spu_config.iUseInterpolation>=2) // gauss/cubic interpolation - { - int gpos = SB[28]; - gval0 = fa; - gpos = (gpos+1) & 3; - SB[28] = gpos; - } - else - if(spu_config.iUseInterpolation==1) // simple interpolation - { - SB[28] = 0; - SB[29] = SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour' - SB[30] = SB[31]; - SB[31] = fa; - SB[32] = 1; // -> flag: calc new interolation - } - else SB[29]=fa; // no interpolation - } + int gpos = sb->interp.gauss.pos & 3; + sb->interp.gauss.val[gpos++] = fa; + sb->interp.gauss.pos = gpos & 3; } -//////////////////////////////////////////////////////////////////////// +#define gval(x) (int)sb->interp.gauss.val[(gpos + x) & 3] -INLINE int iGetInterpolationVal(int *SB, int sinc, int spos, int fmod_freq) +INLINE int GetInterpolationCubic(const sample_buf *sb, int spos) { + int gpos = sb->interp.gauss.pos; + int xd = (spos >> 1) + 1; int fa; - if(fmod_freq) return SB[29]; - - switch(spu_config.iUseInterpolation) - { - //--------------------------------------------------// - case 3: // cubic interpolation - { - long xd;int gpos; - xd = (spos >> 1)+1; - gpos = SB[28]; - - fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0; - fa *= (xd - (2<<15)) / 6; - fa >>= 15; - fa += gval(2) - gval(1) - gval(1) + gval0; - fa *= (xd - (1<<15)) >> 1; - fa >>= 15; - fa += gval(1) - gval0; - fa *= xd; - fa >>= 15; - fa = fa + gval0; - - } break; - //--------------------------------------------------// - case 2: // gauss interpolation - { - int vl, vr;int gpos; - vl = (spos >> 6) & ~3; - gpos = SB[28]; - vr=(gauss[vl]*(int)gval0) >> 15; - vr+=(gauss[vl+1]*gval(1)) >> 15; - vr+=(gauss[vl+2]*gval(2)) >> 15; - vr+=(gauss[vl+3]*gval(3)) >> 15; - fa = vr; - } break; - //--------------------------------------------------// - case 1: // simple interpolation - { - if(sinc<0x10000L) // -> upsampling? - InterpolateUp(SB, sinc); // --> interpolate up - else InterpolateDown(SB, sinc); // --> else down - fa=SB[29]; - } break; - //--------------------------------------------------// - default: // no interpolation - { - fa=SB[29]; - } break; - //--------------------------------------------------// - } - + fa = gval(3) - 3*gval(2) + 3*gval(1) - gval(0); + fa *= (xd - (2<<15)) / 6; + fa >>= 15; + fa += gval(2) - gval(1) - gval(1) + gval(0); + fa *= (xd - (1<<15)) >> 1; + fa >>= 15; + fa += gval(1) - gval(0); + fa *= xd; + fa >>= 15; + fa = fa + gval(0); return fa; } +INLINE int GetInterpolationGauss(const sample_buf *sb, int spos) +{ + int gpos = sb->interp.gauss.pos; + int vl = (spos >> 6) & ~3; + int vr; + vr = (gauss[vl+0] * gval(0)) >> 15; + vr += (gauss[vl+1] * gval(1)) >> 15; + vr += (gauss[vl+2] * gval(2)) >> 15; + vr += (gauss[vl+3] * gval(3)) >> 15; + return vr; +} + static void decode_block_data(int *dest, const unsigned char *src, int predict_nr, int shift_factor) { static const int f[16][2] = { @@ -527,10 +478,10 @@ static void scan_for_irq(int ch, unsigned int *upd_samples) } } -#define make_do_samples(name, fmod_code, interp_start, interp1_code, interp2_code, interp_end) \ -static noinline int do_samples_##name( \ +#define make_do_samples(name, fmod_code, interp_start, interp_store, interp_get, interp_end) \ +static noinline int name( \ int (*decode_f)(void *context, int ch, int *SB), void *ctx, \ - int ch, int ns_to, int *SB, int sinc, int *spos, int *sbpos) \ + int ch, int ns_to, sample_buf *sb, int sinc, int *spos, int *sbpos) \ { \ int ns, d, fa; \ int ret = ns_to; \ @@ -543,20 +494,20 @@ static noinline int do_samples_##name( \ *spos += sinc; \ while (*spos >= 0x10000) \ { \ - fa = SB[(*sbpos)++]; \ + fa = sb->SB[(*sbpos)++]; \ if (*sbpos >= 28) \ { \ *sbpos = 0; \ - d = decode_f(ctx, ch, SB); \ + d = decode_f(ctx, ch, sb->SB); \ if (d && ns < ret) \ ret = ns; \ } \ \ - interp1_code; \ + interp_store; \ *spos -= 0x10000; \ } \ \ - interp2_code; \ + interp_get; \ } \ \ interp_end; \ @@ -564,30 +515,56 @@ static noinline int do_samples_##name( \ return ret; \ } -#define fmod_recv_check \ - if(spu.s_chan[ch].bFMod==1 && iFMod[ns]) \ - sinc = FModChangeFrequency(SB, spu.s_chan[ch].iRawPitch, ns) - -make_do_samples(default, fmod_recv_check, , - StoreInterpolationVal(SB, sinc, fa, spu.s_chan[ch].bFMod==2), - ChanBuf[ns] = iGetInterpolationVal(SB, sinc, *spos, spu.s_chan[ch].bFMod==2), ) -make_do_samples(noint, , fa = SB[29], , ChanBuf[ns] = fa, SB[29] = fa) - +// helpers for simple linear interpolation: delay real val for two slots, +// and calc the two deltas, for a 'look at the future behaviour' #define simple_interp_store \ - SB[28] = 0; \ - SB[29] = SB[30]; \ - SB[30] = SB[31]; \ - SB[31] = fa; \ - SB[32] = 1 + sb->SB[28] = 0; \ + sb->SB[29] = sb->SB[30]; \ + sb->SB[30] = sb->SB[31]; \ + sb->SB[31] = fa; \ + sb->SB[32] = 1 #define simple_interp_get \ if(sinc<0x10000) /* -> upsampling? */ \ - InterpolateUp(SB, sinc); /* --> interpolate up */ \ - else InterpolateDown(SB, sinc); /* --> else down */ \ - ChanBuf[ns] = SB[29] + InterpolateUp(sb, sinc); /* --> interpolate up */ \ + else InterpolateDown(sb, sinc); /* --> else down */ \ + ChanBuf[ns] = sb->SB[29] -make_do_samples(simple, , , +make_do_samples(do_samples_nointerp, , fa = sb->SB[29], + , ChanBuf[ns] = fa, sb->SB[29] = fa) +make_do_samples(do_samples_simple, , , simple_interp_store, simple_interp_get, ) +make_do_samples(do_samples_gauss, , , + StoreInterpolationGaussCubic(sb, fa), + ChanBuf[ns] = GetInterpolationGauss(sb, *spos), ) +make_do_samples(do_samples_cubic, , , + StoreInterpolationGaussCubic(sb, fa), + ChanBuf[ns] = GetInterpolationCubic(sb, *spos), ) +make_do_samples(do_samples_fmod, + sinc = FModChangeFrequency(spu.s_chan[ch].iRawPitch, ns), , + StoreInterpolationGaussCubic(sb, fa), + ChanBuf[ns] = GetInterpolationGauss(sb, *spos), ) + +INLINE int do_samples_adpcm( + int (*decode_f)(void *context, int ch, int *SB), void *ctx, + int ch, int ns_to, int fmod, sample_buf *sb, int sinc, int *spos, int *sbpos) +{ + int interp = spu.interpolation; + if (fmod == 1) + return do_samples_fmod(decode_f, ctx, ch, ns_to, sb, sinc, spos, sbpos); + if (fmod) + interp = 2; + switch (interp) { + case 0: + return do_samples_nointerp(decode_f, ctx, ch, ns_to, sb, sinc, spos, sbpos); + case 1: + return do_samples_simple (decode_f, ctx, ch, ns_to, sb, sinc, spos, sbpos); + default: + return do_samples_gauss (decode_f, ctx, ch, ns_to, sb, sinc, spos, sbpos); + case 3: + return do_samples_cubic (decode_f, ctx, ch, ns_to, sb, sinc, spos, sbpos); + } +} static int do_samples_skip(int ch, int ns_to) { @@ -762,7 +739,15 @@ static void do_channels(int ns_to) unsigned int mask; int do_rvb, ch, d; SPUCHAN *s_chan; - int *SB, sinc; + + if (unlikely(spu.interpolation != spu_config.iUseInterpolation)) + { + spu.interpolation = spu_config.iUseInterpolation; + mask = spu.dwChannelsAudible & 0xffffff; + for (ch = 0; mask != 0; ch++, mask >>= 1) + if (mask & 1) + ResetInterpolation(&spu.sb[ch]); + } do_rvb = spu.rvb->StartAddr && spu_config.iUseReverb; if (do_rvb) @@ -780,24 +765,11 @@ static void do_channels(int ns_to) if (!(mask & 1)) continue; // channel not playing? next s_chan = &spu.s_chan[ch]; - SB = spu.SB + ch * SB_SIZE; - sinc = s_chan->sinc; - if (spu.s_chan[ch].bNewPitch) - SB[32] = 1; // reset interpolation - spu.s_chan[ch].bNewPitch = 0; - if (s_chan->bNoise) d = do_samples_noise(ch, ns_to); - else if (s_chan->bFMod == 2 - || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0)) - d = do_samples_noint(decode_block, NULL, ch, ns_to, - SB, sinc, &s_chan->spos, &s_chan->iSBPos); - else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1) - d = do_samples_simple(decode_block, NULL, ch, ns_to, - SB, sinc, &s_chan->spos, &s_chan->iSBPos); else - d = do_samples_default(decode_block, NULL, ch, ns_to, - SB, sinc, &s_chan->spos, &s_chan->iSBPos); + d = do_samples_adpcm(decode_block, NULL, ch, ns_to, s_chan->bFMod, + &spu.sb[ch], s_chan->sinc, &s_chan->spos, &s_chan->iSBPos); if (!s_chan->bStarting) { d = MixADSR(&s_chan->ADSRX, d); @@ -883,7 +855,6 @@ static struct spu_worker { unsigned short bNoise:1; unsigned short bFMod:2; unsigned short bRVBActive:1; - unsigned short bNewPitch:1; ADSRInfoEx adsr; } ch[24]; int SSumLR[NSSIZE * 2]; @@ -965,7 +936,6 @@ static void queue_channel_work(int ns_to, unsigned int silentch) work->ch[ch].bNoise = s_chan->bNoise; work->ch[ch].bFMod = s_chan->bFMod; work->ch[ch].bRVBActive = s_chan->bRVBActive; - work->ch[ch].bNewPitch = s_chan->bNewPitch; if (s_chan->prevflags & 1) work->ch[ch].start = work->ch[ch].loop; @@ -981,7 +951,6 @@ static void queue_channel_work(int ns_to, unsigned int silentch) s_chan->ADSRX.EnvelopeVol = 0; } } - s_chan->bNewPitch = 0; } work->rvb_addr = 0; @@ -1001,18 +970,27 @@ static void queue_channel_work(int ns_to, unsigned int silentch) static void do_channel_work(struct work_item *work) { unsigned int mask; - int *SB, sinc, spos, sbpos; + int spos, sbpos; int d, ch, ns_to; ns_to = work->ns_to; + if (unlikely(spu.interpolation != spu_config.iUseInterpolation)) + { + spu.interpolation = spu_config.iUseInterpolation; + mask = spu.dwChannelsAudible & 0xffffff; + for (ch = 0; mask != 0; ch++, mask >>= 1) + if (mask & 1) + ResetInterpolation(&spu.sb[ch]); + } + if (work->rvb_addr) memset(RVB, 0, ns_to * sizeof(RVB[0]) * 2); mask = work->channels_new; for (ch = 0; mask != 0; ch++, mask >>= 1) { if (mask & 1) - StartSoundSB(spu.SB + ch * SB_SIZE); + StartSoundSB(&spu.sb[ch]); } mask = work->channels_on; @@ -1023,21 +1001,12 @@ static void do_channel_work(struct work_item *work) d = work->ch[ch].ns_to; spos = work->ch[ch].spos; sbpos = work->ch[ch].sbpos; - sinc = work->ch[ch].sinc; - - SB = spu.SB + ch * SB_SIZE; - if (work->ch[ch].bNewPitch) - SB[32] = 1; // reset interpolation if (work->ch[ch].bNoise) do_lsfr_samples(d, work->ctrl, &spu.dwNoiseCount, &spu.dwNoiseVal); - else if (work->ch[ch].bFMod == 2 - || (work->ch[ch].bFMod == 0 && spu_config.iUseInterpolation == 0)) - do_samples_noint(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos); - else if (work->ch[ch].bFMod == 0 && spu_config.iUseInterpolation == 1) - do_samples_simple(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos); else - do_samples_default(decode_block_work, work, ch, d, SB, sinc, &spos, &sbpos); + do_samples_adpcm(decode_block_work, work, ch, d, work->ch[ch].bFMod, + &spu.sb[ch], work->ch[ch].sinc, &spos, &sbpos); d = MixADSR(&work->ch[ch].adsr, d); if (d < ns_to) { @@ -1509,7 +1478,6 @@ long CALLBACK SPUinit(void) spu.s_chan = calloc(MAXCHAN+1, sizeof(spu.s_chan[0])); // channel + 1 infos (1 is security for fmod handling) spu.rvb = calloc(1, sizeof(REVERBInfo)); - spu.SB = calloc(MAXCHAN, sizeof(spu.SB[0]) * SB_SIZE); spu.spuAddr = 0; spu.decode_pos = 0; @@ -1569,8 +1537,6 @@ long CALLBACK SPUshutdown(void) free(spu.spuMemC); spu.spuMemC = NULL; - free(spu.SB); - spu.SB = NULL; free(spu.s_chan); spu.s_chan = NULL; free(spu.rvb);