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 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version. See also the license.txt file for *
14  *   additional informations.                                              *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "stdafx.h"
19 
20 #define _IN_SPU
21 
22 #include "externals.h"
23 #include "cfg.h"
24 #include "dsoundoss.h"
25 #include "regs.h"
26 
27 #ifdef _WINDOWS
28 #include "debug.h"
29 #include "record.h"
30 #elif defined(_MACOSX)
31 #include "maccfg.h"
32 #endif
33 
34 #ifdef ENABLE_NLS
35 #include <libintl.h>
36 #include <locale.h>
37 #define _(x)  gettext(x)
38 #define N_(x) (x)
39 //If running under Mac OS X, use the Localizable.strings file instead.
40 #elif defined(_MACOSX)
41 #ifdef PCSXRCORE
42 __private_extern char* Pcsxr_locale_text(char* toloc);
43 #define _(String) Pcsxr_locale_text(String)
44 #define N_(String) String
45 #else
46 #ifndef PCSXRPLUG
47 #warning please define the plug being built to use Mac OS X localization!
48 #define _(msgid) msgid
49 #define N_(msgid) msgid
50 #else
51 //Kludge to get the preprocessor to accept PCSXRPLUG as a variable.
52 #define PLUGLOC_x(x,y) x ## y
53 #define PLUGLOC_y(x,y) PLUGLOC_x(x,y)
54 #define PLUGLOC PLUGLOC_y(PCSXRPLUG,_locale_text)
55 __private_extern char* PLUGLOC(char* toloc);
56 #define _(String) PLUGLOC(String)
57 #define N_(String) String
58 #endif
59 #endif
60 #else
61 #define _(x)  (x)
62 #define N_(x) (x)
63 #endif
64 
65 #if defined (_WINDOWS)
66 static char * libraryName     = N_("DirectSound Driver");
67 #elif defined (USEMACOSX)
68 static char * libraryName     = N_("Mac OS X Sound");
69 #elif defined (USEALSA)
70 static char * libraryName     = N_("ALSA Sound");
71 #elif defined (USEOSS)
72 static char * libraryName     = N_("OSS Sound");
73 #elif defined (USESDL)
74 static char * libraryName     = N_("SDL Sound");
75 #elif defined (USEOPENAL)
76 static char * libraryName     = N_("OpenAL Sound");
77 #elif defined (USEPULSEAUDIO)
78 static char * libraryName     = N_("PulseAudio Sound");
79 #else
80 static char * libraryName     = N_("NULL Sound");
81 #endif
82 
83 static char * libraryInfo     = N_("P.E.Op.S. Sound Driver V1.7\nCoded by Pete Bernert and the P.E.Op.S. team\n");
84 
85 // globals
86 
87 // psx buffer / addresses
88 
89 unsigned short  regArea[10000];
90 unsigned short  spuMem[256*1024];
91 unsigned char * spuMemC;
92 unsigned char * pSpuIrq=0;
93 unsigned char * pSpuBuffer;
94 unsigned char * pMixIrq=0;
95 
96 // user settings
97 
98 int             iVolume=3;
99 int             iXAPitch=1;
100 int             iUseTimer=2;
101 int             iSPUIRQWait=1;
102 int             iDebugMode=0;
103 int             iRecordMode=0;
104 int             iUseReverb=2;
105 int             iUseInterpolation=2;
106 int             iDisStereo=0;
107 int							iFreqResponse=0;
108 
109 // MAIN infos struct for each channel
110 
111 SPUCHAN         s_chan[MAXCHAN+1];                     // channel + 1 infos (1 is security for fmod handling)
112 REVERBInfo      rvb;
113 
114 unsigned long   dwNoiseVal=1;                          // global noise generator
115 unsigned long   dwNoiseCount;                          // global noise generator
116 unsigned long   dwNoiseClock;                          // global noise generator
117 int             iSpuAsyncWait=0;
118 
119 unsigned int    decoded_ptr = 0;
120 unsigned int	bIrqHit = 0;
121 
122 unsigned short  spuCtrl=0;                             // some vars to store psx reg infos
123 unsigned short  spuStat=0;
124 unsigned short  spuIrq=0;
125 unsigned long   spuAddr=0x200;                         // address into spu mem
126 int             bEndThread=0;                          // thread handlers
127 int             bThreadEnded=0;
128 int             bSpuInit=0;
129 int             bSPUIsOpen=0;
130 
131 #ifdef _WINDOWS
132 HWND    hWMain=0;                                      // window handle
133 HWND    hWDebug=0;
134 HWND    hWRecord=0;
135 static HANDLE   hMainThread;
136 #else
137 static pthread_t thread = (pthread_t)-1;               // thread id (linux)
138 #endif
139 
140 uint32_t dwNewChannel=0;                          // flags for faster testing, if new channel starts
141 
142 void (CALLBACK *irqCallback)(void)=0;                  // func of main emu, called on spu irq
143 void (CALLBACK *cddavCallback)(unsigned short,unsigned short)=0;
144 
145 // certain globals (were local before, but with the new timeproc I need em global)
146 
147 static const int f[5][2] = {   {    0,  0  },
148                         {   60,  0  },
149                         {  115, -52 },
150                         {   98, -55 },
151                         {  122, -60 } };
152 int SSumR[NSSIZE];
153 int SSumL[NSSIZE];
154 int iFMod[NSSIZE];
155 int iCycle = 0;
156 short * pS;
157 
158 int lastns=0;              // last ns pos
159 static int iSecureStart=0; // secure start counter
160 
161 ////////////////////////////////////////////////////////////////////////
162 // CODE AREA
163 ////////////////////////////////////////////////////////////////////////
164 
165 // dirty inline func includes
166 
167 #include "reverb.c"
168 #include "adsr.c"
169 
170 ////////////////////////////////////////////////////////////////////////
171 // helpers for simple interpolation
172 
173 //
174 // easy interpolation on upsampling, no special filter, just "Pete's common sense" tm
175 //
176 // instead of having n equal sample values in a row like:
177 //       ____
178 //           |____
179 //
180 // we compare the current delta change with the next delta change.
181 //
182 // if curr_delta is positive,
183 //
184 //  - and next delta is smaller (or changing direction):
185 //         \.
186 //          -__
187 //
188 //  - and next delta significant (at least twice) bigger:
189 //         --_
190 //            \.
191 //
192 //  - and next delta is nearly same:
193 //          \.
194 //           \.
195 //
196 //
197 // if curr_delta is negative,
198 //
199 //  - and next delta is smaller (or changing direction):
200 //          _--
201 //         /
202 //
203 //  - and next delta significant (at least twice) bigger:
204 //            /
205 //         __-
206 //
207 //  - and next delta is nearly same:
208 //           /
209 //          /
210 //
211 
212 
InterpolateUp(int ch)213 static INLINE void InterpolateUp(int ch)
214 {
215  if(s_chan[ch].SB[32]==1)                              // flag == 1? calc step and set flag... and don't change the value in this pass
216   {
217    const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29];  // curr delta to next val
218    const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30];  // and next delta to next-next val :)
219 
220    s_chan[ch].SB[32]=0;
221 
222    if(id1>0)                                           // curr delta positive
223     {
224      if(id2<id1)
225       {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
226      else
227      if(id2<(id1<<1))
228       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
229      else
230       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L;
231     }
232    else                                                // curr delta negative
233     {
234      if(id2>id1)
235       {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
236      else
237      if(id2>(id1<<1))
238       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
239      else
240       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L;
241     }
242   }
243  else
244  if(s_chan[ch].SB[32]==2)                              // flag 1: calc step and set flag... and don't change the value in this pass
245   {
246    s_chan[ch].SB[32]=0;
247 
248    s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L;
249    if(s_chan[ch].sinc<=0x8000)
250         s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1));
251    else s_chan[ch].SB[29]+=s_chan[ch].SB[28];
252   }
253  else                                                  // no flags? add bigger val (if possible), calc smaller step, set flag1
254   s_chan[ch].SB[29]+=s_chan[ch].SB[28];
255 }
256 
257 //
258 // even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
259 //
260 
InterpolateDown(int ch)261 static INLINE void InterpolateDown(int ch)
262 {
263  if(s_chan[ch].sinc>=0x20000L)                                 // we would skip at least one val?
264   {
265    s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight
266    if(s_chan[ch].sinc>=0x30000L)                               // we would skip even more vals?
267     s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight
268   }
269 }
270 
271 ////////////////////////////////////////////////////////////////////////
272 // helpers for gauss interpolation
273 
274 #define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos])
275 #define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3])
276 
277 #include "gauss_i.h"
278 
279 ////////////////////////////////////////////////////////////////////////
280 
281 #include "xa.c"
282 
283 ////////////////////////////////////////////////////////////////////////
284 // START SOUND... called by main thread to setup a new sound on a channel
285 ////////////////////////////////////////////////////////////////////////
286 
StartSound(int ch)287 static INLINE void StartSound(int ch)
288 {
289  StartADSR(ch);
290  StartREVERB(ch);
291 
292  // fussy timing issues - do in VoiceOn
293  //s_chan[ch].pCurr=s_chan[ch].pStart;                   // set sample start
294  //s_chan[ch].bStop=0;
295  //s_chan[ch].bOn=1;
296 
297  s_chan[ch].s_1=0;                                     // init mixing vars
298  s_chan[ch].s_2=0;
299  s_chan[ch].iSBPos=28;
300 
301  s_chan[ch].bNew=0;                                    // init channel flags
302 
303  s_chan[ch].SB[29]=0;                                  // init our interpolation helpers
304  s_chan[ch].SB[30]=0;
305 
306  if(iUseInterpolation>=2)                              // gauss interpolation?
307       {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;}  // -> start with more decoding
308  else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;}  // -> no/simple interpolation starts with one 44100 decoding
309 
310  dwNewChannel&=~(1<<ch);                               // clear new channel bit
311 }
312 
313 ////////////////////////////////////////////////////////////////////////
314 // ALL KIND OF HELPERS
315 ////////////////////////////////////////////////////////////////////////
316 
VoiceChangeFrequency(int ch)317 static INLINE void VoiceChangeFrequency(int ch)
318 {
319  s_chan[ch].iUsedFreq=s_chan[ch].iActFreq;             // -> take it and calc steps
320  s_chan[ch].sinc=s_chan[ch].iRawPitch<<4;
321  if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
322  if(iUseInterpolation==1) s_chan[ch].SB[32]=1;         // -> freq change in simle imterpolation mode: set flag
323 }
324 
325 ////////////////////////////////////////////////////////////////////////
326 
FModChangeFrequency(int ch,int ns)327 static INLINE void FModChangeFrequency(int ch,int ns)
328 {
329  int NP=s_chan[ch].iRawPitch;
330 
331  NP=((32768L+iFMod[ns])*NP)/32768L;
332 
333  if(NP>0x3fff) NP=0x3fff;
334  if(NP<0x1)    NP=0x1;
335 
336  NP=(44100L*NP)/(4096L);                               // calc frequency
337 
338  s_chan[ch].iActFreq=NP;
339  s_chan[ch].iUsedFreq=NP;
340  s_chan[ch].sinc=(((NP/10)<<16)/4410);
341  if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
342  if(iUseInterpolation==1)                              // freq change in simple interpolation mode
343  s_chan[ch].SB[32]=1;
344  iFMod[ns]=0;
345 }
346 
347 ////////////////////////////////////////////////////////////////////////
348 
349 /*
350 Noise Algorithm
351 - Dr.Hell (Xebra PS1 emu)
352 - 100% accurate (waveform + frequency)
353 - http://drhell.web.fc2.com
354 
355 
356 Level change cycle
357 Freq = 0x8000 >> (NoiseClock >> 2);
358 
359 Frequency of half cycle
360 Half = ((NoiseClock & 3) * 2) / (4 + (NoiseClock & 3));
361 - 0 = (0*2)/(4+0) = 0/4
362 - 1 = (1*2)/(4+1) = 2/5
363 - 2 = (2*2)/(4+2) = 4/6
364 - 3 = (3*2)/(4+3) = 6/7
365 
366 -------------------------------
367 
368 5*6*7 = 210
369 4 -  0*0 = 0
370 5 - 42*2 = 84
371 6 - 35*4 = 140
372 7 - 30*6 = 180
373 */
374 
375 // Noise Waveform - Dr. Hell (Xebra)
376 char NoiseWaveAdd [64] = {
377 	1, 0, 0, 1, 0, 1, 1, 0,
378 	1, 0, 0, 1, 0, 1, 1, 0,
379 	1, 0, 0, 1, 0, 1, 1, 0,
380 	1, 0, 0, 1, 0, 1, 1, 0,
381 	0, 1, 1, 0, 1, 0, 0, 1,
382 	0, 1, 1, 0, 1, 0, 0, 1,
383 	0, 1, 1, 0, 1, 0, 0, 1,
384 	0, 1, 1, 0, 1, 0, 0, 1
385 };
386 
387 unsigned short NoiseFreqAdd[5] = {
388 	0, 84, 140, 180, 210
389 };
390 
NoiseClock()391 static INLINE void NoiseClock()
392 {
393 	unsigned int level;
394 
395 	level = 0x8000 >> (dwNoiseClock >> 2);
396 	level <<= 16;
397 
398 	dwNoiseCount += 0x10000;
399 
400 	// Dr. Hell - fraction
401 	dwNoiseCount += NoiseFreqAdd[ dwNoiseClock & 3 ];
402 	if( (dwNoiseCount&0xffff) >= NoiseFreqAdd[4] ) {
403 		dwNoiseCount += 0x10000;
404 		dwNoiseCount -= NoiseFreqAdd[ dwNoiseClock & 3 ];
405 	}
406 
407 	if( dwNoiseCount >= level )
408 	{
409 		while( dwNoiseCount >= level )
410 			dwNoiseCount -= level;
411 
412 		// Dr. Hell - form
413 		dwNoiseVal = (dwNoiseVal<<1) | NoiseWaveAdd[ (dwNoiseVal>>10) & 63 ];
414 	}
415 }
416 
iGetNoiseVal(int ch)417 static INLINE int iGetNoiseVal(int ch)
418 {
419  int fa;
420 
421  fa = (short) dwNoiseVal;
422 
423  // no clip need
424  //if(fa>32767L)  fa=32767L;
425  //if(fa<-32767L) fa=-32767L;
426 
427  // don't upset VAG decoder
428  //if(iUseInterpolation<2)                               // no gauss/cubic interpolation?
429   //pChannel->SB[29] = fa;                               // -> store noise val in "current sample" slot
430 
431  // boost volume - no more!
432  //return fa * 3 / 2;
433  return fa;
434 }
435 
436 ////////////////////////////////////////////////////////////////////////
437 
StoreInterpolationVal(int ch,int fa)438 static INLINE void StoreInterpolationVal(int ch,int fa)
439 {
440 	/*
441 	// fmod channel = sound output
442  if(s_chan[ch].bFMod==2)                               // fmod freq channel
443   s_chan[ch].SB[29]=fa;
444  else
445  */
446   {
447    if((spuCtrl&0x4000)==0) fa=0;                       // muted?
448    else                                                // else adjust
449     {
450      if(fa>32767L)  fa=32767L;
451      if(fa<-32767L) fa=-32767L;
452     }
453 
454    if(iUseInterpolation>=2)                            // gauss/cubic interpolation
455     {
456      int gpos = s_chan[ch].SB[28];
457      gval0 = fa;
458      gpos = (gpos+1) & 3;
459      s_chan[ch].SB[28] = gpos;
460     }
461    else
462    if(iUseInterpolation==1)                            // simple interpolation
463     {
464      s_chan[ch].SB[28] = 0;
465      s_chan[ch].SB[29] = s_chan[ch].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'
466      s_chan[ch].SB[30] = s_chan[ch].SB[31];
467      s_chan[ch].SB[31] = fa;
468      s_chan[ch].SB[32] = 1;                            // -> flag: calc new interolation
469     }
470    else s_chan[ch].SB[29]=fa;                          // no interpolation
471   }
472 }
473 
474 ////////////////////////////////////////////////////////////////////////
475 
iGetInterpolationVal(int ch)476 static INLINE int iGetInterpolationVal(int ch)
477 {
478  int fa;
479 
480  // fmod channel = sound output
481  //if(s_chan[ch].bFMod==2) return s_chan[ch].SB[29];
482 
483  switch(iUseInterpolation)
484   {
485    //--------------------------------------------------//
486    case 3:                                             // cubic interpolation
487     {
488      long xd;int gpos;
489      xd = ((s_chan[ch].spos) >> 1)+1;
490      gpos = s_chan[ch].SB[28];
491 
492      fa  = gval(3) - 3*gval(2) + 3*gval(1) - gval0;
493      fa *= (xd - (2<<15)) / 6;
494      fa >>= 15;
495      fa += gval(2) - gval(1) - gval(1) + gval0;
496      fa *= (xd - (1<<15)) >> 1;
497      fa >>= 15;
498      fa += gval(1) - gval0;
499      fa *= xd;
500      fa >>= 15;
501      fa = fa + gval0;
502 
503     } break;
504    //--------------------------------------------------//
505    case 2:                                             // gauss interpolation
506     {
507      int vl, vr;int gpos;
508      vl = (s_chan[ch].spos >> 6) & ~3;
509      gpos = s_chan[ch].SB[28];
510      vr=(gauss[vl]*gval0)&~2047;
511      vr+=(gauss[vl+1]*gval(1))&~2047;
512      vr+=(gauss[vl+2]*gval(2))&~2047;
513      vr+=(gauss[vl+3]*gval(3))&~2047;
514      fa = vr>>11;
515     } break;
516    //--------------------------------------------------//
517    case 1:                                             // simple interpolation
518     {
519      if(s_chan[ch].sinc<0x10000L)                      // -> upsampling?
520           InterpolateUp(ch);                           // --> interpolate up
521      else InterpolateDown(ch);                         // --> else down
522      fa=s_chan[ch].SB[29];
523     } break;
524    //--------------------------------------------------//
525    default:                                            // no interpolation
526     {
527      fa=s_chan[ch].SB[29];
528     } break;
529    //--------------------------------------------------//
530   }
531 
532  return fa;
533 }
534 
535 ////////////////////////////////////////////////////////////////////////
536 // MAIN SPU FUNCTION
537 // here is the main job handler... thread, timer or direct func call
538 // basically the whole sound processing is done in this fat func!
539 ////////////////////////////////////////////////////////////////////////
540 
541 // 5 ms waiting phase, if buffer is full and no new sound has to get started
542 // .. can be made smaller (smallest val: 1 ms), but bigger waits give
543 // better performance
544 
545 #define PAUSE_W 1
546 #define PAUSE_L 1000
547 
548 ////////////////////////////////////////////////////////////////////////
549 
550 #ifdef _WINDOWS
MAINProc(UINT nTimerId,UINT msg,DWORD dwUser,DWORD dwParam1,DWORD dwParam2)551 static VOID CALLBACK MAINProc(UINT nTimerId, UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
552 #else
553 static void *MAINThread(void *arg)
554 #endif
555 {
556  int s_1,s_2,fa,ns;
557  int voldiv = iVolume;
558 
559  unsigned char * start;unsigned int nSample;
560  int ch,predict_nr,shift_factor,flags,d,s;
561  int bIRQReturn=0;
562  unsigned int decoded_voice=0;
563 
564  // mute output
565  if( voldiv == 5 ) voldiv = 0x7fffffff;
566 
567  while(!bEndThread)                                    // until we are shutting down
568   {
569    // ok, at the beginning we are looking if there is
570    // enuff free place in the dsound/oss buffer to
571    // fill in new data, or if there is a new channel to start.
572    // if not, we wait (thread) or return (timer/spuasync)
573    // until enuff free place is available/a new channel gets
574    // started
575 
576    if(dwNewChannel)                                    // new channel should start immedately?
577     {                                                  // (at least one bit 0 ... MAXCHANNEL is set?)
578      iSecureStart++;                                   // -> set iSecure
579      if(iSecureStart>1) iSecureStart=0;                //    (if it is set 5 times - that means on 5 tries a new samples has been started - in a row, we will reset it, to give the sound update a chance)
580     }
581    else iSecureStart=0;                                // 0: no new channel should start
582 
583    while(!iSecureStart && !bEndThread &&               // no new start? no thread end?
584          (SoundGetBytesBuffered()>TESTSIZE))           // and still enuff data in sound buffer?
585     {
586      iSecureStart=0;                                   // reset secure
587 
588 #ifdef _WINDOWS
589      if(iUseTimer)                                     // no-thread mode?
590       {
591        if(iUseTimer==1)                                // -> ok, timer mode 1: setup a oneshot timer of x ms to wait
592         timeSetEvent(PAUSE_W,1,MAINProc,0,TIME_ONESHOT);
593        return;                                         // -> and done this time (timer mode 1 or 2)
594       }
595                                                        // win thread mode:
596      Sleep(PAUSE_W);                                   // sleep for x ms (win)
597 #else
598      if(iUseTimer) return 0;                           // linux no-thread mode? bye
599      usleep(PAUSE_L);                                  // else sleep for x ms (linux)
600 #endif
601 
602      if(dwNewChannel) iSecureStart=1;                  // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop
603     }
604 
605    ns=0;
606 
607    //--------------------------------------------------// continue from irq handling in timer mode?
608 
609    if(lastns>0)                                        // will be 0 if no continue is pending
610     {
611      ns=lastns;                                        // -> setup all kind of vars to continue
612      lastns=0;
613     }
614 
615    //--------------------------------------------------//
616    //- main channel loop                              -//
617    //--------------------------------------------------//
618     {
619 		 decoded_voice = decoded_ptr;
620 
621 		 while(ns<NSSIZE)                                // loop until 1 ms of data is reached
622       {
623 				SSumL[ns]=0;
624 				SSumR[ns]=0;
625 
626 
627 				// decoded buffer values - dummy
628 				spuMem[ (0x000 + decoded_voice) / 2 ] = (short) 0;
629 				spuMem[ (0x400 + decoded_voice) / 2 ] = (short) 0;
630 				spuMem[ (0x800 + decoded_voice) / 2 ] = (short) 0;
631 				spuMem[ (0xc00 + decoded_voice) / 2 ] = (short) 0;
632 
633 
634 				NoiseClock();
635 
636 				for(ch=0;ch<MAXCHAN;ch++)                         // loop em all... we will collect 1 ms of sound of each playing channel
637         {
638 					if(s_chan[ch].bNew) {
639 #if 1
640 						StartSound(ch);																 // start new sound
641 						dwNewChannel&=~(1<<ch);                       // clear new channel bit
642 #else
643 						if( s_chan[ch].ADSRX.StartDelay == 0 ) {
644 							StartSound(ch);															// start new sound
645 							dwNewChannel&=~(1<<ch);                     // clear new channel bit
646 						} else {
647 							s_chan[ch].ADSRX.StartDelay--;
648 						}
649 #endif
650 					}
651 				 if(!s_chan[ch].bOn) continue;                   // channel not playing? next
652 
653 				 if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq)   // new psx frequency?
654 					VoiceChangeFrequency(ch);
655 
656 				 if(s_chan[ch].bFMod==1 && iFMod[ns])          // fmod freq channel
657           FModChangeFrequency(ch,ns);
658 
659          while(s_chan[ch].spos>=0x10000L)
660           {
661            if(s_chan[ch].iSBPos==28)                   // 28 reached?
662             {
663 						 // Xenogears - Anima Relic dungeon (exp gain)
664 						 if( s_chan[ch].bLoopJump == 1 )
665 							 s_chan[ch].pCurr = s_chan[ch].pLoop;
666 
667 						 s_chan[ch].bLoopJump = 0;
668 
669 
670 						 start=s_chan[ch].pCurr;                   // set up the current pos
671 
672              if (start == spuMemC)
673               s_chan[ch].bOn = 0;
674 
675              if (s_chan[ch].iSilent==1 )
676               {
677                // silence = let channel keep running (IRQs)
678 							 //s_chan[ch].bOn=0;                       // -> turn everything off
679 							 s_chan[ch].iSilent=2;
680 
681                s_chan[ch].ADSRX.lVolume=0;
682                s_chan[ch].ADSRX.EnvelopeVol=0;
683               }
684 
685              s_chan[ch].iSBPos=0;
686 
687              //////////////////////////////////////////// spu irq handler here? mmm... do it later
688 
689              s_1=s_chan[ch].s_1;
690              s_2=s_chan[ch].s_2;
691 
692              predict_nr=(int)*start;start++;
693              shift_factor=predict_nr&0xf;
694              predict_nr >>= 4;
695              flags=(int)*start;start++;
696 
697 						 // Silhouette Mirage - Serah fight
698 						 if( predict_nr > 4 ) predict_nr = 0;
699 
700              // -------------------------------------- //
701 
702              for (nSample=0;nSample<28;start++)
703               {
704                d=(int)*start;
705                s=((d&0xf)<<12);
706                if(s&0x8000) s|=0xffff0000;
707 
708                fa=(s >> shift_factor);
709                fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
710 
711 							 // snes brr clamps
712 							 fa = CLAMP16(fa);
713 
714                s_2=s_1;s_1=fa;
715                s=((d & 0xf0) << 8);
716 
717                s_chan[ch].SB[nSample++]=fa;
718 
719 
720                if(s&0x8000) s|=0xffff0000;
721                fa=(s>>shift_factor);
722                fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
723 
724 							 // snes brr clamps
725 							 fa = CLAMP16(fa);
726 
727                s_2=s_1;s_1=fa;
728 
729                s_chan[ch].SB[nSample++]=fa;
730               }
731 
732              //////////////////////////////////////////// irq check
733 
734 #if 1
735 						// Check channel/loop IRQs (e.g. Castlevania Chronicles) and at pos-8 for unknown reason
736 						if( Check_IRQ( (s_chan[ch].pCurr)-spuMemC, 0 ) ||
737 								Check_IRQ( (start-spuMemC)-0, 0 ) ||
738 								Check_IRQ( (start-spuMemC)-8, 0 ) )
739 						{
740 #else
741              if(irqCallback && (spuCtrl&0x40))         // some callback and irq active?
742               {
743                if((pSpuIrq >  start-16 &&              // irq address reached?
744                    pSpuIrq <= start) ||
745                   ((flags&1) &&                        // special: irq on looping addr, when stop/loop flag is set
746                    (pSpuIrq >  s_chan[ch].pLoop-16 &&
747                     pSpuIrq <= s_chan[ch].pLoop)))
748 #endif
749                {
750                  s_chan[ch].iIrqDone=1;                // -> debug flag
751                  //irqCallback();                      // -> call main emu (checked & called on Check_IRQ)
752 
753                  if(iSPUIRQWait)                       // -> option: wait after irq for main emu
754                   {
755                    iSpuAsyncWait=1;
756                    bIRQReturn=1;
757                   }
758                 }
759               }
760 
761              //////////////////////////////////////////// flag handler
762 
763 						/*
764 						SPU2-X:
765 						$4 = set loop to current block
766 						$2 = keep envelope on (no mute)
767 						$1 = jump to loop address
768 
769 						silence means no volume (ADSR keeps playing!!)
770 						*/
771 
772 						if(flags&4)
773 							s_chan[ch].pLoop=start-16;
774 
775 
776 						// Jungle Book - Rhythm 'n Groove - don't reset ignore status
777 						// - fixes gameplay speed (IRQ hits)
778 						//s_chan[ch].bIgnoreLoop = 0;
779 
780 
781 						if(flags&1)
782 						{
783 							// ...?
784 							//s_chan[ch].bIgnoreLoop = 0;
785 
786 							// Xenogears - 7 = play missing sounds
787 							// set jump flag
788 							s_chan[ch].bLoopJump = 1;
789 
790 
791 							// silence = keep playing..?
792 							if( (flags&2) == 0 ) {
793 								s_chan[ch].iSilent = 1;
794 
795 								// silence = don't start release phase
796 								//s_chan[ch].bStop = 1;
797 
798 								//start = (unsigned char *) -1;
799 							}
800 						}
801 
802 #if 0
803 						// crash check
804 						if( start == 0 )
805 							start = (unsigned char *) -1;
806 						if( start >= spuMemC + 0x80000 )
807 							start = spuMemC - 0x80000;
808 #endif
809 
810 
811 						// Silhouette Mirage - ending mini-game
812 
813 						// ??
814 						if( start - spuMemC >= 0x80000 ) {
815 							start -= 16;
816 
817 							s_chan[ch].iSilent = 1;
818 							s_chan[ch].bStop = 1;
819 						}
820 
821 
822              s_chan[ch].pCurr=start;                   // store values for next cycle
823              s_chan[ch].s_1=s_1;
824              s_chan[ch].s_2=s_2;
825             }
826 
827            fa=s_chan[ch].SB[s_chan[ch].iSBPos++];      // get sample data
828 
829            StoreInterpolationVal(ch,fa);               // store val for later interpolation
830 
831            s_chan[ch].spos -= 0x10000L;
832           }
833 
834          if(s_chan[ch].bNoise)
835               fa=iGetNoiseVal(ch);                     // get noise val
836          else fa=iGetInterpolationVal(ch);             // get sample val
837 
838 
839 				 // Voice 1/3 decoded buffer
840 				 if( ch == 0 ) {
841 					 spuMem[ (0x800 + decoded_voice) / 2 ] = (short) fa;
842 				 } else if( ch == 2 ) {
843 					 spuMem[ (0xc00 + decoded_voice) / 2 ] = (short) fa;
844 				 }
845 
846 
847          s_chan[ch].sval = (MixADSR(ch) * fa) / 1023;  // mix adsr
848 
849          if(s_chan[ch].bFMod==2)                       // fmod freq channel
850           iFMod[ns]=s_chan[ch].sval;                   // -> store 1T sample data, use that to do fmod on next channel
851 
852 				 // mix fmod channel into output
853 				 // - Xenogears save icon (high pitch)
854 				 {
855            //////////////////////////////////////////////
856            // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
857 
858            if(s_chan[ch].iMute)
859             s_chan[ch].sval=0;                         // debug mute
860            else
861             {
862              SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)/0x4000L;
863              SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)/0x4000L;
864             }
865 
866            //////////////////////////////////////////////
867            // now let us store sound data for reverb
868 
869            if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns);
870           }
871 
872 				 s_chan[ch].spos += s_chan[ch].sinc;
873         }
874 
875         ////////////////////////////////////////////////
876         // ok, go on until 1 ms data of this channel is collected
877 
878 				// decoded buffer - voice
879 				decoded_voice += 2;
880 				decoded_voice &= 0x3ff;
881 
882 
883 				// status flag
884 				if( decoded_voice >= 0x200 ) {
885 					spuStat |= STAT_DECODED;
886 				} else {
887 					spuStat &= ~STAT_DECODED;
888 				}
889 
890 
891 				// IRQ work
892 				{
893 					unsigned char *old_irq;
894 					unsigned int old_ptr;
895 
896 					old_irq = pSpuIrq;
897 					old_ptr = decoded_voice;
898 
899 #if 0
900 					// align to boundaries ($0, $200, $400, $600)
901 					pSpuIrq = ((pSpuIrq - spuMemC) & (~0x1ff)) + spuMemC;
902 					decoded_voice = decoded_voice & (~0x1ff);
903 #endif
904 
905 					// check all decoded buffer IRQs - timing issue
906 					Check_IRQ( decoded_voice + 0x000, 0 );
907 					Check_IRQ( decoded_voice + 0x400, 0 );
908 					Check_IRQ( decoded_voice + 0x800, 0 );
909 					Check_IRQ( decoded_voice + 0xc00, 0 );
910 
911 					pSpuIrq = old_irq;
912 					decoded_voice = old_ptr;
913 				}
914 
915          if(bIRQReturn)                            // special return for "spu irq - wait for cpu action"
916           {
917            bIRQReturn=0;
918            if(iUseTimer!=2)
919             {
920              DWORD dwWatchTime=timeGetTime_spu()+2500;
921 
922              while(iSpuAsyncWait && !bEndThread &&
923                    timeGetTime_spu()<dwWatchTime)
924 #ifdef _WINDOWS
925                  Sleep(1);
926 #else
927                  usleep(1000L);
928 #endif
929             }
930            else
931             {
932              lastns=ns+1;
933 
934 #ifdef _WINDOWS
935              return;
936 #else
937              return 0;
938 #endif
939            }
940          }
941 
942         ns++;
943       } // end ns
944     }
945 
946 
947   //---------------------------------------------------//
948   //- here we have another 1 ms of sound data
949   //---------------------------------------------------//
950   // mix XA infos (if any)
951 
952   MixXA();
953 
954 
955 	// now safe to update decoded buffer ptr
956 	decoded_ptr += ns * 2;
957 	decoded_ptr &= 0x3ff;
958 
959 
960   ///////////////////////////////////////////////////////
961   // mix all channels (including reverb) into one buffer
962 
963   if(iDisStereo)                                       // no stereo?
964    {
965     int dl, dr;
966     for (ns = 0; ns < NSSIZE; ns++)
967      {
968       SSumL[ns] += MixREVERBLeft(ns);
969 
970       dl = SSumL[ns] / voldiv; SSumL[ns] = 0;
971       if (dl < -32767) dl = -32767; if (dl > 32767) dl = 32767;
972 
973       SSumR[ns] += MixREVERBRight();
974 
975       dr = SSumR[ns] / voldiv; SSumR[ns] = 0;
976       if (dr < -32767) dr = -32767; if (dr > 32767) dr = 32767;
977       *pS++ = (dl + dr) / 2;
978      }
979    }
980   else                                                 // stereo:
981   for (ns = 0; ns < NSSIZE; ns++)
982    {
983 		static double _interpolation_coefficient = 3.759285613;
984 
985 		if(iFreqResponse) {
986 			int sl,sr;
987 			double ldiff, rdiff, avg, tmp;
988 
989 			SSumL[ns]+=MixREVERBLeft(ns);
990 			SSumR[ns]+=MixREVERBRight();
991 
992 			sl = SSumL[ns]; SSumL[ns]=0;
993 			sr = SSumR[ns]; SSumR[ns]=0;
994 
995 
996 			/*
997 			Frequency Response
998 			- William Pitcock (nenolod) (UPSE PSF player)
999 			- accurate (!)
1000 			- http://nenolod.net
1001 			*/
1002 
1003 			avg = ((sl + sr) / 2);
1004 			ldiff = sl - avg;
1005 			rdiff = sr - avg;
1006 
1007 			tmp = avg + ldiff * _interpolation_coefficient;
1008 			if (tmp < -32768)
1009 				tmp = -32768;
1010 			if (tmp > 32767)
1011 				tmp = 32767;
1012 			sl = (int)tmp;
1013 
1014 			tmp = avg + rdiff * _interpolation_coefficient;
1015 			if (tmp < -32768)
1016 				tmp = -32768;
1017 			if (tmp > 32767)
1018 				tmp = 32767;
1019 			sr = (int)tmp;
1020 
1021 
1022 			*pS++=sl/voldiv;
1023 			*pS++=sr/voldiv;
1024 		} else {
1025 			SSumL[ns]+=MixREVERBLeft(ns);
1026 
1027 			d=SSumL[ns]/voldiv;SSumL[ns]=0;
1028 			if(d<-32767) d=-32767;if(d>32767) d=32767;
1029 			*pS++=d;
1030 
1031 			SSumR[ns]+=MixREVERBRight();
1032 
1033 			d=SSumR[ns]/voldiv;SSumR[ns]=0;
1034 			if(d<-32767) d=-32767;if(d>32767) d=32767;
1035 			*pS++=d;
1036 		}
1037    }
1038 
1039   //////////////////////////////////////////////////////
1040   // special irq handling in the decode buffers (0x0000-0x1000)
1041   // we know:
1042   // the decode buffers are located in spu memory in the following way:
1043   // 0x0000-0x03ff  CD audio left
1044   // 0x0400-0x07ff  CD audio right
1045   // 0x0800-0x0bff  Voice 1
1046   // 0x0c00-0x0fff  Voice 3
1047   // and decoded data is 16 bit for one sample
1048   // we assume:
1049   // even if voices 1/3 are off or no cd audio is playing, the internal
1050   // play positions will move on and wrap after 0x400 bytes.
1051   // Therefore: we just need a pointer from spumem+0 to spumem+3ff, and
1052   // increase this pointer on each sample by 2 bytes. If this pointer
1053   // (or 0x400 offsets of this pointer) hits the spuirq address, we generate
1054   // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here
1055   // in some of Peops timer modes. So: we ignore this option here (for now).
1056 
1057 #if 0
1058   if(pMixIrq && irqCallback)
1059    {
1060     for(ns=0;ns<NSSIZE;ns++)
1061      {
1062       if((spuCtrl&0x40) && pSpuIrq && pSpuIrq<spuMemC+0x1000)
1063        {
1064         for(ch=0;ch<4;ch++)
1065          {
1066           if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
1067            {irqCallback();s_chan[ch].iIrqDone=1;}
1068          }
1069        }
1070       pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
1071      }
1072    }
1073 #endif
1074 
1075   InitREVERB();
1076 
1077   //////////////////////////////////////////////////////
1078   // feed the sound
1079   // latency = 25 ms (less pops, crackles, smoother)
1080 
1081 	//if(iCycle++>=20)
1082 	iCycle += APU_CYCLES_UPDATE;
1083 	if(iCycle > 44000/1000*LATENCY + 100*LATENCY/1000)
1084    {
1085     SoundFeedStreamData((unsigned char *)pSpuBuffer,
1086                         ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer));
1087     pS = (short *)pSpuBuffer;
1088     iCycle = 0;
1089    }
1090 
1091 
1092 	if( iUseTimer == 2 )
1093 		break;
1094  }
1095 
1096  // end of big main loop...
1097 
1098  bThreadEnded = 1;
1099 
1100 #ifndef _WINDOWS
1101  return 0;
1102 #endif
1103 }
1104 
1105 ////////////////////////////////////////////////////////////////////////
1106 // WINDOWS THREAD... simply calls the timer func and stays forever :)
1107 ////////////////////////////////////////////////////////////////////////
1108 
1109 #ifdef _WINDOWS
1110 
1111 DWORD WINAPI MAINThreadEx(LPVOID lpParameter)
1112 {
1113  MAINProc(0,0,0,0,0);
1114  return 0;
1115 }
1116 
1117 #endif
1118 
1119 // SPU ASYNC... even newer epsxe func
1120 //  1 time every 'cycle' cycles... harhar
1121 
1122 long cpu_cycles;
1123 void CALLBACK SPUasync(unsigned long cycle)
1124 {
1125 	cpu_cycles += cycle;
1126 
1127  if(iSpuAsyncWait)
1128   {
1129    iSpuAsyncWait++;
1130    if(iSpuAsyncWait<=64) return;
1131    iSpuAsyncWait=0;
1132   }
1133 
1134 #ifdef _WINDOWS
1135  if(iDebugMode==2)
1136   {
1137    if(IsWindow(hWDebug)) DestroyWindow(hWDebug);
1138    hWDebug=0;iDebugMode=0;
1139   }
1140  if(iRecordMode==2)
1141   {
1142    if(IsWindow(hWRecord)) DestroyWindow(hWRecord);
1143    hWRecord=0;iRecordMode=0;
1144   }
1145 #endif
1146 
1147  if(iUseTimer==2)                                      // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode)
1148   {
1149    if(!bSpuInit) return;                               // -> no init, no call
1150 
1151 	 // note: usable precision difference (not using interval_time)
1152 	 while( cpu_cycles >= CPU_CLOCK / 44100 * NSSIZE )
1153 	 {
1154 	#ifdef _WINDOWS
1155 		 MAINProc(0,0,0,0,0);                                // -> experimental win mode... not really tested... don't like the drawbacks
1156 	#else
1157 		 MAINThread(0);                                      // -> linux high-compat mode
1158 	#endif
1159 
1160 	  if (iSpuAsyncWait)
1161 	    break;
1162 	  cpu_cycles -= CPU_CLOCK / 44100 * NSSIZE;
1163 	 }
1164   }
1165 }
1166 
1167 // SPU UPDATE... new epsxe func
1168 //  1 time every 32 hsync lines
1169 //  (312/32)x50 in pal
1170 //  (262/32)x60 in ntsc
1171 
1172 // since epsxe 1.5.2 (linux) uses SPUupdate, not SPUasync, I will
1173 // leave that func in the linux port, until epsxe linux is using
1174 // the async function as well
1175 
1176 void CALLBACK SPUupdate(void)
1177 {
1178  SPUasync(0);
1179 }
1180 
1181 // XA AUDIO
1182 
1183 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap)
1184 {
1185  if(!xap)       return;
1186  if(!xap->freq) return;                                // no xa freq ? bye
1187 
1188  FeedXA(xap);                                          // call main XA feeder
1189 }
1190 
1191 // CDDA AUDIO
1192 void CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
1193 {
1194  if (!pcm)      return;
1195  if (nbytes<=0) return;
1196 
1197  FeedCDDA((unsigned char *)pcm, nbytes);
1198 }
1199 
1200 // SETUPTIMER: init of certain buffers and threads/timers
1201 void SetupTimer(void)
1202 {
1203  memset(SSumR,0,NSSIZE*sizeof(int));                   // init some mixing buffers
1204  memset(SSumL,0,NSSIZE*sizeof(int));
1205  memset(iFMod,0,NSSIZE*sizeof(int));
1206  pS=(short *)pSpuBuffer;                               // setup soundbuffer pointer
1207 
1208  bEndThread=0;                                         // init thread vars
1209  bThreadEnded=0;
1210  bSpuInit=1;                                           // flag: we are inited
1211 
1212 #ifdef _WINDOWS
1213 
1214  if(iUseTimer==1)                                      // windows: use timer
1215   {
1216    timeBeginPeriod(1);
1217    timeSetEvent(1,1,MAINProc,0,TIME_ONESHOT);
1218   }
1219  else
1220  if(iUseTimer==0)                                      // windows: use thread
1221   {
1222    //_beginthread(MAINThread,0,NULL);
1223    DWORD dw;
1224    hMainThread=CreateThread(NULL,0,MAINThreadEx,0,0,&dw);
1225    SetThreadPriority(hMainThread,
1226                      //THREAD_PRIORITY_TIME_CRITICAL);
1227                      THREAD_PRIORITY_HIGHEST);
1228   }
1229 
1230 #else
1231 
1232  if(!iUseTimer)                                        // linux: use thread
1233   {
1234    pthread_create(&thread, NULL, MAINThread, NULL);
1235   }
1236 
1237 #endif
1238 }
1239 
1240 // REMOVETIMER: kill threads/timers
1241 void RemoveTimer(void)
1242 {
1243  bEndThread=1;                                         // raise flag to end thread
1244 
1245 #ifdef _WINDOWS
1246 
1247  if(iUseTimer!=2)                                      // windows thread?
1248   {
1249    while(!bThreadEnded) {Sleep(5L);}                   // -> wait till thread has ended
1250    Sleep(5L);
1251   }
1252  if(iUseTimer==1) timeEndPeriod(1);                    // windows timer? stop it
1253 
1254 #else
1255  if(!iUseTimer)                                        // linux tread?
1256   {
1257    int i=0;
1258    while(!bThreadEnded && i<2000) {usleep(1000L);i++;} // -> wait until thread has ended
1259    if(thread!=(pthread_t)-1) {pthread_cancel(thread);thread=(pthread_t)-1;}  // -> cancel thread anyway
1260   }
1261 
1262 #endif
1263 
1264  bThreadEnded=0;                                       // no more spu is running
1265  bSpuInit=0;
1266 }
1267 
1268 // SETUPSTREAMS: init most of the spu buffers
1269 void SetupStreams(void)
1270 {
1271  int i;
1272 
1273  pSpuBuffer=(unsigned char *)malloc(32768);            // alloc mixing buffer
1274 
1275  if(iUseReverb==1) i=88200*2;
1276  else              i=NSSIZE*2;
1277 
1278  sRVBStart = (int *)malloc(i*4);                       // alloc reverb buffer
1279  memset(sRVBStart,0,i*4);
1280  sRVBEnd  = sRVBStart + i;
1281  sRVBPlay = sRVBStart;
1282 
1283  XAStart =                                             // alloc xa buffer
1284   (uint32_t *)malloc(44100 * sizeof(uint32_t));
1285  XAEnd   = XAStart + 44100;
1286  XAPlay  = XAStart;
1287  XAFeed  = XAStart;
1288 
1289  CDDAStart =                                           // alloc cdda buffer
1290   (uint32_t *)malloc(44100 * sizeof(uint32_t));
1291  CDDAEnd   = CDDAStart + 44100;
1292  CDDAPlay  = CDDAStart;
1293  CDDAFeed  = CDDAStart;
1294 
1295  for(i=0;i<MAXCHAN;i++)                                // loop sound channels
1296   {
1297 // we don't use mutex sync... not needed, would only
1298 // slow us down:
1299 //   s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
1300    s_chan[i].ADSRX.SustainLevel = 1024;                // -> init sustain
1301    s_chan[i].iMute=0;
1302    s_chan[i].iIrqDone=0;
1303    s_chan[i].pLoop=spuMemC;
1304    s_chan[i].pStart=spuMemC;
1305    s_chan[i].pCurr=spuMemC;
1306   }
1307 
1308   pMixIrq=spuMemC;                                     // enable decoded buffer irqs by setting the address
1309 }
1310 
1311 // REMOVESTREAMS: free most buffer
1312 void RemoveStreams(void)
1313 {
1314  free(pSpuBuffer);                                     // free mixing buffer
1315  pSpuBuffer = NULL;
1316  free(sRVBStart);                                      // free reverb buffer
1317  sRVBStart = NULL;
1318  free(XAStart);                                        // free XA buffer
1319  XAStart = NULL;
1320  free(CDDAStart);                                      // free CDDA buffer
1321  CDDAStart = NULL;
1322 }
1323 
1324 // INIT/EXIT STUFF
1325 
1326 // SPUINIT: this func will be called first by the main emu
1327 long CALLBACK SPUinit(void)
1328 {
1329  spuMemC = (unsigned char *)spuMem;                    // just small setup
1330  memset((void *)&rvb, 0, sizeof(REVERBInfo));
1331  InitADSR();
1332 
1333  iVolume = 3;
1334  iReverbOff = -1;
1335  spuIrq = 0;
1336  spuAddr = 0x200;
1337  bEndThread = 0;
1338  bThreadEnded = 0;
1339  spuMemC = (unsigned char *)spuMem;
1340  pMixIrq = 0;
1341  memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
1342  pSpuIrq = 0;
1343  iSPUIRQWait = 1;
1344  lastns = 0;
1345 
1346  ReadConfig();                                         // read user stuff
1347  SetupStreams();                                       // prepare streaming
1348 
1349  return 0;
1350 }
1351 
1352 // SPUOPEN: called by main emu after init
1353 #ifdef _WINDOWS
1354 long CALLBACK SPUopen(HWND hW)
1355 #else
1356 long SPUopen(void)
1357 #endif
1358 {
1359  if (bSPUIsOpen) return 0;                             // security for some stupid main emus
1360 
1361 #ifdef _WINDOWS
1362  LastWrite=0xffffffff;LastPlay=0;                      // init some play vars
1363  if(!IsWindow(hW)) hW=GetActiveWindow();
1364  hWMain = hW;                                          // store hwnd
1365 #endif
1366 
1367  SetupSound();                                         // setup sound (before init!)
1368  SetupTimer();                                         // timer for feeding data
1369 
1370  bSPUIsOpen = 1;
1371 
1372 #ifdef _WINDOWS
1373  if(iDebugMode)                                        // windows debug dialog
1374   {
1375    hWDebug=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DEBUG),
1376                         NULL,(DLGPROC)DebugDlgProc);
1377    SetWindowPos(hWDebug,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
1378    UpdateWindow(hWDebug);
1379    SetFocus(hWMain);
1380   }
1381 
1382  if(iRecordMode)                                       // windows recording dialog
1383   {
1384    hWRecord=CreateDialog(hInst,MAKEINTRESOURCE(IDD_RECORD),
1385                         NULL,(DLGPROC)RecordDlgProc);
1386    SetWindowPos(hWRecord,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW|SWP_NOACTIVATE);
1387    UpdateWindow(hWRecord);
1388    SetFocus(hWMain);
1389   }
1390 #endif
1391 
1392  return PSE_SPU_ERR_SUCCESS;
1393 }
1394 
1395 // SPUCLOSE: called before shutdown
1396 long CALLBACK SPUclose(void)
1397 {
1398  if (!bSPUIsOpen) return 0;                            // some security
1399 
1400  bSPUIsOpen = 0;                                       // no more open
1401 
1402 #ifdef _WINDOWS
1403  if(IsWindow(hWDebug)) DestroyWindow(hWDebug);
1404  hWDebug=0;
1405  if(IsWindow(hWRecord)) DestroyWindow(hWRecord);
1406  hWRecord=0;
1407 #endif
1408 
1409  RemoveTimer();                                        // no more feeding
1410  RemoveSound();                                        // no more sound handling
1411 
1412  return 0;
1413 }
1414 
1415 // SPUSHUTDOWN: called by main emu on final exit
1416 long CALLBACK SPUshutdown(void)
1417 {
1418  SPUclose();
1419  RemoveStreams();                                      // no more streaming
1420 
1421  return 0;
1422 }
1423 
1424 // SPUTEST: we don't test, we are always fine ;)
1425 long CALLBACK SPUtest(void)
1426 {
1427  return 0;
1428 }
1429 
1430 // SPUCONFIGURE: call config dialog
1431 long CALLBACK SPUconfigure(void)
1432 {
1433 #if defined (_WINDOWS)
1434  DialogBox(hInst,MAKEINTRESOURCE(IDD_CFGDLG),
1435            GetActiveWindow(),(DLGPROC)DSoundDlgProc);
1436 #elif defined (_MACOSX)
1437  return DoConfiguration();
1438 #else
1439  StartCfgTool("configure");
1440 #endif
1441 
1442  return 0;
1443 }
1444 
1445 // SPUABOUT: show about window
1446 void CALLBACK SPUabout(void)
1447 {
1448 #if defined (_WINDOWS)
1449  DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUT),
1450            GetActiveWindow(),(DLGPROC)AboutDlgProc);
1451 #elif defined (_MACOSX)
1452  DoAbout();
1453 #else
1454  StartCfgTool("about");
1455 #endif
1456 }
1457 
1458 // SETUP CALLBACKS
1459 // this functions will be called once,
1460 // passes a callback that should be called on SPU-IRQ/cdda volume change
1461 void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
1462 {
1463  irqCallback = callback;
1464 }
1465 
1466 void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
1467 {
1468  cddavCallback = CDDAVcallback;
1469 }
1470 
1471 // COMMON PLUGIN INFO FUNCS
1472 char * CALLBACK PSEgetLibName(void)
1473 {
1474  return _(libraryName);
1475 }
1476 
1477 unsigned long CALLBACK PSEgetLibType(void)
1478 {
1479  return  PSE_LT_SPU;
1480 }
1481 
1482 unsigned long CALLBACK PSEgetLibVersion(void)
1483 {
1484  return (1 << 16) | (1 << 8);
1485 }
1486 
1487 char * SPUgetLibInfos(void)
1488 {
1489  return _(libraryInfo);
1490 }
1491