spu: finish offload code to TI C64x DSP
[pcsx_rearmed.git] / plugins / dfsound / spu.c
1 /***************************************************************************
2                             spu.c  -  description
3                              -------------------
4     begin                : Wed May 15 2002
5     copyright            : (C) 2002 by Pete Bernert
6     email                : BlackDove@addcom.de
7
8  Portions (C) GraÅžvydas "notaz" Ignotas, 2010-2012,2014,2015
9
10  ***************************************************************************/
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version. See also the license.txt file for *
17  *   additional informations.                                              *
18  *                                                                         *
19  ***************************************************************************/
20
21 #if !defined(_WIN32) && !defined(NO_OS)
22 #include <sys/time.h> // gettimeofday in xa.c
23 #define THREAD_ENABLED 1
24 #endif
25 #include "stdafx.h"
26
27 #define _IN_SPU
28
29 #include "externals.h"
30 #include "registers.h"
31 #include "out.h"
32 #include "spu_config.h"
33
34 #ifdef __arm__
35 #include "arm_features.h"
36 #endif
37
38 #ifdef __ARM_ARCH_7A__
39  #define ssat32_to_16(v) \
40   asm("ssat %0,#16,%1" : "=r" (v) : "r" (v))
41 #else
42  #define ssat32_to_16(v) do { \
43   if (v < -32768) v = -32768; \
44   else if (v > 32767) v = 32767; \
45  } while (0)
46 #endif
47
48 #define PSXCLK  33868800        /* 33.8688 MHz */
49
50 // intended to be ~1 frame
51 #define IRQ_NEAR_BLOCKS 32
52
53 /*
54 #if defined (USEMACOSX)
55 static char * libraryName     = N_("Mac OS X Sound");
56 #elif defined (USEALSA)
57 static char * libraryName     = N_("ALSA Sound");
58 #elif defined (USEOSS)
59 static char * libraryName     = N_("OSS Sound");
60 #elif defined (USESDL)
61 static char * libraryName     = N_("SDL Sound");
62 #elif defined (USEPULSEAUDIO)
63 static char * libraryName     = N_("PulseAudio Sound");
64 #else
65 static char * libraryName     = N_("NULL Sound");
66 #endif
67
68 static char * libraryInfo     = N_("P.E.Op.S. Sound Driver V1.7\nCoded by Pete Bernert and the P.E.Op.S. team\n");
69 */
70
71 // globals
72
73 SPUInfo         spu;
74 SPUConfig       spu_config;
75
76 // MAIN infos struct for each channel
77
78 REVERBInfo      rvb;
79
80 #if defined(THREAD_ENABLED) || defined(WANT_THREAD_CODE)
81
82 // worker thread state
83 static struct spu_worker {
84  unsigned int pending:1;
85  unsigned int exit_thread:1;
86  unsigned int stale_cache:1;
87  int ns_to;
88  int ctrl;
89  int decode_pos;
90  int silentch;
91  unsigned int chmask;
92  struct {
93   int spos;
94   int sbpos;
95   int sinc;
96   int start;
97   int loop;
98   int ns_to;
99   ADSRInfoEx adsr;
100   // might want to add vol and fmod flags..
101  } ch[24];
102  struct {
103   struct {
104    int adsrState;
105    int adsrEnvelopeVol;
106   } ch[24];
107   unsigned int chan_end;
108   unsigned int decode_dirty;
109  } r;
110 } *worker;
111
112 #else
113 static const void * const worker = NULL;
114 #endif
115
116 // certain globals (were local before, but with the new timeproc I need em global)
117
118 static int iFMod[NSSIZE];
119 int ChanBuf[NSSIZE];
120 int *SSumLR;
121
122 #define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2
123
124 ////////////////////////////////////////////////////////////////////////
125 // CODE AREA
126 ////////////////////////////////////////////////////////////////////////
127
128 // dirty inline func includes
129
130 #include "reverb.c"
131 #include "adsr.c"
132
133 ////////////////////////////////////////////////////////////////////////
134 // helpers for simple interpolation
135
136 //
137 // easy interpolation on upsampling, no special filter, just "Pete's common sense" tm
138 //
139 // instead of having n equal sample values in a row like:
140 //       ____
141 //           |____
142 //
143 // we compare the current delta change with the next delta change.
144 //
145 // if curr_delta is positive,
146 //
147 //  - and next delta is smaller (or changing direction):
148 //         \.
149 //          -__
150 //
151 //  - and next delta significant (at least twice) bigger:
152 //         --_
153 //            \.
154 //
155 //  - and next delta is nearly same:
156 //          \.
157 //           \.
158 //
159 //
160 // if curr_delta is negative,
161 //
162 //  - and next delta is smaller (or changing direction):
163 //          _--
164 //         /
165 //
166 //  - and next delta significant (at least twice) bigger:
167 //            /
168 //         __- 
169 //
170 //  - and next delta is nearly same:
171 //           /
172 //          /
173 //
174
175 static void InterpolateUp(int *SB, int sinc)
176 {
177  if(SB[32]==1)                                         // flag == 1? calc step and set flag... and don't change the value in this pass
178   {
179    const int id1=SB[30]-SB[29];                        // curr delta to next val
180    const int id2=SB[31]-SB[30];                        // and next delta to next-next val :)
181
182    SB[32]=0;
183
184    if(id1>0)                                           // curr delta positive
185     {
186      if(id2<id1)
187       {SB[28]=id1;SB[32]=2;}
188      else
189      if(id2<(id1<<1))
190       SB[28]=(id1*sinc)>>16;
191      else
192       SB[28]=(id1*sinc)>>17;
193     }
194    else                                                // curr delta negative
195     {
196      if(id2>id1)
197       {SB[28]=id1;SB[32]=2;}
198      else
199      if(id2>(id1<<1))
200       SB[28]=(id1*sinc)>>16;
201      else
202       SB[28]=(id1*sinc)>>17;
203     }
204   }
205  else
206  if(SB[32]==2)                                         // flag 1: calc step and set flag... and don't change the value in this pass
207   {
208    SB[32]=0;
209
210    SB[28]=(SB[28]*sinc)>>17;
211    //if(sinc<=0x8000)
212    //     SB[29]=SB[30]-(SB[28]*((0x10000/sinc)-1));
213    //else
214    SB[29]+=SB[28];
215   }
216  else                                                  // no flags? add bigger val (if possible), calc smaller step, set flag1
217   SB[29]+=SB[28];
218 }
219
220 //
221 // even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
222 //
223
224 static void InterpolateDown(int *SB, int sinc)
225 {
226  if(sinc>=0x20000L)                                 // we would skip at least one val?
227   {
228    SB[29]+=(SB[30]-SB[29])/2;                                  // add easy weight
229    if(sinc>=0x30000L)                               // we would skip even more vals?
230     SB[29]+=(SB[31]-SB[30])/2;                                 // add additional next weight
231   }
232 }
233
234 ////////////////////////////////////////////////////////////////////////
235 // helpers for gauss interpolation
236
237 #define gval0 (((short*)(&SB[29]))[gpos&3])
238 #define gval(x) ((int)((short*)(&SB[29]))[(gpos+x)&3])
239
240 #include "gauss_i.h"
241
242 ////////////////////////////////////////////////////////////////////////
243
244 #include "xa.c"
245
246 static void do_irq(void)
247 {
248  //if(!(spu.spuStat & STAT_IRQ))
249  {
250   spu.spuStat |= STAT_IRQ;                             // asserted status?
251   if(spu.irqCallback) spu.irqCallback();
252  }
253 }
254
255 static int check_irq(int ch, unsigned char *pos)
256 {
257  if((spu.spuCtrl & CTRL_IRQ) && pos == spu.pSpuIrq)
258  {
259   //printf("ch%d irq %04x\n", ch, pos - spu.spuMemC);
260   do_irq();
261   return 1;
262  }
263  return 0;
264 }
265
266 ////////////////////////////////////////////////////////////////////////
267 // START SOUND... called by main thread to setup a new sound on a channel
268 ////////////////////////////////////////////////////////////////////////
269
270 INLINE void StartSound(int ch)
271 {
272  SPUCHAN *s_chan = &spu.s_chan[ch];
273  int *SB = spu.SB + ch * SB_SIZE;
274
275  StartADSR(ch);
276  StartREVERB(ch);
277
278  s_chan->prevflags=2;
279
280  s_chan->iSBPos=27;
281  SB[26]=0;                                             // init mixing vars
282  SB[27]=0;
283
284  SB[28]=0;
285  SB[29]=0;                                             // init our interpolation helpers
286  SB[30]=0;
287  SB[31]=0;
288  s_chan->spos=0;
289
290  spu.dwNewChannel&=~(1<<ch);                           // clear new channel bit
291  spu.dwChannelOn|=1<<ch;
292  spu.dwChannelDead&=~(1<<ch);
293 }
294
295 ////////////////////////////////////////////////////////////////////////
296 // ALL KIND OF HELPERS
297 ////////////////////////////////////////////////////////////////////////
298
299 INLINE int FModChangeFrequency(int *SB, int pitch, int ns)
300 {
301  unsigned int NP=pitch;
302  int sinc;
303
304  NP=((32768L+iFMod[ns])*NP)>>15;
305
306  if(NP>0x3fff) NP=0x3fff;
307  if(NP<0x1)    NP=0x1;
308
309  sinc=NP<<4;                                           // calc frequency
310  if(spu_config.iUseInterpolation==1)                   // freq change in simple interpolation mode
311   SB[32]=1;
312  iFMod[ns]=0;
313
314  return sinc;
315 }                    
316
317 ////////////////////////////////////////////////////////////////////////
318
319 INLINE void StoreInterpolationVal(int *SB, int sinc, int fa, int fmod_freq)
320 {
321  if(fmod_freq)                                         // fmod freq channel
322   SB[29]=fa;
323  else
324   {
325    ssat32_to_16(fa);
326
327    if(spu_config.iUseInterpolation>=2)                 // gauss/cubic interpolation
328     {
329      int gpos = SB[28];
330      gval0 = fa;
331      gpos = (gpos+1) & 3;
332      SB[28] = gpos;
333     }
334    else
335    if(spu_config.iUseInterpolation==1)                 // simple interpolation
336     {
337      SB[28] = 0;
338      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'
339      SB[30] = SB[31];
340      SB[31] = fa;
341      SB[32] = 1;                                       // -> flag: calc new interolation
342     }
343    else SB[29]=fa;                                     // no interpolation
344   }
345 }
346
347 ////////////////////////////////////////////////////////////////////////
348
349 INLINE int iGetInterpolationVal(int *SB, int sinc, int spos, int fmod_freq)
350 {
351  int fa;
352
353  if(fmod_freq) return SB[29];
354
355  switch(spu_config.iUseInterpolation)
356   {
357    //--------------------------------------------------//
358    case 3:                                             // cubic interpolation
359     {
360      long xd;int gpos;
361      xd = (spos >> 1)+1;
362      gpos = SB[28];
363
364      fa  = gval(3) - 3*gval(2) + 3*gval(1) - gval0;
365      fa *= (xd - (2<<15)) / 6;
366      fa >>= 15;
367      fa += gval(2) - gval(1) - gval(1) + gval0;
368      fa *= (xd - (1<<15)) >> 1;
369      fa >>= 15;
370      fa += gval(1) - gval0;
371      fa *= xd;
372      fa >>= 15;
373      fa = fa + gval0;
374
375     } break;
376    //--------------------------------------------------//
377    case 2:                                             // gauss interpolation
378     {
379      int vl, vr;int gpos;
380      vl = (spos >> 6) & ~3;
381      gpos = SB[28];
382      vr=(gauss[vl]*(int)gval0)&~2047;
383      vr+=(gauss[vl+1]*gval(1))&~2047;
384      vr+=(gauss[vl+2]*gval(2))&~2047;
385      vr+=(gauss[vl+3]*gval(3))&~2047;
386      fa = vr>>11;
387     } break;
388    //--------------------------------------------------//
389    case 1:                                             // simple interpolation
390     {
391      if(sinc<0x10000L)                                 // -> upsampling?
392           InterpolateUp(SB, sinc);                     // --> interpolate up
393      else InterpolateDown(SB, sinc);                   // --> else down
394      fa=SB[29];
395     } break;
396    //--------------------------------------------------//
397    default:                                            // no interpolation
398     {
399      fa=SB[29];
400     } break;
401    //--------------------------------------------------//
402   }
403
404  return fa;
405 }
406
407 static void decode_block_data(int *dest, const unsigned char *src, int predict_nr, int shift_factor)
408 {
409  static const int f[16][2] = {
410     {    0,  0  },
411     {   60,  0  },
412     {  115, -52 },
413     {   98, -55 },
414     {  122, -60 }
415  };
416  int nSample;
417  int fa, s_1, s_2, d, s;
418
419  s_1 = dest[27];
420  s_2 = dest[26];
421
422  for (nSample = 0; nSample < 28; src++)
423  {
424   d = (int)*src;
425   s = (int)(signed short)((d & 0x0f) << 12);
426
427   fa = s >> shift_factor;
428   fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
429   s_2=s_1;s_1=fa;
430
431   dest[nSample++] = fa;
432
433   s = (int)(signed short)((d & 0xf0) << 8);
434   fa = s >> shift_factor;
435   fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
436   s_2=s_1;s_1=fa;
437
438   dest[nSample++] = fa;
439  }
440 }
441
442 static int decode_block(int ch, int *SB)
443 {
444  SPUCHAN *s_chan = &spu.s_chan[ch];
445  unsigned char *start;
446  int predict_nr, shift_factor, flags;
447  int ret = 0;
448
449  start = s_chan->pCurr;                    // set up the current pos
450  if (start == spu.spuMemC)                 // ?
451   ret = 1;
452
453  if (s_chan->prevflags & 1)                // 1: stop/loop
454  {
455   if (!(s_chan->prevflags & 2))
456    ret = 1;
457
458   start = s_chan->pLoop;
459  }
460  else
461   check_irq(ch, start);                    // hack, see check_irq below..
462
463  predict_nr = start[0];
464  shift_factor = predict_nr & 0xf;
465  predict_nr >>= 4;
466
467  decode_block_data(SB, start + 2, predict_nr, shift_factor);
468
469  flags = start[1];
470  if (flags & 4)
471   s_chan->pLoop = start;                   // loop adress
472
473  start += 16;
474
475  if (flags & 1) {                          // 1: stop/loop
476   start = s_chan->pLoop;
477   check_irq(ch, start);                    // hack.. :(
478  }
479
480  if (start - spu.spuMemC >= 0x80000)
481   start = spu.spuMemC;
482
483  s_chan->pCurr = start;                    // store values for next cycle
484  s_chan->prevflags = flags;
485
486  return ret;
487 }
488
489 // do block, but ignore sample data
490 static int skip_block(int ch)
491 {
492  SPUCHAN *s_chan = &spu.s_chan[ch];
493  unsigned char *start = s_chan->pCurr;
494  int flags;
495  int ret = 0;
496
497  if (s_chan->prevflags & 1) {
498   if (!(s_chan->prevflags & 2))
499    ret = 1;
500
501   start = s_chan->pLoop;
502  }
503  else
504   check_irq(ch, start);
505
506  flags = start[1];
507  if (flags & 4)
508   s_chan->pLoop = start;
509
510  start += 16;
511
512  if (flags & 1) {
513   start = s_chan->pLoop;
514   check_irq(ch, start);
515  }
516
517  s_chan->pCurr = start;
518  s_chan->prevflags = flags;
519
520  return ret;
521 }
522
523 #if defined(THREAD_ENABLED) || defined(WANT_THREAD_CODE)
524
525 static int decode_block_work(int ch, int *SB)
526 {
527  const unsigned char *ram = spu.spuMemC;
528  int predict_nr, shift_factor, flags;
529  int start = worker->ch[ch].start;
530  int loop = worker->ch[ch].loop;
531
532  predict_nr = ram[start];
533  shift_factor = predict_nr & 0xf;
534  predict_nr >>= 4;
535
536  decode_block_data(SB, ram + start + 2, predict_nr, shift_factor);
537
538  flags = ram[start + 1];
539  if (flags & 4)
540   loop = start;                            // loop adress
541
542  start += 16;
543
544  if (flags & 1)                            // 1: stop/loop
545   start = loop;
546
547  worker->ch[ch].start = start & 0x7ffff;
548  worker->ch[ch].loop = loop;
549
550  return 0;
551 }
552
553 #endif
554
555 // if irq is going to trigger sooner than in upd_samples, set upd_samples
556 static void scan_for_irq(int ch, unsigned int *upd_samples)
557 {
558  SPUCHAN *s_chan = &spu.s_chan[ch];
559  int pos, sinc, sinc_inv, end;
560  unsigned char *block;
561  int flags;
562
563  block = s_chan->pCurr;
564  pos = s_chan->spos;
565  sinc = s_chan->sinc;
566  end = pos + *upd_samples * sinc;
567
568  pos += (28 - s_chan->iSBPos) << 16;
569  while (pos < end)
570  {
571   if (block == spu.pSpuIrq)
572    break;
573   flags = block[1];
574   block += 16;
575   if (flags & 1) {                          // 1: stop/loop
576    block = s_chan->pLoop;
577    if (block == spu.pSpuIrq)                // hack.. (see decode_block)
578     break;
579   }
580   pos += 28 << 16;
581  }
582
583  if (pos < end)
584  {
585   sinc_inv = s_chan->sinc_inv;
586   if (sinc_inv == 0)
587    sinc_inv = s_chan->sinc_inv = (0x80000000u / (uint32_t)sinc) << 1;
588
589   pos -= s_chan->spos;
590   *upd_samples = (((uint64_t)pos * sinc_inv) >> 32) + 1;
591   //xprintf("ch%02d: irq sched: %3d %03d\n",
592   // ch, *upd_samples, *upd_samples * 60 * 263 / 44100);
593  }
594 }
595
596 #define make_do_samples(name, fmod_code, interp_start, interp1_code, interp2_code, interp_end) \
597 static noinline int do_samples_##name(int (*decode_f)(int ch, int *SB), int ch, \
598  int ns_to, int *SB, int sinc, int *spos, int *sbpos) \
599 {                                            \
600  int ns, d, fa;                              \
601  int ret = ns_to;                            \
602  interp_start;                               \
603                                              \
604  for (ns = 0; ns < ns_to; ns++)              \
605  {                                           \
606   fmod_code;                                 \
607                                              \
608   *spos += sinc;                             \
609   while (*spos >= 0x10000)                   \
610   {                                          \
611    fa = SB[(*sbpos)++];                      \
612    if (*sbpos >= 28)                         \
613    {                                         \
614     *sbpos = 0;                              \
615     d = decode_f(ch, SB);                    \
616     if (d && ns < ret)                       \
617      ret = ns;                               \
618    }                                         \
619                                              \
620    interp1_code;                             \
621    *spos -= 0x10000;                         \
622   }                                          \
623                                              \
624   interp2_code;                              \
625  }                                           \
626                                              \
627  interp_end;                                 \
628                                              \
629  return ret;                                 \
630 }
631
632 #define fmod_recv_check \
633   if(spu.s_chan[ch].bFMod==1 && iFMod[ns]) \
634     sinc = FModChangeFrequency(SB, spu.s_chan[ch].iRawPitch, ns)
635
636 make_do_samples(default, fmod_recv_check, ,
637   StoreInterpolationVal(SB, sinc, fa, spu.s_chan[ch].bFMod==2),
638   ChanBuf[ns] = iGetInterpolationVal(SB, sinc, *spos, spu.s_chan[ch].bFMod==2), )
639 make_do_samples(noint, , fa = SB[29], , ChanBuf[ns] = fa, SB[29] = fa)
640
641 #define simple_interp_store \
642   SB[28] = 0; \
643   SB[29] = SB[30]; \
644   SB[30] = SB[31]; \
645   SB[31] = fa; \
646   SB[32] = 1
647
648 #define simple_interp_get \
649   if(sinc<0x10000)                /* -> upsampling? */ \
650        InterpolateUp(SB, sinc);   /* --> interpolate up */ \
651   else InterpolateDown(SB, sinc); /* --> else down */ \
652   ChanBuf[ns] = SB[29]
653
654 make_do_samples(simple, , ,
655   simple_interp_store, simple_interp_get, )
656
657 static int do_samples_skip(int ch, int ns_to)
658 {
659  SPUCHAN *s_chan = &spu.s_chan[ch];
660  int ret = ns_to, ns, d;
661
662  s_chan->spos += s_chan->iSBPos << 16;
663
664  for (ns = 0; ns < ns_to; ns++)
665  {
666   s_chan->spos += s_chan->sinc;
667   while (s_chan->spos >= 28*0x10000)
668   {
669    d = skip_block(ch);
670    if (d && ns < ret)
671     ret = ns;
672    s_chan->spos -= 28*0x10000;
673   }
674  }
675
676  s_chan->iSBPos = s_chan->spos >> 16;
677  s_chan->spos &= 0xffff;
678
679  return ret;
680 }
681
682 static void do_lsfr_samples(int ns_to, int ctrl,
683  unsigned int *dwNoiseCount, unsigned int *dwNoiseVal)
684 {
685  unsigned int counter = *dwNoiseCount;
686  unsigned int val = *dwNoiseVal;
687  unsigned int level, shift, bit;
688  int ns;
689
690  // modified from DrHell/shalma, no fraction
691  level = (ctrl >> 10) & 0x0f;
692  level = 0x8000 >> level;
693
694  for (ns = 0; ns < ns_to; ns++)
695  {
696   counter += 2;
697   if (counter >= level)
698   {
699    counter -= level;
700    shift = (val >> 10) & 0x1f;
701    bit = (0x69696969 >> shift) & 1;
702    bit ^= (val >> 15) & 1;
703    val = (val << 1) | bit;
704   }
705
706   ChanBuf[ns] = (signed short)val;
707  }
708
709  *dwNoiseCount = counter;
710  *dwNoiseVal = val;
711 }
712
713 static int do_samples_noise(int ch, int ns_to)
714 {
715  int ret;
716
717  ret = do_samples_skip(ch, ns_to);
718
719  do_lsfr_samples(ns_to, spu.spuCtrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
720
721  return ret;
722 }
723
724 #ifdef HAVE_ARMV5
725 // asm code; lv and rv must be 0-3fff
726 extern void mix_chan(int start, int count, int lv, int rv);
727 extern void mix_chan_rvb(int start, int count, int lv, int rv, int *rvb);
728 #else
729 static void mix_chan(int start, int count, int lv, int rv)
730 {
731  int *dst = SSumLR + start * 2;
732  const int *src = ChanBuf + start;
733  int l, r;
734
735  while (count--)
736   {
737    int sval = *src++;
738
739    l = (sval * lv) >> 14;
740    r = (sval * rv) >> 14;
741    *dst++ += l;
742    *dst++ += r;
743   }
744 }
745
746 static void mix_chan_rvb(int start, int count, int lv, int rv, int *rvb)
747 {
748  int *dst = SSumLR + start * 2;
749  int *drvb = rvb + start * 2;
750  const int *src = ChanBuf + start;
751  int l, r;
752
753  while (count--)
754   {
755    int sval = *src++;
756
757    l = (sval * lv) >> 14;
758    r = (sval * rv) >> 14;
759    *dst++ += l;
760    *dst++ += r;
761    *drvb++ += l;
762    *drvb++ += r;
763   }
764 }
765 #endif
766
767 // 0x0800-0x0bff  Voice 1
768 // 0x0c00-0x0fff  Voice 3
769 static noinline void do_decode_bufs(unsigned short *mem, int which,
770  int count, int decode_pos)
771 {
772  unsigned short *dst = &mem[0x800/2 + which*0x400/2];
773  const int *src = ChanBuf;
774  int cursor = decode_pos;
775
776  while (count-- > 0)
777   {
778    cursor &= 0x1ff;
779    dst[cursor] = *src++;
780    cursor++;
781   }
782
783  // decode_pos is updated and irqs are checked later, after voice loop
784 }
785
786 static void do_silent_chans(int ns_to, int silentch)
787 {
788  unsigned int mask;
789  SPUCHAN *s_chan;
790  int ch;
791
792  mask = silentch & 0xffffff;
793  for (ch = 0; mask != 0; ch++, mask >>= 1)
794   {
795    if (!(mask & 1)) continue;
796    if (spu.dwChannelDead & (1<<ch)) continue;
797
798    s_chan = &spu.s_chan[ch];
799    if (s_chan->pCurr > spu.pSpuIrq && s_chan->pLoop > spu.pSpuIrq)
800     continue;
801
802    s_chan->spos += s_chan->iSBPos << 16;
803    s_chan->iSBPos = 0;
804
805    s_chan->spos += s_chan->sinc * ns_to;
806    while (s_chan->spos >= 28 * 0x10000)
807     {
808      unsigned char *start = s_chan->pCurr;
809
810      skip_block(ch);
811      if (start == s_chan->pCurr || start - spu.spuMemC < 0x1000)
812       {
813        // looping on self or stopped(?)
814        spu.dwChannelDead |= 1<<ch;
815        s_chan->spos = 0;
816        break;
817       }
818
819      s_chan->spos -= 28 * 0x10000;
820     }
821   }
822 }
823
824 static void do_channels(int ns_to)
825 {
826  unsigned int mask;
827  SPUCHAN *s_chan;
828  int *SB, sinc;
829  int ch, d;
830
831  InitREVERB(ns_to);
832
833  mask = spu.dwChannelOn & 0xffffff;
834  for (ch = 0; mask != 0; ch++, mask >>= 1)         // loop em all...
835   {
836    if (!(mask & 1)) continue;                      // channel not playing? next
837
838    s_chan = &spu.s_chan[ch];
839    SB = spu.SB + ch * SB_SIZE;
840    sinc = s_chan->sinc;
841
842    if (s_chan->bNoise)
843     d = do_samples_noise(ch, ns_to);
844    else if (s_chan->bFMod == 2
845          || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0))
846     d = do_samples_noint(decode_block, ch, ns_to,
847           SB, sinc, &s_chan->spos, &s_chan->iSBPos);
848    else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1)
849     d = do_samples_simple(decode_block, ch, ns_to,
850           SB, sinc, &s_chan->spos, &s_chan->iSBPos);
851    else
852     d = do_samples_default(decode_block, ch, ns_to,
853           SB, sinc, &s_chan->spos, &s_chan->iSBPos);
854
855    d = MixADSR(&s_chan->ADSRX, d);
856    if (d < ns_to) {
857     spu.dwChannelOn &= ~(1 << ch);
858     s_chan->ADSRX.EnvelopeVol = 0;
859     memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
860    }
861
862    if (ch == 1 || ch == 3)
863     {
864      do_decode_bufs(spu.spuMem, ch/2, ns_to, spu.decode_pos);
865      spu.decode_dirty_ch |= 1 << ch;
866     }
867
868    if (s_chan->bFMod == 2)                         // fmod freq channel
869     memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0]));
870    if (s_chan->bRVBActive)
871     mix_chan_rvb(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume, spu.sRVBStart);
872    else
873     mix_chan(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume);
874   }
875 }
876
877 static void do_samples_finish(int ns_to, int silentch, int decode_pos);
878
879 // optional worker thread handling
880
881 #if defined(THREAD_ENABLED) || defined(WANT_THREAD_CODE)
882
883 static void thread_work_start(void);
884 static void thread_work_wait_sync(void);
885 static void thread_sync_caches(void);
886
887 static void queue_channel_work(int ns_to, int silentch)
888 {
889  const SPUCHAN *s_chan;
890  unsigned int mask;
891  int ch;
892
893  worker->ns_to = ns_to;
894  worker->ctrl = spu.spuCtrl;
895  worker->decode_pos = spu.decode_pos;
896  worker->silentch = silentch;
897
898  mask = worker->chmask = spu.dwChannelOn & 0xffffff;
899  for (ch = 0; mask != 0; ch++, mask >>= 1)
900   {
901    if (!(mask & 1)) continue;
902
903    s_chan = &spu.s_chan[ch];
904    worker->ch[ch].spos = s_chan->spos;
905    worker->ch[ch].sbpos = s_chan->iSBPos;
906    worker->ch[ch].sinc = s_chan->sinc;
907    worker->ch[ch].adsr = s_chan->ADSRX;
908    worker->ch[ch].start = s_chan->pCurr - spu.spuMemC;
909    worker->ch[ch].loop = s_chan->pLoop - spu.spuMemC;
910    if (s_chan->prevflags & 1)
911     worker->ch[ch].start = worker->ch[ch].loop;
912
913    worker->ch[ch].ns_to = do_samples_skip(ch, ns_to);
914   }
915
916  worker->pending = 1;
917  thread_work_start();
918 }
919
920 static void do_channel_work(void)
921 {
922  unsigned int mask, endmask = 0;
923  unsigned int decode_dirty_ch = 0;
924  int *SB, sinc, spos, sbpos;
925  int d, ch, ns_to;
926  SPUCHAN *s_chan;
927
928  ns_to = worker->ns_to;
929  memset(spu.sRVBStart, 0, ns_to * sizeof(spu.sRVBStart[0]) * 2);
930
931  mask = worker->chmask;
932  for (ch = 0; mask != 0; ch++, mask >>= 1)
933   {
934    if (!(mask & 1)) continue;
935
936    d = worker->ch[ch].ns_to;
937    spos = worker->ch[ch].spos;
938    sbpos = worker->ch[ch].sbpos;
939    sinc = worker->ch[ch].sinc;
940
941    s_chan = &spu.s_chan[ch];
942    SB = spu.SB + ch * SB_SIZE;
943
944    if (s_chan->bNoise)
945     do_lsfr_samples(d, worker->ctrl, &spu.dwNoiseCount, &spu.dwNoiseVal);
946    else if (s_chan->bFMod == 2
947          || (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 0))
948     do_samples_noint(decode_block_work, ch, d, SB, sinc, &spos, &sbpos);
949    else if (s_chan->bFMod == 0 && spu_config.iUseInterpolation == 1)
950     do_samples_simple(decode_block_work, ch, d, SB, sinc, &spos, &sbpos);
951    else
952     do_samples_default(decode_block_work, ch, d, SB, sinc, &spos, &sbpos);
953
954    d = MixADSR(&worker->ch[ch].adsr, d);
955    if (d < ns_to) {
956     endmask |= 1 << ch;
957     worker->ch[ch].adsr.EnvelopeVol = 0;
958     memset(&ChanBuf[d], 0, (ns_to - d) * sizeof(ChanBuf[0]));
959    }
960    worker->r.ch[ch].adsrState = worker->ch[ch].adsr.State;
961    worker->r.ch[ch].adsrEnvelopeVol = worker->ch[ch].adsr.EnvelopeVol;
962
963    if (ch == 1 || ch == 3)
964     {
965      do_decode_bufs(spu.spuMem, ch/2, ns_to, worker->decode_pos);
966      decode_dirty_ch |= 1 << ch;
967     }
968
969    if (s_chan->bFMod == 2)                         // fmod freq channel
970     memcpy(iFMod, &ChanBuf, ns_to * sizeof(iFMod[0]));
971    if (s_chan->bRVBActive)
972     mix_chan_rvb(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume, spu.sRVBStart);
973    else
974     mix_chan(0, ns_to, s_chan->iLeftVolume, s_chan->iRightVolume);
975   }
976
977   worker->r.chan_end = endmask;
978   worker->r.decode_dirty = decode_dirty_ch;
979 }
980
981 static void sync_worker_thread(int do_direct)
982 {
983  unsigned int mask;
984  int ch;
985
986  if (do_direct)
987   thread_sync_caches();
988  if (!worker->pending)
989   return;
990
991  thread_work_wait_sync();
992  worker->pending = 0;
993
994  mask = worker->chmask;
995  for (ch = 0; mask != 0; ch++, mask >>= 1) {
996   if (!(mask & 1)) continue;
997
998   // be sure there was no keyoff while thread was working
999   if (spu.s_chan[ch].ADSRX.State != ADSR_RELEASE)
1000     spu.s_chan[ch].ADSRX.State = worker->r.ch[ch].adsrState;
1001   spu.s_chan[ch].ADSRX.EnvelopeVol = worker->r.ch[ch].adsrEnvelopeVol;
1002  }
1003
1004  spu.dwChannelOn &= ~worker->r.chan_end;
1005  spu.decode_dirty_ch |= worker->r.decode_dirty;
1006
1007  do_samples_finish(worker->ns_to, worker->silentch,
1008   worker->decode_pos);
1009 }
1010
1011 #else
1012
1013 static void queue_channel_work(int ns_to, int silentch) {}
1014 static void sync_worker_thread(int do_direct) {}
1015
1016 #endif // THREAD_ENABLED
1017
1018 ////////////////////////////////////////////////////////////////////////
1019 // MAIN SPU FUNCTION
1020 // here is the main job handler...
1021 ////////////////////////////////////////////////////////////////////////
1022
1023 void do_samples(unsigned int cycles_to, int do_direct)
1024 {
1025  unsigned int mask;
1026  int ch, ns_to;
1027  int silentch;
1028  int cycle_diff;
1029
1030  cycle_diff = cycles_to - spu.cycles_played;
1031  if (cycle_diff < -2*1048576 || cycle_diff > 2*1048576)
1032   {
1033    //xprintf("desync %u %d\n", cycles_to, cycle_diff);
1034    spu.cycles_played = cycles_to;
1035    return;
1036   }
1037
1038  do_direct |= (cycle_diff < 64 * 768);
1039  if (worker != NULL)
1040   sync_worker_thread(do_direct);
1041
1042  if (cycle_diff < 2 * 768)
1043   return;
1044
1045  ns_to = (cycle_diff / 768 + 1) & ~1;
1046  if (ns_to > NSSIZE) {
1047   // should never happen
1048   //xprintf("ns_to oflow %d %d\n", ns_to, NSSIZE);
1049   ns_to = NSSIZE;
1050  }
1051
1052   //////////////////////////////////////////////////////
1053   // special irq handling in the decode buffers (0x0000-0x1000)
1054   // we know:
1055   // the decode buffers are located in spu memory in the following way:
1056   // 0x0000-0x03ff  CD audio left
1057   // 0x0400-0x07ff  CD audio right
1058   // 0x0800-0x0bff  Voice 1
1059   // 0x0c00-0x0fff  Voice 3
1060   // and decoded data is 16 bit for one sample
1061   // we assume:
1062   // even if voices 1/3 are off or no cd audio is playing, the internal
1063   // play positions will move on and wrap after 0x400 bytes.
1064   // Therefore: we just need a pointer from spumem+0 to spumem+3ff, and
1065   // increase this pointer on each sample by 2 bytes. If this pointer
1066   // (or 0x400 offsets of this pointer) hits the spuirq address, we generate
1067   // an IRQ.
1068
1069   if (unlikely((spu.spuCtrl & CTRL_IRQ)
1070        && spu.pSpuIrq < spu.spuMemC+0x1000))
1071    {
1072     int irq_pos = (spu.pSpuIrq - spu.spuMemC) / 2 & 0x1ff;
1073     int left = (irq_pos - spu.decode_pos) & 0x1ff;
1074     if (0 < left && left <= ns_to)
1075      {
1076       //xprintf("decoder irq %x\n", spu.decode_pos);
1077       do_irq();
1078      }
1079    }
1080
1081   mask = spu.dwNewChannel & 0xffffff;
1082   for (ch = 0; mask != 0; ch++, mask >>= 1) {
1083    if (mask & 1)
1084     StartSound(ch);
1085   }
1086
1087   silentch = ~spu.dwChannelOn & 0xffffff;
1088
1089   if (spu.dwChannelOn == 0) {
1090    InitREVERB(ns_to);
1091    do_samples_finish(ns_to, silentch, spu.decode_pos);
1092   }
1093   else {
1094    if (do_direct || worker == NULL || !spu_config.iUseThread) {
1095     do_channels(ns_to);
1096     do_samples_finish(ns_to, silentch, spu.decode_pos);
1097    }
1098    else {
1099     queue_channel_work(ns_to, silentch);
1100    }
1101   }
1102
1103   // advance "stopped" channels that can cause irqs
1104   // (all chans are always playing on the real thing..)
1105   if (spu.spuCtrl & CTRL_IRQ)
1106    do_silent_chans(ns_to, silentch);
1107
1108   spu.cycles_played += ns_to * 768;
1109   spu.decode_pos = (spu.decode_pos + ns_to) & 0x1ff;
1110 }
1111
1112 static void do_samples_finish(int ns_to, int silentch, int decode_pos)
1113 {
1114   int volmult = spu_config.iVolume;
1115   int ns;
1116   int d;
1117
1118   if(unlikely(silentch & spu.decode_dirty_ch & (1<<1))) // must clear silent channel decode buffers
1119    {
1120     memset(&spu.spuMem[0x800/2], 0, 0x400);
1121     spu.decode_dirty_ch &= ~(1<<1);
1122    }
1123   if(unlikely(silentch & spu.decode_dirty_ch & (1<<3)))
1124    {
1125     memset(&spu.spuMem[0xc00/2], 0, 0x400);
1126     spu.decode_dirty_ch &= ~(1<<3);
1127    }
1128
1129   //---------------------------------------------------//
1130   // mix XA infos (if any)
1131
1132   MixXA(ns_to, decode_pos);
1133   
1134   ///////////////////////////////////////////////////////
1135   // mix all channels (including reverb) into one buffer
1136
1137   if(spu_config.iUseReverb)
1138    REVERBDo(ns_to);
1139
1140   if((spu.spuCtrl&0x4000)==0) // muted? (rare, don't optimize for this)
1141    {
1142     memset(spu.pS, 0, ns_to * 2 * sizeof(spu.pS[0]));
1143     spu.pS += ns_to * 2;
1144    }
1145   else
1146   for (ns = 0; ns < ns_to * 2; )
1147    {
1148     d = SSumLR[ns]; SSumLR[ns] = 0;
1149     d = d * volmult >> 10;
1150     ssat32_to_16(d);
1151     *spu.pS++ = d;
1152     ns++;
1153
1154     d = SSumLR[ns]; SSumLR[ns] = 0;
1155     d = d * volmult >> 10;
1156     ssat32_to_16(d);
1157     *spu.pS++ = d;
1158     ns++;
1159    }
1160 }
1161
1162 void schedule_next_irq(void)
1163 {
1164  unsigned int upd_samples;
1165  int ch;
1166
1167  if (spu.scheduleCallback == NULL)
1168   return;
1169
1170  upd_samples = 44100 / 50;
1171
1172  for (ch = 0; ch < MAXCHAN; ch++)
1173  {
1174   if (spu.dwChannelDead & (1 << ch))
1175    continue;
1176   if ((unsigned long)(spu.pSpuIrq - spu.s_chan[ch].pCurr) > IRQ_NEAR_BLOCKS * 16
1177     && (unsigned long)(spu.pSpuIrq - spu.s_chan[ch].pLoop) > IRQ_NEAR_BLOCKS * 16)
1178    continue;
1179
1180   scan_for_irq(ch, &upd_samples);
1181  }
1182
1183  if (unlikely(spu.pSpuIrq < spu.spuMemC + 0x1000))
1184  {
1185   int irq_pos = (spu.pSpuIrq - spu.spuMemC) / 2 & 0x1ff;
1186   int left = (irq_pos - spu.decode_pos) & 0x1ff;
1187   if (0 < left && left < upd_samples) {
1188    //xprintf("decode: %3d (%3d/%3d)\n", left, spu.decode_pos, irq_pos);
1189    upd_samples = left;
1190   }
1191  }
1192
1193  if (upd_samples < 44100 / 50)
1194   spu.scheduleCallback(upd_samples * 768);
1195 }
1196
1197 // SPU ASYNC... even newer epsxe func
1198 //  1 time every 'cycle' cycles... harhar
1199
1200 // rearmed: called dynamically now
1201
1202 void CALLBACK SPUasync(unsigned int cycle, unsigned int flags)
1203 {
1204  do_samples(cycle, 0);
1205
1206  if (spu.spuCtrl & CTRL_IRQ)
1207   schedule_next_irq();
1208
1209  if (flags & 1) {
1210   out_current->feed(spu.pSpuBuffer, (unsigned char *)spu.pS - spu.pSpuBuffer);
1211   spu.pS = (short *)spu.pSpuBuffer;
1212
1213   if (spu_config.iTempo) {
1214    if (!out_current->busy())
1215     // cause more samples to be generated
1216     // (and break some games because of bad sync)
1217     spu.cycles_played -= 44100 / 60 / 2 * 768;
1218   }
1219  }
1220 }
1221
1222 // SPU UPDATE... new epsxe func
1223 //  1 time every 32 hsync lines
1224 //  (312/32)x50 in pal
1225 //  (262/32)x60 in ntsc
1226
1227 // since epsxe 1.5.2 (linux) uses SPUupdate, not SPUasync, I will
1228 // leave that func in the linux port, until epsxe linux is using
1229 // the async function as well
1230
1231 void CALLBACK SPUupdate(void)
1232 {
1233 }
1234
1235 // XA AUDIO
1236
1237 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap)
1238 {
1239  if(!xap)       return;
1240  if(!xap->freq) return;                                // no xa freq ? bye
1241
1242  FeedXA(xap);                                          // call main XA feeder
1243 }
1244
1245 // CDDA AUDIO
1246 int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
1247 {
1248  if (!pcm)      return -1;
1249  if (nbytes<=0) return -1;
1250
1251  return FeedCDDA((unsigned char *)pcm, nbytes);
1252 }
1253
1254 // to be called after state load
1255 void ClearWorkingState(void)
1256 {
1257  memset(SSumLR, 0, NSSIZE * 2 * 4);                    // init some mixing buffers
1258  memset(iFMod, 0, sizeof(iFMod));
1259  spu.pS=(short *)spu.pSpuBuffer;                       // setup soundbuffer pointer
1260 }
1261
1262 // SETUPSTREAMS: init most of the spu buffers
1263 void SetupStreams(void)
1264
1265  int i;
1266
1267  spu.pSpuBuffer = (unsigned char *)malloc(32768);      // alloc mixing buffer
1268  spu.sRVBStart = calloc(NSSIZE * 2, sizeof(spu.sRVBStart[0]));
1269  SSumLR = calloc(NSSIZE * 2, sizeof(SSumLR[0]));
1270
1271  spu.XAStart =                                         // alloc xa buffer
1272   (uint32_t *)malloc(44100 * sizeof(uint32_t));
1273  spu.XAEnd   = spu.XAStart + 44100;
1274  spu.XAPlay  = spu.XAStart;
1275  spu.XAFeed  = spu.XAStart;
1276
1277  spu.CDDAStart =                                       // alloc cdda buffer
1278   (uint32_t *)malloc(CDDA_BUFFER_SIZE);
1279  spu.CDDAEnd   = spu.CDDAStart + 16384;
1280  spu.CDDAPlay  = spu.CDDAStart;
1281  spu.CDDAFeed  = spu.CDDAStart;
1282
1283  for(i=0;i<MAXCHAN;i++)                                // loop sound channels
1284   {
1285    spu.s_chan[i].ADSRX.SustainLevel = 0xf;             // -> init sustain
1286    spu.s_chan[i].ADSRX.SustainIncrease = 1;
1287    spu.s_chan[i].pLoop=spu.spuMemC;
1288    spu.s_chan[i].pCurr=spu.spuMemC;
1289   }
1290
1291  ClearWorkingState();
1292
1293  spu.bSpuInit=1;                                       // flag: we are inited
1294 }
1295
1296 // REMOVESTREAMS: free most buffer
1297 void RemoveStreams(void)
1298
1299  free(spu.pSpuBuffer);                                 // free mixing buffer
1300  spu.pSpuBuffer = NULL;
1301  free(spu.sRVBStart);                                  // free reverb buffer
1302  spu.sRVBStart = NULL;
1303  free(SSumLR);
1304  SSumLR = NULL;
1305  free(spu.XAStart);                                    // free XA buffer
1306  spu.XAStart = NULL;
1307  free(spu.CDDAStart);                                  // free CDDA buffer
1308  spu.CDDAStart = NULL;
1309 }
1310
1311 #if defined(C64X_DSP)
1312
1313 /* special code for TI C64x DSP */
1314 #include "spu_c64x.c"
1315
1316 #elif defined(THREAD_ENABLED)
1317
1318 #include <pthread.h>
1319 #include <semaphore.h>
1320 #include <unistd.h>
1321
1322 static struct {
1323  pthread_t thread;
1324  sem_t sem_avail;
1325  sem_t sem_done;
1326 } t;
1327
1328 /* generic pthread implementation */
1329
1330 static void thread_work_start(void)
1331 {
1332  sem_post(&t.sem_avail);
1333 }
1334
1335 static void thread_work_wait_sync(void)
1336 {
1337  sem_wait(&t.sem_done);
1338 }
1339
1340 static void thread_sync_caches(void)
1341 {
1342 }
1343
1344 static void *spu_worker_thread(void *unused)
1345 {
1346  while (1) {
1347   sem_wait(&t.sem_avail);
1348   if (worker->exit_thread)
1349    break;
1350
1351   do_channel_work();
1352
1353   sem_post(&t.sem_done);
1354  }
1355
1356  return NULL;
1357 }
1358
1359 static void init_spu_thread(void)
1360 {
1361  int ret;
1362
1363  if (sysconf(_SC_NPROCESSORS_ONLN) <= 1)
1364   return;
1365
1366  worker = calloc(1, sizeof(*worker));
1367  if (worker == NULL)
1368   return;
1369  ret = sem_init(&t.sem_avail, 0, 0);
1370  if (ret != 0)
1371   goto fail_sem_avail;
1372  ret = sem_init(&t.sem_done, 0, 0);
1373  if (ret != 0)
1374   goto fail_sem_done;
1375
1376  ret = pthread_create(&t.thread, NULL, spu_worker_thread, NULL);
1377  if (ret != 0)
1378   goto fail_thread;
1379
1380  return;
1381
1382 fail_thread:
1383  sem_destroy(&t.sem_done);
1384 fail_sem_done:
1385  sem_destroy(&t.sem_avail);
1386 fail_sem_avail:
1387  free(worker);
1388  worker = NULL;
1389 }
1390
1391 static void exit_spu_thread(void)
1392 {
1393  if (worker == NULL)
1394   return;
1395  worker->exit_thread = 1;
1396  sem_post(&t.sem_avail);
1397  pthread_join(t.thread, NULL);
1398  sem_destroy(&t.sem_done);
1399  sem_destroy(&t.sem_avail);
1400  free(worker);
1401  worker = NULL;
1402 }
1403
1404 #else // if !THREAD_ENABLED
1405
1406 static void init_spu_thread(void)
1407 {
1408 }
1409
1410 static void exit_spu_thread(void)
1411 {
1412 }
1413
1414 #endif
1415
1416 // SPUINIT: this func will be called first by the main emu
1417 long CALLBACK SPUinit(void)
1418 {
1419  spu.spuMemC = calloc(1, 512 * 1024);
1420  memset((void *)&rvb, 0, sizeof(REVERBInfo));
1421  InitADSR();
1422
1423  spu.s_chan = calloc(MAXCHAN+1, sizeof(spu.s_chan[0])); // channel + 1 infos (1 is security for fmod handling)
1424  spu.SB = calloc(MAXCHAN, sizeof(spu.SB[0]) * SB_SIZE);
1425
1426  spu.spuAddr = 0;
1427  spu.decode_pos = 0;
1428  spu.pSpuIrq = spu.spuMemC;
1429
1430  SetupStreams();                                       // prepare streaming
1431
1432  if (spu_config.iVolume == 0)
1433   spu_config.iVolume = 768; // 1024 is 1.0
1434
1435  init_spu_thread();
1436
1437  return 0;
1438 }
1439
1440 // SPUOPEN: called by main emu after init
1441 long CALLBACK SPUopen(void)
1442 {
1443  if (spu.bSPUIsOpen) return 0;                         // security for some stupid main emus
1444
1445  SetupSound();                                         // setup sound (before init!)
1446
1447  spu.bSPUIsOpen = 1;
1448
1449  return PSE_SPU_ERR_SUCCESS;
1450 }
1451
1452 // SPUCLOSE: called before shutdown
1453 long CALLBACK SPUclose(void)
1454 {
1455  if (!spu.bSPUIsOpen) return 0;                        // some security
1456
1457  spu.bSPUIsOpen = 0;                                   // no more open
1458
1459  out_current->finish();                                // no more sound handling
1460
1461  return 0;
1462 }
1463
1464 // SPUSHUTDOWN: called by main emu on final exit
1465 long CALLBACK SPUshutdown(void)
1466 {
1467  SPUclose();
1468
1469  exit_spu_thread();
1470
1471  free(spu.spuMemC);
1472  spu.spuMemC = NULL;
1473  free(spu.SB);
1474  spu.SB = NULL;
1475  free(spu.s_chan);
1476  spu.s_chan = NULL;
1477
1478  RemoveStreams();                                      // no more streaming
1479  spu.bSpuInit=0;
1480
1481  return 0;
1482 }
1483
1484 // SPUTEST: we don't test, we are always fine ;)
1485 long CALLBACK SPUtest(void)
1486 {
1487  return 0;
1488 }
1489
1490 // SPUCONFIGURE: call config dialog
1491 long CALLBACK SPUconfigure(void)
1492 {
1493 #ifdef _MACOSX
1494  DoConfiguration();
1495 #else
1496 // StartCfgTool("CFG");
1497 #endif
1498  return 0;
1499 }
1500
1501 // SPUABOUT: show about window
1502 void CALLBACK SPUabout(void)
1503 {
1504 #ifdef _MACOSX
1505  DoAbout();
1506 #else
1507 // StartCfgTool("ABOUT");
1508 #endif
1509 }
1510
1511 // SETUP CALLBACKS
1512 // this functions will be called once, 
1513 // passes a callback that should be called on SPU-IRQ/cdda volume change
1514 void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
1515 {
1516  spu.irqCallback = callback;
1517 }
1518
1519 void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
1520 {
1521  spu.cddavCallback = CDDAVcallback;
1522 }
1523
1524 void CALLBACK SPUregisterScheduleCb(void (CALLBACK *callback)(unsigned int))
1525 {
1526  spu.scheduleCallback = callback;
1527 }
1528
1529 // COMMON PLUGIN INFO FUNCS
1530 /*
1531 char * CALLBACK PSEgetLibName(void)
1532 {
1533  return _(libraryName);
1534 }
1535
1536 unsigned long CALLBACK PSEgetLibType(void)
1537 {
1538  return  PSE_LT_SPU;
1539 }
1540
1541 unsigned long CALLBACK PSEgetLibVersion(void)
1542 {
1543  return (1 << 16) | (6 << 8);
1544 }
1545
1546 char * SPUgetLibInfos(void)
1547 {
1548  return _(libraryInfo);
1549 }
1550 */
1551
1552 // debug
1553 void spu_get_debug_info(int *chans_out, int *run_chans, int *fmod_chans_out, int *noise_chans_out)
1554 {
1555  int ch = 0, fmod_chans = 0, noise_chans = 0, irq_chans = 0;
1556
1557  if (spu.s_chan == NULL)
1558   return;
1559
1560  for(;ch<MAXCHAN;ch++)
1561  {
1562   if (!(spu.dwChannelOn & (1<<ch)))
1563    continue;
1564   if (spu.s_chan[ch].bFMod == 2)
1565    fmod_chans |= 1 << ch;
1566   if (spu.s_chan[ch].bNoise)
1567    noise_chans |= 1 << ch;
1568   if((spu.spuCtrl&CTRL_IRQ) && spu.s_chan[ch].pCurr <= spu.pSpuIrq && spu.s_chan[ch].pLoop <= spu.pSpuIrq)
1569    irq_chans |= 1 << ch;
1570  }
1571
1572  *chans_out = spu.dwChannelOn;
1573  *run_chans = ~spu.dwChannelOn & ~spu.dwChannelDead & irq_chans;
1574  *fmod_chans_out = fmod_chans;
1575  *noise_chans_out = noise_chans;
1576 }
1577
1578 // vim:shiftwidth=1:expandtab