spu: try to clean up the interpolation mess
authornotaz <notasas@gmail.com>
Sat, 7 Oct 2023 19:56:09 +0000 (22:56 +0300)
committernotaz <notasas@gmail.com>
Sun, 8 Oct 2023 15:28:36 +0000 (18:28 +0300)
It's still full of magic offsets and constants,
but maybe not as much as before.

libpcsxcore/plugins.h
plugins/dfsound/externals.h
plugins/dfsound/freeze.c
plugins/dfsound/registers.c
plugins/dfsound/spu.c

index fbbd44f..cb9b88a 100644 (file)
@@ -184,7 +184,7 @@ typedef struct {
        unsigned char SPUPorts[0x200];\r
        unsigned char SPURam[0x80000];\r
        xa_decode_t xa;\r
-       unsigned char *SPUInfo;\r
+       unsigned char *unused;\r
 } SPUFreeze_t;\r
 typedef long (CALLBACK* SPUfreeze)(uint32_t, SPUFreeze_t *, uint32_t);\r
 typedef void (CALLBACK* SPUasync)(uint32_t, uint32_t);\r
index 4407177..9fb58ad 100644 (file)
@@ -117,7 +117,6 @@ typedef struct
  unsigned int      bFMod:2;                            // freq mod (0=off, 1=sound channel, 2=freq channel)\r
  unsigned int      prevflags:3;                        // flags from previous block\r
  unsigned int      bIgnoreLoop:1;                      // Ignore loop\r
- unsigned int      bNewPitch:1;                        // pitch changed\r
  unsigned int      bStarting:1;                        // starting after keyon\r
  union {\r
   struct {\r
@@ -183,7 +182,21 @@ typedef struct
 \r
 // psx buffers / addresses\r
 \r
-#define SB_SIZE (32 + 4)\r
+typedef union\r
+{\r
+ int SB[28 + 4 + 4];\r
+ struct {\r
+  int sample[28];\r
+  union {\r
+   struct {\r
+    int pos;\r
+    signed short val[4];\r
+   } gauss;\r
+   int simple[5]; // 28-32\r
+  } interp;\r
+  int sinc_old;\r
+ };\r
+} sample_buf;\r
 \r
 typedef struct\r
 {\r
@@ -239,10 +252,13 @@ typedef struct
  REVERBInfo    * rvb;\r
 \r
  // buffers\r
int           * SB;\r
void          * unused;\r
  int           * SSumLR;\r
 \r
  unsigned short  regArea[0x400];\r
+\r
+ sample_buf      sb[MAXCHAN];\r
+ int             interpolation;\r
 } SPUInfo;\r
 \r
 #define regAreaGet(offset) \\r
index d4898b4..c4afad8 100644 (file)
@@ -15,6 +15,7 @@
  *                                                                         *\r
  ***************************************************************************/\r
 \r
+#include <assert.h>\r
 #include "stdafx.h"\r
 \r
 #define _IN_FREEZE\r
@@ -145,7 +146,8 @@ static void save_channel(SPUCHAN_orig *d, const SPUCHAN *s, int ch)
  d->iSBPos = s->iSBPos;\r
  d->spos = s->spos;\r
  d->sinc = s->sinc;\r
- memcpy(d->SB, spu.SB + ch * SB_SIZE, sizeof(d->SB[0]) * SB_SIZE);\r
+ assert(sizeof(d->SB) >= sizeof(spu.sb[ch]));\r
+ memcpy(d->SB, &spu.sb[ch], sizeof(spu.sb[ch]));\r
  d->iStart = (regAreaGetCh(ch, 6) & ~1) << 3;\r
  d->iCurr = 0; // set by the caller\r
  d->iLoop = 0; // set by the caller\r
@@ -159,8 +161,8 @@ static void save_channel(SPUCHAN_orig *d, const SPUCHAN *s, int ch)
  d->bIgnoreLoop = (s->prevflags ^ 2) << 1;\r
  d->iRightVolume = s->iRightVolume;\r
  d->iRawPitch = s->iRawPitch;\r
- d->s_1 = spu.SB[ch * SB_SIZE + 27]; // yes it's reversed\r
- d->s_2 = spu.SB[ch * SB_SIZE + 26];\r
+ d->s_1 = spu.sb[ch].SB[27]; // yes it's reversed\r
+ d->s_2 = spu.sb[ch].SB[26];\r
  d->bRVBActive = s->bRVBActive;\r
  d->bNoise = s->bNoise;\r
  d->bFMod = s->bFMod;\r
@@ -187,7 +189,7 @@ static void load_channel(SPUCHAN *d, const SPUCHAN_orig *s, int ch)
  d->spos = s->spos;\r
  d->sinc = s->sinc;\r
  d->sinc_inv = 0;\r
- memcpy(spu.SB + ch * SB_SIZE, s->SB, sizeof(spu.SB[0]) * SB_SIZE);\r
+ memcpy(&spu.sb[ch], s->SB, sizeof(spu.sb[ch]));\r
  d->pCurr = (void *)((uintptr_t)s->iCurr & 0x7fff0);\r
  d->pLoop = (void *)((uintptr_t)s->iLoop & 0x7fff0);\r
  d->bReverb = s->bReverb;\r
@@ -340,7 +342,7 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
  load_register(H_CDRight, cycles);\r
 \r
  // fix to prevent new interpolations from crashing\r
for(i=0;i<MAXCHAN;i++) spu.SB[i * SB_SIZE + 28]=0;\r
spu.interpolation = -1;\r
 \r
  ClearWorkingState();\r
 \r
index a20538a..2796f9c 100644 (file)
@@ -546,7 +546,6 @@ static void SetPitch(int ch,unsigned short val)               // SET PITCH
  spu.s_chan[ch].iRawPitch = NP;\r
  spu.s_chan[ch].sinc = NP << 4;\r
  spu.s_chan[ch].sinc_inv = 0;\r
- spu.s_chan[ch].bNewPitch = 1;\r
 \r
  // don't mess spu.dwChannelsAudible as adsr runs independently\r
 }\r
index 04997ba..9e1e83f 100644 (file)
@@ -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);