cdrom: change pause timing again
[pcsx_rearmed.git] / plugins / dfsound / spu.c
index 9e1e83f..ed5b4b5 100644 (file)
@@ -18,6 +18,7 @@
  *                                                                         *
  ***************************************************************************/
 
+#include <assert.h>
 #include "stdafx.h"
 
 #define _IN_SPU
@@ -26,6 +27,7 @@
 #include "registers.h"
 #include "out.h"
 #include "spu_config.h"
+#include "spu.h"
 
 #ifdef __arm__
 #include "arm_features.h"
@@ -197,12 +199,15 @@ static void InterpolateDown(sample_buf *sb, int sinc)
 #include "gauss_i.h"
 #include "xa.c"
 
-static void do_irq(void)
+static void do_irq(int cycles_after)
 {
- //if(!(spu.spuStat & STAT_IRQ))
+ if (spu.spuStat & STAT_IRQ)
+  log_unhandled("spu: missed irq?\n");
+ else
  {
   spu.spuStat |= STAT_IRQ;                             // asserted status?
-  if(spu.irqCallback) spu.irqCallback();
+  if (spu.irqCallback)
+   spu.irqCallback(cycles_after);
  }
 }
 
@@ -210,8 +215,8 @@ static int check_irq(int ch, unsigned char *pos)
 {
  if((spu.spuCtrl & (CTRL_ON|CTRL_IRQ)) == (CTRL_ON|CTRL_IRQ) && pos == spu.pSpuIrq)
  {
-  //printf("ch%d irq %04x\n", ch, pos - spu.spuMemC);
-  do_irq();
+  //printf("ch%d irq %04zx\n", ch, pos - spu.spuMemC);
+  do_irq(0);
   return 1;
  }
  return 0;
@@ -224,7 +229,15 @@ void check_irq_io(unsigned int addr)
  if((spu.spuCtrl & (CTRL_ON|CTRL_IRQ)) == (CTRL_ON|CTRL_IRQ) && addr == irq_addr)
  {
   //printf("io   irq %04x\n", irq_addr);
-  do_irq();
+  do_irq(0);
+ }
+}
+
+void do_irq_io(int cycles_after)
+{
+ if ((spu.spuCtrl & (CTRL_ON|CTRL_IRQ)) == (CTRL_ON|CTRL_IRQ))
+ {
+  do_irq(cycles_after);
  }
 }
 
@@ -274,15 +287,15 @@ static void StartSound(int ch)
 // ALL KIND OF HELPERS
 ////////////////////////////////////////////////////////////////////////
 
-INLINE int FModChangeFrequency(int pitch, int ns)
+INLINE int FModChangeFrequency(int pitch, int ns, int *fmod_buf)
 {
  pitch = (signed short)pitch;
- pitch = ((32768 + iFMod[ns]) * pitch) >> 15;
+ pitch = ((32768 + fmod_buf[ns]) * pitch) >> 15;
  pitch &= 0xffff;
  if (pitch > 0x3fff)
   pitch = 0x3fff;
 
iFMod[ns] = 0;
fmod_buf[ns] = 0;
 
  return pitch << 4;
 }                    
@@ -479,7 +492,7 @@ static void scan_for_irq(int ch, unsigned int *upd_samples)
 }
 
 #define make_do_samples(name, fmod_code, interp_start, interp_store, interp_get, interp_end) \
-static noinline int name( \
+static noinline int name(int *dst, \
  int (*decode_f)(void *context, int ch, int *SB), void *ctx, \
  int ch, int ns_to, sample_buf *sb, int sinc, int *spos, int *sbpos) \
 {                                            \
@@ -528,41 +541,41 @@ static noinline int name( \
   if(sinc<0x10000)                /* -> upsampling? */ \
        InterpolateUp(sb, sinc);   /* --> interpolate up */ \
   else InterpolateDown(sb, sinc); /* --> else down */ \
-  ChanBuf[ns] = sb->SB[29]
+  dst[ns] = sb->SB[29]
 
 make_do_samples(do_samples_nointerp, , fa = sb->SB[29],
-   , ChanBuf[ns] = fa, sb->SB[29] = fa)
+   , dst[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), )
+  dst[ns] = GetInterpolationGauss(sb, *spos), )
 make_do_samples(do_samples_cubic, , ,
   StoreInterpolationGaussCubic(sb, fa),
-  ChanBuf[ns] = GetInterpolationCubic(sb, *spos), )
+  dst[ns] = GetInterpolationCubic(sb, *spos), )
 make_do_samples(do_samples_fmod,
-  sinc = FModChangeFrequency(spu.s_chan[ch].iRawPitch, ns), ,
+  sinc = FModChangeFrequency(spu.s_chan[ch].iRawPitch, ns, iFMod), ,
   StoreInterpolationGaussCubic(sb, fa),
-  ChanBuf[ns] = GetInterpolationGauss(sb, *spos), )
+  dst[ns] = GetInterpolationGauss(sb, *spos), )
 
-INLINE int do_samples_adpcm(
+INLINE int do_samples_adpcm(int *dst,
  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);
+  return do_samples_fmod(dst, 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);
+   return do_samples_nointerp(dst, 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);
+   return do_samples_simple  (dst, 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);
+   return do_samples_gauss   (dst, 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);
+   return do_samples_cubic   (dst, decode_f, ctx, ch, ns_to, sb, sinc, spos, sbpos);
  }
 }
 
@@ -593,7 +606,33 @@ static int do_samples_skip(int ch, int ns_to)
  return ret;
 }
 
-static void do_lsfr_samples(int ns_to, int ctrl,
+static int do_samples_skip_fmod(int ch, int ns_to, int *fmod_buf)
+{
+ SPUCHAN *s_chan = &spu.s_chan[ch];
+ int spos = s_chan->spos;
+ int ret = ns_to, ns, d;
+
+ spos += s_chan->iSBPos << 16;
+
+ for (ns = 0; ns < ns_to; ns++)
+ {
+  spos += FModChangeFrequency(s_chan->iRawPitch, ns, fmod_buf);
+  while (spos >= 28*0x10000)
+  {
+   d = skip_block(ch);
+   if (d && ns < ret)
+    ret = ns;
+   spos -= 28*0x10000;
+  }
+ }
+
+ s_chan->iSBPos = spos >> 16;
+ s_chan->spos = spos & 0xffff;
+
+ return ret;
+}
+
+static void do_lsfr_samples(int *dst, int ns_to, int ctrl,
  unsigned int *dwNoiseCount, unsigned int *dwNoiseVal)
 {
  unsigned int counter = *dwNoiseCount;
@@ -617,20 +656,20 @@ static void do_lsfr_samples(int ns_to, int ctrl,
    val = (val << 1) | bit;
   }
 
-  ChanBuf[ns] = (signed short)val;
+  dst[ns] = (signed short)val;
  }
 
  *dwNoiseCount = counter;
  *dwNoiseVal = val;
 }
 
-static int do_samples_noise(int ch, int ns_to)
+static int do_samples_noise(int *dst, int ch, int ns_to)
 {
  int ret;
 
  ret = do_samples_skip(ch, ns_to);
 
- do_lsfr_samples(ns_to, spu.spuCtrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
+ do_lsfr_samples(dst, ns_to, spu.spuCtrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
 
  return ret;
 }
@@ -766,13 +805,13 @@ static void do_channels(int ns_to)
 
    s_chan = &spu.s_chan[ch];
    if (s_chan->bNoise)
-    d = do_samples_noise(ch, ns_to);
+    d = do_samples_noise(ChanBuf, ch, ns_to);
    else
-    d = do_samples_adpcm(decode_block, NULL, ch, ns_to, s_chan->bFMod,
+    d = do_samples_adpcm(ChanBuf, 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);
+    d = MixADSR(ChanBuf, &s_chan->ADSRX, d);
     if (d < ns_to) {
      spu.dwChannelsAudible &= ~(1 << ch);
      s_chan->ADSRX.State = ADSR_RELEASE;
@@ -789,13 +828,15 @@ static void do_channels(int ns_to)
 
    if (s_chan->bFMod == 2)                         // fmod freq channel
     memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0]));
-   if (s_chan->bRVBActive && do_rvb)
+   if (!(spu.spuCtrl & CTRL_MUTE))
+    ;
+   else if (s_chan->bRVBActive && do_rvb)
     mix_chan_rvb(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume, RVB);
    else
     mix_chan(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume);
   }
 
-  MixXA(spu.SSumLR, RVB, ns_to, spu.decode_pos);
+  MixCD(spu.SSumLR, RVB, ns_to, spu.decode_pos);
 
   if (spu.rvb->StartAddr) {
    if (do_rvb)
@@ -818,11 +859,14 @@ static void do_samples_finish(int *SSumLR, int ns_to,
 static struct spu_worker {
  union {
   struct {
-   unsigned int exit_thread;
+   unsigned char exit_thread;
+   unsigned char prev_work_in_thread;
+   unsigned char pad[2];
    unsigned int i_ready;
    unsigned int i_reaped;
    unsigned int last_boot_cnt; // dsp
    unsigned int ram_dirty;
+   unsigned int channels_last;
   };
   // aligning for C64X_DSP
   unsigned int _pad0[128/4];
@@ -855,6 +899,7 @@ static struct spu_worker {
    unsigned short bNoise:1;
    unsigned short bFMod:2;
    unsigned short bRVBActive:1;
+   unsigned short bStarting:1;
    ADSRInfoEx adsr;
   } ch[24];
   int SSumLR[NSSIZE * 2];
@@ -900,6 +945,7 @@ static int decode_block_work(void *context, int ch, int *SB)
 
 static void queue_channel_work(int ns_to, unsigned int silentch)
 {
+ int tmpFMod[NSSIZE];
  struct work_item *work;
  SPUCHAN *s_chan;
  unsigned int mask;
@@ -911,13 +957,24 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
  work->decode_pos = spu.decode_pos;
  work->channels_silent = silentch;
 
+ if (!worker->prev_work_in_thread) {
+  // copy adpcm and interpolation state to sb_thread
+  worker->prev_work_in_thread = 1;
+  mask = spu.dwChannelsAudible & ~spu.dwNewChannel & 0xffffff;
+  for (ch = 0; mask != 0; ch++, mask >>= 1) {
+   if (mask & 1)
+    memcpy(spu.sb_thread[ch].SB, spu.sb[ch].SB, sizeof(spu.sb_thread[ch].SB));
+  }
+ }
+
  mask = work->channels_new = spu.dwNewChannel & 0xffffff;
  for (ch = 0; mask != 0; ch++, mask >>= 1) {
   if (mask & 1)
-   StartSoundMain(ch);
+   StartSound(ch);
  }
 
  mask = work->channels_on = spu.dwChannelsAudible & 0xffffff;
+ worker->channels_last = mask;
  spu.decode_dirty_ch |= mask & 0x0a;
 
  for (ch = 0; mask != 0; ch++, mask >>= 1)
@@ -936,10 +993,34 @@ 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].bStarting = s_chan->bStarting;
    if (s_chan->prevflags & 1)
     work->ch[ch].start = work->ch[ch].loop;
 
-   d = do_samples_skip(ch, ns_to);
+   if (unlikely(s_chan->bFMod == 2))
+   {
+    // sucks, have to do double work
+    if (s_chan->bNoise)
+     d = do_samples_noise(tmpFMod, ch, ns_to);
+    else
+     d = do_samples_gauss(tmpFMod, decode_block, NULL, ch, ns_to,
+          &spu.sb[ch], s_chan->sinc, &s_chan->spos, &s_chan->iSBPos);
+    if (!s_chan->bStarting) {
+     d = MixADSR(tmpFMod, &s_chan->ADSRX, d);
+     if (d < ns_to) {
+      spu.dwChannelsAudible &= ~(1 << ch);
+      s_chan->ADSRX.State = ADSR_RELEASE;
+      s_chan->ADSRX.EnvelopeVol = 0;
+     }
+    }
+    memset(&tmpFMod[d], 0, (ns_to - d) * sizeof(tmpFMod[d]));
+    work->ch[ch].ns_to = d;
+    continue;
+   }
+   if (unlikely(s_chan->bFMod))
+    d = do_samples_skip_fmod(ch, ns_to, tmpFMod);
+   else
+    d = do_samples_skip(ch, ns_to);
    work->ch[ch].ns_to = d;
 
    if (!s_chan->bStarting) {
@@ -951,7 +1032,7 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
      s_chan->ADSRX.EnvelopeVol = 0;
     }
    }
-  }
+  } // for (ch;;)
 
  work->rvb_addr = 0;
  if (spu.rvb->StartAddr) {
@@ -978,10 +1059,10 @@ static void do_channel_work(struct work_item *work)
  if (unlikely(spu.interpolation != spu_config.iUseInterpolation))
  {
   spu.interpolation = spu_config.iUseInterpolation;
-  mask = spu.dwChannelsAudible & 0xffffff;
+  mask = work->channels_on;
   for (ch = 0; mask != 0; ch++, mask >>= 1)
    if (mask & 1)
-    ResetInterpolation(&spu.sb[ch]);
+    ResetInterpolation(&spu.sb_thread[ch]);
  }
 
  if (work->rvb_addr)
@@ -990,7 +1071,7 @@ static void do_channel_work(struct work_item *work)
  mask = work->channels_new;
  for (ch = 0; mask != 0; ch++, mask >>= 1) {
   if (mask & 1)
-   StartSoundSB(&spu.sb[ch]);
+   StartSoundSB(&spu.sb_thread[ch]);
  }
 
  mask = work->channels_on;
@@ -1003,12 +1084,12 @@ static void do_channel_work(struct work_item *work)
    sbpos = work->ch[ch].sbpos;
 
    if (work->ch[ch].bNoise)
-    do_lsfr_samples(d, work->ctrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
+    do_lsfr_samples(ChanBuf, d, work->ctrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
    else
-    do_samples_adpcm(decode_block_work, work, ch, d, work->ch[ch].bFMod,
-          &spu.sb[ch], work->ch[ch].sinc, &spos, &sbpos);
+    do_samples_adpcm(ChanBuf, decode_block_work, work, ch, d, work->ch[ch].bFMod,
+          &spu.sb_thread[ch], work->ch[ch].sinc, &spos, &sbpos);
 
-   d = MixADSR(&work->ch[ch].adsr, d);
+   d = MixADSR(ChanBuf, &work->ch[ch].adsr, d);
    if (d < ns_to) {
     work->ch[ch].adsr.EnvelopeVol = 0;
     memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
@@ -1030,8 +1111,9 @@ static void do_channel_work(struct work_item *work)
    REVERBDo(work->SSumLR, RVB, ns_to, work->rvb_addr);
 }
 
-static void sync_worker_thread(int force)
+static void sync_worker_thread(int force_no_thread)
 {
+ int force = force_no_thread;
  struct work_item *work;
  int done, used_space;
 
@@ -1048,7 +1130,7 @@ static void sync_worker_thread(int force)
   work = &worker->i[worker->i_reaped & WORK_I_MASK];
   thread_work_wait_sync(work, force);
 
-  MixXA(work->SSumLR, RVB, work->ns_to, work->decode_pos);
+  MixCD(work->SSumLR, RVB, work->ns_to, work->decode_pos);
   do_samples_finish(work->SSumLR, work->ns_to,
    work->channels_silent, work->decode_pos);
 
@@ -1056,14 +1138,21 @@ static void sync_worker_thread(int force)
   done = thread_get_i_done() - worker->i_reaped;
   used_space = worker->i_ready - worker->i_reaped;
  }
- if (force)
+ if (force_no_thread && worker->prev_work_in_thread) {
+  unsigned int ch, mask = worker->channels_last;
+  worker->prev_work_in_thread = 0;
   thread_sync_caches();
+  for (ch = 0; mask != 0; ch++, mask >>= 1) {
+   if (mask & 1)
+    memcpy(spu.sb[ch].SB, spu.sb_thread[ch].SB, sizeof(spu.sb_thread[ch].SB));
+  }
+ }
 }
 
 #else
 
 static void queue_channel_work(int ns_to, int silentch) {}
-static void sync_worker_thread(int force) {}
+static void sync_worker_thread(int force_no_thread) {}
 
 static const void * const worker = NULL;
 
@@ -1074,7 +1163,7 @@ static const void * const worker = NULL;
 // here is the main job handler...
 ////////////////////////////////////////////////////////////////////////
 
-void do_samples(unsigned int cycles_to, int do_direct)
+void do_samples(unsigned int cycles_to, int force_no_thread)
 {
  unsigned int silentch;
  int cycle_diff;
@@ -1083,16 +1172,16 @@ void do_samples(unsigned int cycles_to, int do_direct)
  cycle_diff = cycles_to - spu.cycles_played;
  if (cycle_diff < -2*1048576 || cycle_diff > 2*1048576)
   {
-   //xprintf("desync %u %d\n", cycles_to, cycle_diff);
+   log_unhandled("desync %u %d\n", cycles_to, cycle_diff);
    spu.cycles_played = cycles_to;
    return;
   }
 
  silentch = ~(spu.dwChannelsAudible | spu.dwNewChannel) & 0xffffff;
 
do_direct |= (silentch == 0xffffff);
force_no_thread |= (silentch == 0xffffff);
  if (worker != NULL)
-  sync_worker_thread(do_direct);
+  sync_worker_thread(force_no_thread);
 
  if (cycle_diff < 2 * 768)
   return;
@@ -1100,7 +1189,7 @@ void do_samples(unsigned int cycles_to, int do_direct)
  ns_to = (cycle_diff / 768 + 1) & ~1;
  if (ns_to > NSSIZE) {
   // should never happen
-  //xprintf("ns_to oflow %d %d\n", ns_to, NSSIZE);
+  log_unhandled("ns_to oflow %d %d\n", ns_to, NSSIZE);
   ns_to = NSSIZE;
  }
 
@@ -1129,7 +1218,7 @@ void do_samples(unsigned int cycles_to, int do_direct)
     if (0 < left && left <= ns_to)
      {
       //xprintf("decoder irq %x\n", spu.decode_pos);
-      do_irq();
+      do_irq(0);
      }
    }
   if (!spu.cycles_dma_end || (int)(spu.cycles_dma_end - cycles_to) < 0) {
@@ -1140,7 +1229,7 @@ void do_samples(unsigned int cycles_to, int do_direct)
   if (unlikely(spu.rvb->dirty))
    REVERBPrep();
 
-  if (do_direct || worker == NULL || !spu_config.iUseThread) {
+  if (force_no_thread || worker == NULL || !spu_config.iUseThread) {
    do_channels(ns_to);
    do_samples_finish(spu.SSumLR, ns_to, silentch, spu.decode_pos);
   }
@@ -1156,6 +1245,7 @@ void do_samples(unsigned int cycles_to, int do_direct)
 
   spu.cycles_played += ns_to * 768;
   spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff;
+  spu.spuStat = (spu.spuStat & ~0x800) | ((spu.decode_pos << 3) & 0x800);
 #if 0
   static int ccount; static time_t ctime; ccount++;
   if (time(NULL) != ctime)
@@ -1186,7 +1276,7 @@ static void do_samples_finish(int *SSumLR, int ns_to,
   vol_l = vol_l * spu_config.iVolume >> 10;
   vol_r = vol_r * spu_config.iVolume >> 10;
 
-  if (!(spu.spuCtrl & CTRL_MUTE) || !(vol_l | vol_r))
+  if (!(vol_l | vol_r))
    {
     // muted? (rare)
     memset(spu.pS, 0, ns_to * 2 * sizeof(spu.pS[0]));
@@ -1293,25 +1383,40 @@ void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_s
  if(!xap->freq) return;                // no xa freq ? bye
 
  if (is_start)
+  spu.XAPlay = spu.XAFeed = spu.XAStart;
+ if (spu.XAPlay == spu.XAFeed)
   do_samples(cycle, 1);                // catch up to prevent source underflows later
 
  FeedXA(xap);                          // call main XA feeder
  spu.xapGlobal = xap;                  // store info for save states
+ spu.cdClearSamples = 512;
 }
 
 // CDDA AUDIO
-int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes, unsigned int cycle, int is_start)
+int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes, unsigned int cycle, int unused)
 {
  if (!pcm)      return -1;
  if (nbytes<=0) return -1;
 
- if (is_start)
+ if (spu.CDDAPlay == spu.CDDAFeed)
   do_samples(cycle, 1);                // catch up to prevent source underflows later
 
  FeedCDDA((unsigned char *)pcm, nbytes);
+ spu.cdClearSamples = 512;
  return 0;
 }
 
+void CALLBACK SPUsetCDvol(unsigned char ll, unsigned char lr,
+  unsigned char rl, unsigned char rr, unsigned int cycle)
+{
+ if (spu.XAPlay != spu.XAFeed || spu.CDDAPlay != spu.CDDAFeed)
+  do_samples(cycle, 1);
+ spu.cdv.ll = ll;
+ spu.cdv.lr = lr;
+ spu.cdv.rl = rl;
+ spu.cdv.rr = rr;
+}
+
 // to be called after state load
 void ClearWorkingState(void)
 {
@@ -1412,6 +1517,8 @@ static void init_spu_thread(void)
 {
  int ret;
 
+ spu.sb_thread = spu.sb_thread_;
+
  if (sysconf(_SC_NPROCESSORS_ONLN) <= 1)
   return;
 
@@ -1473,7 +1580,10 @@ long CALLBACK SPUinit(void)
  int i;
 
  memset(&spu, 0, sizeof(spu));
- spu.spuMemC = calloc(1, 512 * 1024);
+ spu.spuMemC = calloc(1, 512 * 1024 + 16);
+ // a guard for runaway channels - End+Mute
+ spu.spuMemC[512 * 1024 + 1] = 1;
+
  InitADSR();
 
  spu.s_chan = calloc(MAXCHAN+1, sizeof(spu.s_chan[0])); // channel + 1 infos (1 is security for fmod handling)
@@ -1551,14 +1661,14 @@ long CALLBACK SPUshutdown(void)
 // SETUP CALLBACKS
 // this functions will be called once, 
 // passes a callback that should be called on SPU-IRQ/cdda volume change
-void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
+void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(int))
 {
  spu.irqCallback = callback;
 }
 
 void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(short, short))
 {
- spu.cddavCallback = CDDAVcallback;
//spu.cddavCallback = CDDAVcallback;
 }
 
 void CALLBACK SPUregisterScheduleCb(void (CALLBACK *callback)(unsigned int))