spu: adjust fmod to match nocash description
[pcsx_rearmed.git] / plugins / dfsound / spu.c
index f5e8de5..04997ba 100644 (file)
@@ -250,9 +250,10 @@ static void StartSoundMain(int ch)
  StartADSR(ch);
  StartREVERB(ch);
 
- s_chan->prevflags=2;
- s_chan->iSBPos=27;
- s_chan->spos=0;
+ s_chan->prevflags = 2;
+ s_chan->iSBPos = 27;
+ s_chan->spos = 0;
+ s_chan->bStarting = 1;
 
  s_chan->pCurr = spu.spuMemC + ((regAreaGetCh(ch, 6) & ~1) << 3);
 
@@ -273,19 +274,16 @@ static void StartSound(int ch)
 
 INLINE int FModChangeFrequency(int *SB, int pitch, int ns)
 {
- unsigned int NP=pitch;
- int sinc;
+ pitch = (signed short)pitch;
+ pitch = ((32768 + iFMod[ns]) * pitch) >> 15;
+ pitch &= 0xffff;
+ if (pitch > 0x3fff)
+  pitch = 0x3fff;
 
- NP=((32768L+iFMod[ns])*NP)>>15;
+ iFMod[ns] = 0;
+ SB[32] = 1;                                           // reset interpolation
 
- if(NP>0x3fff) NP=0x3fff;
- if(NP<0x1)    NP=0x1;
-
- sinc=NP<<4;                                           // calc frequency
- iFMod[ns]=0;
- SB[32]=1;                                             // reset interpolation
-
- return sinc;
+ return pitch << 4;
 }                    
 
 ////////////////////////////////////////////////////////////////////////
@@ -398,16 +396,18 @@ static void decode_block_data(int *dest, const unsigned char *src, int predict_n
   d = (int)*src;
   s = (int)(signed short)((d & 0x0f) << 12);
 
-  fa = s >> shift_factor;
+  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;
+  ssat32_to_16(fa);
+  s_2 = s_1; s_1 = fa;
 
   dest[nSample++] = fa;
 
   s = (int)(signed short)((d & 0xf0) << 8);
-  fa = s >> shift_factor;
+  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;
+  ssat32_to_16(fa);
+  s_2 = s_1; s_1 = fa;
 
   dest[nSample++] = fa;
  }
@@ -421,8 +421,11 @@ static int decode_block(void *unused, int ch, int *SB)
  int ret = 0;
 
  start = s_chan->pCurr;                    // set up the current pos
- if (start == spu.spuMemC)                 // ?
+ if (start - spu.spuMemC < 0x1000) {       // ?
+  //log_unhandled("ch%02d plays decode bufs @%05lx\n",
+  //  ch, (long)(start - spu.spuMemC));
   ret = 1;
+ }
 
  if (s_chan->prevflags & 1)                // 1: stop/loop
  {
@@ -448,6 +451,7 @@ static int decode_block(void *unused, int ch, int *SB)
 
  s_chan->pCurr = start;                    // store values for next cycle
  s_chan->prevflags = flags;
+ s_chan->bStarting = 0;
 
  return ret;
 }
@@ -477,6 +481,7 @@ static int skip_block(int ch)
 
  s_chan->pCurr = start;
  s_chan->prevflags = flags;
+ s_chan->bStarting = 0;
 
  return ret;
 }
@@ -493,6 +498,8 @@ static void scan_for_irq(int ch, unsigned int *upd_samples)
  pos = s_chan->spos;
  sinc = s_chan->sinc;
  end = pos + *upd_samples * sinc;
+ if (s_chan->prevflags & 1)                 // 1: stop/loop
+  block = s_chan->pLoop;
 
  pos += (28 - s_chan->iSBPos) << 16;
  while (pos < end)
@@ -792,12 +799,14 @@ static void do_channels(int ns_to)
     d = do_samples_default(decode_block, NULL, ch, ns_to,
           SB, sinc, &s_chan->spos, &s_chan->iSBPos);
 
-   d = MixADSR(&s_chan->ADSRX, d);
-   if (d < ns_to) {
-    spu.dwChannelsAudible &= ~(1 << ch);
-    s_chan->ADSRX.State = ADSR_RELEASE;
-    s_chan->ADSRX.EnvelopeVol = 0;
-    memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
+   if (!s_chan->bStarting) {
+    d = MixADSR(&s_chan->ADSRX, d);
+    if (d < ns_to) {
+     spu.dwChannelsAudible &= ~(1 << ch);
+     s_chan->ADSRX.State = ADSR_RELEASE;
+     s_chan->ADSRX.EnvelopeVol = 0;
+     memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
+    }
    }
 
    if (ch == 1 || ch == 3)
@@ -814,6 +823,8 @@ static void do_channels(int ns_to)
     mix_chan(spu.SSumLR, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume);
   }
 
+  MixXA(spu.SSumLR, RVB, ns_to, spu.decode_pos);
+
   if (spu.rvb->StartAddr) {
    if (do_rvb)
     REVERBDo(spu.SSumLR, RVB, ns_to, spu.rvb->CurrAddr);
@@ -829,7 +840,7 @@ static void do_samples_finish(int *SSumLR, int ns_to,
 
 // optional worker thread handling
 
-#if HAVE_PTHREAD || defined(WANT_THREAD_CODE)
+#if P_HAVE_PTHREAD || defined(WANT_THREAD_CODE)
 
 // worker thread state
 static struct spu_worker {
@@ -961,12 +972,14 @@ static void queue_channel_work(int ns_to, unsigned int silentch)
    d = do_samples_skip(ch, ns_to);
    work->ch[ch].ns_to = d;
 
-   // note: d is not accurate on skip
-   d = SkipADSR(&s_chan->ADSRX, d);
-   if (d < ns_to) {
-    spu.dwChannelsAudible &= ~(1 << ch);
-    s_chan->ADSRX.State = ADSR_RELEASE;
-    s_chan->ADSRX.EnvelopeVol = 0;
+   if (!s_chan->bStarting) {
+    // note: d is not accurate on skip
+    d = SkipADSR(&s_chan->ADSRX, d);
+    if (d < ns_to) {
+     spu.dwChannelsAudible &= ~(1 << ch);
+     s_chan->ADSRX.State = ADSR_RELEASE;
+     s_chan->ADSRX.EnvelopeVol = 0;
+    }
    }
    s_chan->bNewPitch = 0;
   }
@@ -1066,6 +1079,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);
   do_samples_finish(work->SSumLR, work->ns_to,
    work->channels_silent, work->decode_pos);
 
@@ -1084,7 +1098,7 @@ static void sync_worker_thread(int force) {}
 
 static const void * const worker = NULL;
 
-#endif // HAVE_PTHREAD || defined(WANT_THREAD_CODE)
+#endif // P_HAVE_PTHREAD || defined(WANT_THREAD_CODE)
 
 ////////////////////////////////////////////////////////////////////////
 // MAIN SPU FUNCTION
@@ -1149,7 +1163,10 @@ void do_samples(unsigned int cycles_to, int do_direct)
       do_irq();
      }
    }
-  check_irq_io(spu.spuAddr);
+  if (!spu.cycles_dma_end || (int)(spu.cycles_dma_end - cycles_to) < 0) {
+   spu.cycles_dma_end = 0;
+   check_irq_io(spu.spuAddr);
+  }
 
   if (unlikely(spu.rvb->dirty))
    REVERBPrep();
@@ -1170,6 +1187,11 @@ 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;
+#if 0
+  static int ccount; static time_t ctime; ccount++;
+  if (time(NULL) != ctime)
+    { printf("%d\n", ccount); ccount = 0; ctime = time(NULL); }
+#endif
 }
 
 static void do_samples_finish(int *SSumLR, int ns_to,
@@ -1192,12 +1214,10 @@ static void do_samples_finish(int *SSumLR, int ns_to,
     spu.decode_dirty_ch &= ~(1<<3);
    }
 
-  MixXA(SSumLR, ns_to, decode_pos);
-
   vol_l = vol_l * spu_config.iVolume >> 10;
   vol_r = vol_r * spu_config.iVolume >> 10;
 
-  if (!(spu.spuCtrl & 0x4000) || !(vol_l | vol_r))
+  if (!(spu.spuCtrl & CTRL_MUTE) || !(vol_l | vol_r))
    {
     // muted? (rare)
     memset(spu.pS, 0, ns_to * 2 * sizeof(spu.pS[0]));
@@ -1265,7 +1285,7 @@ void schedule_next_irq(void)
 
 void CALLBACK SPUasync(unsigned int cycle, unsigned int flags)
 {
- do_samples(cycle, spu_config.iUseFixedUpdates);
+ do_samples(cycle, 0);
 
  if (spu.spuCtrl & CTRL_IRQ)
   schedule_next_irq();
@@ -1307,6 +1327,7 @@ void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_s
   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
 }
 
 // CDDA AUDIO
@@ -1318,7 +1339,8 @@ int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes, unsigned int cycle, int
  if (is_start)
   do_samples(cycle, 1);                // catch up to prevent source underflows later
 
- return FeedCDDA((unsigned char *)pcm, nbytes);
+ FeedCDDA((unsigned char *)pcm, nbytes);
+ return 0;
 }
 
 // to be called after state load
@@ -1340,7 +1362,7 @@ static void SetupStreams(void)
  spu.XAFeed  = spu.XAStart;
 
  spu.CDDAStart = malloc(CDDA_BUFFER_SIZE);             // alloc cdda buffer
- spu.CDDAEnd   = spu.CDDAStart + 16384;
+ spu.CDDAEnd   = spu.CDDAStart + CDDA_BUFFER_SIZE / sizeof(uint32_t);
  spu.CDDAPlay  = spu.CDDAStart;
  spu.CDDAFeed  = spu.CDDAStart;
 
@@ -1365,7 +1387,7 @@ static void RemoveStreams(void)
 /* special code for TI C64x DSP */
 #include "spu_c64x.c"
 
-#elif HAVE_PTHREAD
+#elif P_HAVE_PTHREAD
 
 #include <pthread.h>
 #include <semaphore.h>
@@ -1464,7 +1486,7 @@ static void exit_spu_thread(void)
  worker = NULL;
 }
 
-#else // if !HAVE_PTHREAD
+#else // if !P_HAVE_PTHREAD
 
 static void init_spu_thread(void)
 {
@@ -1481,6 +1503,7 @@ long CALLBACK SPUinit(void)
 {
  int i;
 
+ memset(&spu, 0, sizeof(spu));
  spu.spuMemC = calloc(1, 512 * 1024);
  InitADSR();
 
@@ -1559,33 +1582,6 @@ long CALLBACK SPUshutdown(void)
  return 0;
 }
 
-// SPUTEST: we don't test, we are always fine ;)
-long CALLBACK SPUtest(void)
-{
- return 0;
-}
-
-// SPUCONFIGURE: call config dialog
-long CALLBACK SPUconfigure(void)
-{
-#ifdef _MACOSX
- DoConfiguration();
-#else
-// StartCfgTool("CFG");
-#endif
- return 0;
-}
-
-// SPUABOUT: show about window
-void CALLBACK SPUabout(void)
-{
-#ifdef _MACOSX
- DoAbout();
-#else
-// StartCfgTool("ABOUT");
-#endif
-}
-
 // SETUP CALLBACKS
 // this functions will be called once, 
 // passes a callback that should be called on SPU-IRQ/cdda volume change