084fccf0ebefaff21a8a1ec9586c709d00258e14
[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 /***************************************************************************
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 ENABLE_NLS
28 #include <libintl.h>
29 #include <locale.h>
30 #define _(x)  gettext(x)
31 #define N_(x) (x)
32 #else
33 #define _(x)  (x)
34 #define N_(x) (x)
35 #endif
36
37 #if defined (USEMACOSX)
38 static char * libraryName     = N_("Mac OS X Sound");
39 #elif defined (USEALSA)
40 static char * libraryName     = N_("ALSA Sound");
41 #elif defined (USEOSS)
42 static char * libraryName     = N_("OSS Sound");
43 #elif defined (USESDL)
44 static char * libraryName     = N_("SDL Sound");
45 #elif defined (USEPULSEAUDIO)
46 static char * libraryName     = N_("PulseAudio Sound");
47 #else
48 static char * libraryName     = N_("NULL Sound");
49 #endif
50
51 static char * libraryInfo     = N_("P.E.Op.S. Sound Driver V1.7\nCoded by Pete Bernert and the P.E.Op.S. team\n");
52
53 // globals
54
55 // psx buffer / addresses
56
57 unsigned short  regArea[10000];
58 unsigned short  spuMem[256*1024];
59 unsigned char * spuMemC;
60 unsigned char * pSpuIrq=0;
61 unsigned char * pSpuBuffer;
62 unsigned char * pMixIrq=0;
63
64 // user settings
65
66 int             iVolume=3;
67 int             iXAPitch=1;
68 int             iUseTimer=2;
69 int             iSPUIRQWait=1;
70 int             iDebugMode=0;
71 int             iRecordMode=0;
72 int             iUseReverb=2;
73 int             iUseInterpolation=2;
74 int             iDisStereo=0;
75
76 // MAIN infos struct for each channel
77
78 SPUCHAN         s_chan[MAXCHAN+1];                     // channel + 1 infos (1 is security for fmod handling)
79 REVERBInfo      rvb;
80
81 unsigned long   dwNoiseVal=1;                          // global noise generator
82 int             iSpuAsyncWait=0;
83
84 unsigned short  spuCtrl=0;                             // some vars to store psx reg infos
85 unsigned short  spuStat=0;
86 unsigned short  spuIrq=0;
87 unsigned long   spuAddr=0xffffffff;                    // address into spu mem
88 int             bEndThread=0;                          // thread handlers
89 int             bThreadEnded=0;
90 int             bSpuInit=0;
91 int             bSPUIsOpen=0;
92
93 static pthread_t thread = (pthread_t)-1;               // thread id (linux)
94
95 unsigned long dwNewChannel=0;                          // flags for faster testing, if new channel starts
96
97 void (CALLBACK *irqCallback)(void)=0;                  // func of main emu, called on spu irq
98 void (CALLBACK *cddavCallback)(unsigned short,unsigned short)=0;
99
100 // certain globals (were local before, but with the new timeproc I need em global)
101
102 static const int f[5][2] = {   {    0,  0  },
103                         {   60,  0  },
104                         {  115, -52 },
105                         {   98, -55 },
106                         {  122, -60 } };
107 int SSumR[NSSIZE];
108 int SSumL[NSSIZE];
109 int iFMod[NSSIZE];
110 int iCycle = 0;
111 short * pS;
112
113 int lastch=-1;             // last channel processed on spu irq in timer mode
114 static int lastns=0;       // last ns pos
115 static int iSecureStart=0; // secure start counter
116
117 ////////////////////////////////////////////////////////////////////////
118 // CODE AREA
119 ////////////////////////////////////////////////////////////////////////
120
121 // dirty inline func includes
122
123 #include "reverb.c"
124 #include "adsr.c"
125
126 ////////////////////////////////////////////////////////////////////////
127 // helpers for simple interpolation
128
129 //
130 // easy interpolation on upsampling, no special filter, just "Pete's common sense" tm
131 //
132 // instead of having n equal sample values in a row like:
133 //       ____
134 //           |____
135 //
136 // we compare the current delta change with the next delta change.
137 //
138 // if curr_delta is positive,
139 //
140 //  - and next delta is smaller (or changing direction):
141 //         \.
142 //          -__
143 //
144 //  - and next delta significant (at least twice) bigger:
145 //         --_
146 //            \.
147 //
148 //  - and next delta is nearly same:
149 //          \.
150 //           \.
151 //
152 //
153 // if curr_delta is negative,
154 //
155 //  - and next delta is smaller (or changing direction):
156 //          _--
157 //         /
158 //
159 //  - and next delta significant (at least twice) bigger:
160 //            /
161 //         __- 
162 //
163 //  - and next delta is nearly same:
164 //           /
165 //          /
166 //
167
168
169 INLINE void InterpolateUp(int ch)
170 {
171  if(s_chan[ch].SB[32]==1)                              // flag == 1? calc step and set flag... and don't change the value in this pass
172   {
173    const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29];  // curr delta to next val
174    const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30];  // and next delta to next-next val :)
175
176    s_chan[ch].SB[32]=0;
177
178    if(id1>0)                                           // curr delta positive
179     {
180      if(id2<id1)
181       {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
182      else
183      if(id2<(id1<<1))
184       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
185      else
186       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
187     }
188    else                                                // curr delta negative
189     {
190      if(id2>id1)
191       {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
192      else
193      if(id2>(id1<<1))
194       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
195      else
196       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
197     }
198   }
199  else
200  if(s_chan[ch].SB[32]==2)                              // flag 1: calc step and set flag... and don't change the value in this pass
201   {
202    s_chan[ch].SB[32]=0;
203
204    s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L;
205    if(s_chan[ch].sinc<=0x8000)
206         s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1));
207    else s_chan[ch].SB[29]+=s_chan[ch].SB[28];
208   }
209  else                                                  // no flags? add bigger val (if possible), calc smaller step, set flag1
210   s_chan[ch].SB[29]+=s_chan[ch].SB[28];
211 }
212
213 //
214 // even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
215 //
216
217 INLINE void InterpolateDown(int ch)
218 {
219  if(s_chan[ch].sinc>=0x20000L)                                 // we would skip at least one val?
220   {
221    s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight
222    if(s_chan[ch].sinc>=0x30000L)                               // we would skip even more vals?
223     s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight
224   }
225 }
226
227 ////////////////////////////////////////////////////////////////////////
228 // helpers for gauss interpolation
229
230 #define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos])
231 #define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3])
232
233 #include "gauss_i.h"
234
235 ////////////////////////////////////////////////////////////////////////
236
237 #include "xa.c"
238
239 ////////////////////////////////////////////////////////////////////////
240 // START SOUND... called by main thread to setup a new sound on a channel
241 ////////////////////////////////////////////////////////////////////////
242
243 INLINE void StartSound(int ch)
244 {
245  StartADSR(ch);
246  StartREVERB(ch);
247
248  // fussy timing issues - do in VoiceOn
249  //s_chan[ch].pCurr=s_chan[ch].pStart;                   // set sample start
250  //s_chan[ch].bStop=0;
251  //s_chan[ch].bOn=1;
252
253  s_chan[ch].s_1=0;                                     // init mixing vars
254  s_chan[ch].s_2=0;
255  s_chan[ch].iSBPos=28;
256
257  s_chan[ch].bNew=0;                                    // init channel flags
258
259  s_chan[ch].SB[29]=0;                                  // init our interpolation helpers
260  s_chan[ch].SB[30]=0;
261
262  if(iUseInterpolation>=2)                              // gauss interpolation?
263       {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;}  // -> start with more decoding
264  else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;}  // -> no/simple interpolation starts with one 44100 decoding
265
266  dwNewChannel&=~(1<<ch);                               // clear new channel bit
267 }
268
269 ////////////////////////////////////////////////////////////////////////
270 // ALL KIND OF HELPERS
271 ////////////////////////////////////////////////////////////////////////
272
273 INLINE void VoiceChangeFrequency(int ch)
274 {
275  s_chan[ch].iUsedFreq=s_chan[ch].iActFreq;             // -> take it and calc steps
276  s_chan[ch].sinc=s_chan[ch].iRawPitch<<4;
277  if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
278  if(iUseInterpolation==1) s_chan[ch].SB[32]=1;         // -> freq change in simle imterpolation mode: set flag
279 }
280
281 ////////////////////////////////////////////////////////////////////////
282
283 INLINE void FModChangeFrequency(int ch,int ns)
284 {
285  int NP=s_chan[ch].iRawPitch;
286
287  NP=((32768L+iFMod[ns])*NP)/32768L;
288
289  if(NP>0x3fff) NP=0x3fff;
290  if(NP<0x1)    NP=0x1;
291
292  NP=(44100L*NP)/(4096L);                               // calc frequency
293
294  s_chan[ch].iActFreq=NP;
295  s_chan[ch].iUsedFreq=NP;
296  s_chan[ch].sinc=(((NP/10)<<16)/4410);
297  if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
298  if(iUseInterpolation==1)                              // freq change in simple interpolation mode
299  s_chan[ch].SB[32]=1;
300  iFMod[ns]=0;
301 }                    
302
303 ////////////////////////////////////////////////////////////////////////
304
305 // noise handler... just produces some noise data
306 // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used...
307 // and sometimes the noise will be used as fmod modulation... pfff
308
309 INLINE int iGetNoiseVal(int ch)
310 {
311  int fa;
312
313  if((dwNoiseVal<<=1)&0x80000000L)
314   {
315    dwNoiseVal^=0x0040001L;
316    fa=((dwNoiseVal>>2)&0x7fff);
317    fa=-fa;
318   }
319  else fa=(dwNoiseVal>>2)&0x7fff;
320
321  // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val
322  fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1));
323  if(fa>32767L)  fa=32767L;
324  if(fa<-32767L) fa=-32767L;              
325  s_chan[ch].iOldNoise=fa;
326
327  if(iUseInterpolation<2)                               // no gauss/cubic interpolation?
328  s_chan[ch].SB[29] = fa;                               // -> store noise val in "current sample" slot
329  return fa;
330 }                                 
331
332 ////////////////////////////////////////////////////////////////////////
333
334 INLINE void StoreInterpolationVal(int ch,int fa)
335 {
336  if(s_chan[ch].bFMod==2)                               // fmod freq channel
337   s_chan[ch].SB[29]=fa;
338  else
339   {
340    if((spuCtrl&0x4000)==0) fa=0;                       // muted?
341    else                                                // else adjust
342     {
343      if(fa>32767L)  fa=32767L;
344      if(fa<-32767L) fa=-32767L;              
345     }
346
347    if(iUseInterpolation>=2)                            // gauss/cubic interpolation
348     {     
349      int gpos = s_chan[ch].SB[28];
350      gval0 = fa;          
351      gpos = (gpos+1) & 3;
352      s_chan[ch].SB[28] = gpos;
353     }
354    else
355    if(iUseInterpolation==1)                            // simple interpolation
356     {
357      s_chan[ch].SB[28] = 0;                    
358      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'
359      s_chan[ch].SB[30] = s_chan[ch].SB[31];
360      s_chan[ch].SB[31] = fa;
361      s_chan[ch].SB[32] = 1;                            // -> flag: calc new interolation
362     }
363    else s_chan[ch].SB[29]=fa;                          // no interpolation
364   }
365 }
366
367 ////////////////////////////////////////////////////////////////////////
368
369 INLINE int iGetInterpolationVal(int ch)
370 {
371  int fa;
372
373  if(s_chan[ch].bFMod==2) return s_chan[ch].SB[29];
374
375  switch(iUseInterpolation)
376   {   
377    //--------------------------------------------------//
378    case 3:                                             // cubic interpolation
379     {
380      long xd;int gpos;
381      xd = ((s_chan[ch].spos) >> 1)+1;
382      gpos = s_chan[ch].SB[28];
383
384      fa  = gval(3) - 3*gval(2) + 3*gval(1) - gval0;
385      fa *= (xd - (2<<15)) / 6;
386      fa >>= 15;
387      fa += gval(2) - gval(1) - gval(1) + gval0;
388      fa *= (xd - (1<<15)) >> 1;
389      fa >>= 15;
390      fa += gval(1) - gval0;
391      fa *= xd;
392      fa >>= 15;
393      fa = fa + gval0;
394
395     } break;
396    //--------------------------------------------------//
397    case 2:                                             // gauss interpolation
398     {
399      int vl, vr;int gpos;
400      vl = (s_chan[ch].spos >> 6) & ~3;
401      gpos = s_chan[ch].SB[28];
402      vr=(gauss[vl]*gval0)&~2047;
403      vr+=(gauss[vl+1]*gval(1))&~2047;
404      vr+=(gauss[vl+2]*gval(2))&~2047;
405      vr+=(gauss[vl+3]*gval(3))&~2047;
406      fa = vr>>11;
407     } break;
408    //--------------------------------------------------//
409    case 1:                                             // simple interpolation
410     {
411      if(s_chan[ch].sinc<0x10000L)                      // -> upsampling?
412           InterpolateUp(ch);                           // --> interpolate up
413      else InterpolateDown(ch);                         // --> else down
414      fa=s_chan[ch].SB[29];
415     } break;
416    //--------------------------------------------------//
417    default:                                            // no interpolation
418     {
419      fa=s_chan[ch].SB[29];                  
420     } break;
421    //--------------------------------------------------//
422   }
423
424  return fa;
425 }
426
427 ////////////////////////////////////////////////////////////////////////
428 // MAIN SPU FUNCTION
429 // here is the main job handler... thread, timer or direct func call
430 // basically the whole sound processing is done in this fat func!
431 ////////////////////////////////////////////////////////////////////////
432
433 // 5 ms waiting phase, if buffer is full and no new sound has to get started
434 // .. can be made smaller (smallest val: 1 ms), but bigger waits give
435 // better performance
436
437 #define PAUSE_W 5
438 #define PAUSE_L 5000
439
440 ////////////////////////////////////////////////////////////////////////
441
442 static void *MAINThread(void *arg)
443 {
444  int s_1,s_2,fa,ns,ns_from,ns_to;
445 #if !defined(_MACOSX) && !defined(__arm__)
446  int voldiv = iVolume;
447 #else
448  const int voldiv = 2;
449 #endif
450  unsigned char * start;unsigned int nSample;
451  int ch,predict_nr,shift_factor,flags,d,s;
452  int bIRQReturn=0;
453
454  while(!bEndThread)                                    // until we are shutting down
455   {
456    // ok, at the beginning we are looking if there is
457    // enuff free place in the dsound/oss buffer to
458    // fill in new data, or if there is a new channel to start.
459    // if not, we wait (thread) or return (timer/spuasync)
460    // until enuff free place is available/a new channel gets
461    // started
462
463    if(dwNewChannel)                                    // new channel should start immedately?
464     {                                                  // (at least one bit 0 ... MAXCHANNEL is set?)
465      iSecureStart++;                                   // -> set iSecure
466      if(iSecureStart>5) 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)
467     }
468    else iSecureStart=0;                                // 0: no new channel should start
469
470    while(!iSecureStart && !bEndThread &&               // no new start? no thread end?
471          (SoundGetBytesBuffered()>TESTSIZE))           // and still enuff data in sound buffer?
472     {
473      iSecureStart=0;                                   // reset secure
474
475      if(iUseTimer) return 0;                           // linux no-thread mode? bye
476      usleep(PAUSE_L);                                  // else sleep for x ms (linux)
477
478      if(dwNewChannel) iSecureStart=1;                  // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop
479     }
480
481    //--------------------------------------------------// continue from irq handling in timer mode? 
482
483    ns_from=0;
484    ns_to=NSSIZE;
485    ch=0;
486    if(lastch>=0)                                       // will be -1 if no continue is pending
487     {
488      ch=lastch; ns_from=lastns+1; lastch=-1;           // -> setup all kind of vars to continue
489     }
490
491    //--------------------------------------------------//
492    //- main channel loop                              -// 
493    //--------------------------------------------------//
494     {
495      for(;ch<MAXCHAN;ch++)                             // loop em all... we will collect 1 ms of sound of each playing channel
496       {
497        if(s_chan[ch].bNew) StartSound(ch);             // start new sound
498        if(!s_chan[ch].bOn) continue;                   // channel not playing? next
499
500        if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq)   // new psx frequency?
501         VoiceChangeFrequency(ch);
502
503        for(ns=ns_from;ns<ns_to;ns++)                   // loop until 1 ms of data is reached
504         {
505          if(s_chan[ch].bFMod==1 && iFMod[ns])          // fmod freq channel
506           FModChangeFrequency(ch,ns);
507
508          while(s_chan[ch].spos>=0x10000L)
509           {
510            if(s_chan[ch].iSBPos==28)                   // 28 reached?
511             {
512              start=s_chan[ch].pCurr;                   // set up the current pos
513
514              if (start == (unsigned char*)-1)          // special "stop" sign
515               {
516                s_chan[ch].bOn=0;                       // -> turn everything off
517                s_chan[ch].ADSRX.lVolume=0;
518                s_chan[ch].ADSRX.EnvelopeVol=0;
519                goto ENDX;                              // -> and done for this channel
520               }
521
522              s_chan[ch].iSBPos=0;
523
524              //////////////////////////////////////////// spu irq handler here? mmm... do it later
525
526              s_1=s_chan[ch].s_1;
527              s_2=s_chan[ch].s_2;
528
529              predict_nr=(int)*start;start++;
530              shift_factor=predict_nr&0xf;
531              predict_nr >>= 4;
532              flags=(int)*start;start++;
533
534              // -------------------------------------- // 
535
536              for (nSample=0;nSample<28;start++)      
537               {
538                d=(int)*start;
539                s=((d&0xf)<<12);
540                if(s&0x8000) s|=0xffff0000;
541
542                fa=(s >> shift_factor);
543                fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
544                s_2=s_1;s_1=fa;
545                s=((d & 0xf0) << 8);
546
547                s_chan[ch].SB[nSample++]=fa;
548
549                if(s&0x8000) s|=0xffff0000;
550                fa=(s>>shift_factor);
551                fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
552                s_2=s_1;s_1=fa;
553
554                s_chan[ch].SB[nSample++]=fa;
555               }
556
557              //////////////////////////////////////////// irq check
558
559              if(irqCallback && (spuCtrl&0x40))         // some callback and irq active?
560               {
561                if((pSpuIrq >  start-16 &&              // irq address reached?
562                    pSpuIrq <= start) ||
563                   ((flags&1) &&                        // special: irq on looping addr, when stop/loop flag is set 
564                    (pSpuIrq >  s_chan[ch].pLoop-16 &&
565                     pSpuIrq <= s_chan[ch].pLoop)))
566                {
567                  s_chan[ch].iIrqDone=1;                // -> debug flag
568                  irqCallback();                        // -> call main emu
569
570                  if(iSPUIRQWait)                       // -> option: wait after irq for main emu
571                   {
572                    iSpuAsyncWait=1;
573                    bIRQReturn=1;
574                    lastch=ch; 
575                    lastns=ns;
576                    ns_to=ns+1;
577                   }
578                 }
579               }
580
581              //////////////////////////////////////////// flag handler
582
583              if((flags&4) && (!s_chan[ch].bIgnoreLoop))
584               s_chan[ch].pLoop=start-16;               // loop adress
585
586              if(flags&1)                               // 1: stop/loop
587               {
588                // We play this block out first...
589                //if(!(flags&2))                          // 1+2: do loop... otherwise: stop
590                if(flags!=3 || s_chan[ch].pLoop==NULL)  // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example)
591                 {                                      // and checking if pLoop is set avoids crashes, yeah
592                  start = (unsigned char*)-1;
593                 }
594                else
595                 {
596                  start = s_chan[ch].pLoop;
597                 }
598               }
599
600              s_chan[ch].pCurr=start;                   // store values for next cycle
601              s_chan[ch].s_1=s_1;
602              s_chan[ch].s_2=s_2;
603
604 GOON: ;
605             }
606
607            fa=s_chan[ch].SB[s_chan[ch].iSBPos++];      // get sample data
608
609            StoreInterpolationVal(ch,fa);               // store val for later interpolation
610
611            s_chan[ch].spos -= 0x10000L;
612           }
613
614          if(s_chan[ch].bNoise)
615               fa=iGetNoiseVal(ch);                     // get noise val
616          else fa=iGetInterpolationVal(ch);             // get sample val
617
618          s_chan[ch].sval = (MixADSR(ch) * fa) / 1023;  // mix adsr
619
620          if(s_chan[ch].bFMod==2)                       // fmod freq channel
621           iFMod[ns]=s_chan[ch].sval;                   // -> store 1T sample data, use that to do fmod on next channel
622          else                                          // no fmod freq channel
623           {
624            //////////////////////////////////////////////
625            // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
626
627            if(s_chan[ch].iMute) 
628             s_chan[ch].sval=0;                         // debug mute
629            else
630             {
631              SSumL[ns]+=(s_chan[ch].sval*s_chan[ch].iLeftVolume)/0x4000L;
632              SSumR[ns]+=(s_chan[ch].sval*s_chan[ch].iRightVolume)/0x4000L;
633             }
634
635            //////////////////////////////////////////////
636            // now let us store sound data for reverb    
637
638            if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns);
639           }
640
641          ////////////////////////////////////////////////
642          // ok, go on until 1 ms data of this channel is collected
643
644          s_chan[ch].spos += s_chan[ch].sinc;
645         }
646 ENDX:   ;
647       }
648     }
649
650     if(bIRQReturn)                            // special return for "spu irq - wait for cpu action"
651      {
652       bIRQReturn=0;
653       if(iUseTimer!=2)
654        { 
655         DWORD dwWatchTime=timeGetTime_spu()+2500;
656
657         while(iSpuAsyncWait && !bEndThread && 
658               timeGetTime_spu()<dwWatchTime)
659             usleep(1000L);
660         continue;
661        }
662       else
663        {
664         return 0;
665        }
666      }
667
668
669   //---------------------------------------------------//
670   //- here we have another 1 ms of sound data
671   //---------------------------------------------------//
672   // mix XA infos (if any)
673
674   MixXA();
675   
676   ///////////////////////////////////////////////////////
677   // mix all channels (including reverb) into one buffer
678
679   if(iDisStereo)                                       // no stereo?
680    {
681     int dl, dr;
682     for (ns = 0; ns < NSSIZE; ns++)
683      {
684       SSumL[ns] += MixREVERBLeft(ns);
685
686       dl = SSumL[ns] / voldiv; SSumL[ns] = 0;
687       if (dl < -32767) dl = -32767; if (dl > 32767) dl = 32767;
688
689       SSumR[ns] += MixREVERBRight();
690
691       dr = SSumR[ns] / voldiv; SSumR[ns] = 0;
692       if (dr < -32767) dr = -32767; if (dr > 32767) dr = 32767;
693       *pS++ = (dl + dr) / 2;
694      }
695    }
696   else                                                 // stereo:
697   for (ns = 0; ns < NSSIZE; ns++)
698    {
699     SSumL[ns] += MixREVERBLeft(ns);
700
701     d = SSumL[ns] / voldiv; SSumL[ns] = 0;
702     if (d < -32767) d = -32767; if (d > 32767) d = 32767;
703     *pS++ = d;
704
705     SSumR[ns] += MixREVERBRight();
706
707     d = SSumR[ns] / voldiv; SSumR[ns] = 0;
708     if(d < -32767) d = -32767; if(d > 32767) d = 32767;
709     *pS++ = d;
710    }
711
712   //////////////////////////////////////////////////////                   
713   // special irq handling in the decode buffers (0x0000-0x1000)
714   // we know: 
715   // the decode buffers are located in spu memory in the following way:
716   // 0x0000-0x03ff  CD audio left
717   // 0x0400-0x07ff  CD audio right
718   // 0x0800-0x0bff  Voice 1
719   // 0x0c00-0x0fff  Voice 3
720   // and decoded data is 16 bit for one sample
721   // we assume: 
722   // even if voices 1/3 are off or no cd audio is playing, the internal
723   // play positions will move on and wrap after 0x400 bytes.
724   // Therefore: we just need a pointer from spumem+0 to spumem+3ff, and 
725   // increase this pointer on each sample by 2 bytes. If this pointer
726   // (or 0x400 offsets of this pointer) hits the spuirq address, we generate
727   // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here
728   // in some of Peops timer modes. So: we ignore this option here (for now).
729
730   if(pMixIrq && irqCallback)
731    {
732     for(ns=0;ns<NSSIZE;ns++)
733      {
734       if((spuCtrl&0x40) && pSpuIrq && pSpuIrq<spuMemC+0x1000)                 
735        {
736         for(ch=0;ch<4;ch++)
737          {
738           if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
739            {irqCallback();s_chan[ch].iIrqDone=1;}
740          }
741        }
742       pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
743      }
744    }
745
746   InitREVERB();
747
748   // feed the sound
749   // wanna have around 1/60 sec (16.666 ms) updates
750   if (iCycle++ > 16)
751    {
752     SoundFeedStreamData((unsigned char *)pSpuBuffer,
753                         ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer));
754     pS = (short *)pSpuBuffer;
755     iCycle = 0;
756    }
757  }
758
759  // end of big main loop...
760
761  bThreadEnded = 1;
762
763  return 0;
764 }
765
766 // SPU ASYNC... even newer epsxe func
767 //  1 time every 'cycle' cycles... harhar
768
769 void CALLBACK SPUasync(unsigned long cycle)
770 {
771  if(iSpuAsyncWait)
772   {
773    iSpuAsyncWait++;
774    if(iSpuAsyncWait<=64) return;
775    iSpuAsyncWait=0;
776   }
777
778  if(iUseTimer==2)                                      // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode)
779   {
780    if(!bSpuInit) return;                               // -> no init, no call
781
782    MAINThread(0);                                      // -> linux high-compat mode
783   }
784 }
785
786 // SPU UPDATE... new epsxe func
787 //  1 time every 32 hsync lines
788 //  (312/32)x50 in pal
789 //  (262/32)x60 in ntsc
790
791 // since epsxe 1.5.2 (linux) uses SPUupdate, not SPUasync, I will
792 // leave that func in the linux port, until epsxe linux is using
793 // the async function as well
794
795 void CALLBACK SPUupdate(void)
796 {
797  SPUasync(0);
798 }
799
800 // XA AUDIO
801
802 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap)
803 {
804  if(!xap)       return;
805  if(!xap->freq) return;                                // no xa freq ? bye
806
807  FeedXA(xap);                                          // call main XA feeder
808 }
809
810 // CDDA AUDIO
811 void CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
812 {
813  if (!pcm)      return;
814  if (nbytes<=0) return;
815
816  FeedCDDA((unsigned char *)pcm, nbytes);
817 }
818
819 // SETUPTIMER: init of certain buffers and threads/timers
820 void SetupTimer(void)
821 {
822  memset(SSumR,0,NSSIZE*sizeof(int));                   // init some mixing buffers
823  memset(SSumL,0,NSSIZE*sizeof(int));
824  memset(iFMod,0,NSSIZE*sizeof(int));
825  pS=(short *)pSpuBuffer;                               // setup soundbuffer pointer
826
827  bEndThread=0;                                         // init thread vars
828  bThreadEnded=0; 
829  bSpuInit=1;                                           // flag: we are inited
830
831  if(!iUseTimer)                                        // linux: use thread
832   {
833    pthread_create(&thread, NULL, MAINThread, NULL);
834   }
835 }
836
837 // REMOVETIMER: kill threads/timers
838 void RemoveTimer(void)
839 {
840  bEndThread=1;                                         // raise flag to end thread
841
842  if(!iUseTimer)                                        // linux tread?
843   {
844    int i=0;
845    while(!bThreadEnded && i<2000) {usleep(1000L);i++;} // -> wait until thread has ended
846    if(thread!=(pthread_t)-1) {pthread_cancel(thread);thread=(pthread_t)-1;}  // -> cancel thread anyway
847   }
848
849  bThreadEnded=0;                                       // no more spu is running
850  bSpuInit=0;
851 }
852
853 // SETUPSTREAMS: init most of the spu buffers
854 void SetupStreams(void)
855
856  int i;
857
858  pSpuBuffer=(unsigned char *)malloc(32768);            // alloc mixing buffer
859
860  if(iUseReverb==1) i=88200*2;
861  else              i=NSSIZE*2;
862
863  sRVBStart = (int *)malloc(i*4);                       // alloc reverb buffer
864  memset(sRVBStart,0,i*4);
865  sRVBEnd  = sRVBStart + i;
866  sRVBPlay = sRVBStart;
867
868  XAStart =                                             // alloc xa buffer
869   (uint32_t *)malloc(44100 * sizeof(uint32_t));
870  XAEnd   = XAStart + 44100;
871  XAPlay  = XAStart;
872  XAFeed  = XAStart;
873
874  CDDAStart =                                           // alloc cdda buffer
875   (uint32_t *)malloc(16384 * sizeof(uint32_t));
876  CDDAEnd   = CDDAStart + 16384;
877  CDDAPlay  = CDDAStart;
878  CDDAFeed  = CDDAStart + 1;
879
880  for(i=0;i<MAXCHAN;i++)                                // loop sound channels
881   {
882 // we don't use mutex sync... not needed, would only 
883 // slow us down:
884 //   s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
885    s_chan[i].ADSRX.SustainLevel = 1024;                // -> init sustain
886    s_chan[i].iMute=0;
887    s_chan[i].iIrqDone=0;
888    s_chan[i].pLoop=spuMemC;
889    s_chan[i].pStart=spuMemC;
890    s_chan[i].pCurr=spuMemC;
891   }
892
893   pMixIrq=spuMemC;                                     // enable decoded buffer irqs by setting the address
894 }
895
896 // REMOVESTREAMS: free most buffer
897 void RemoveStreams(void)
898
899  free(pSpuBuffer);                                     // free mixing buffer
900  pSpuBuffer = NULL;
901  free(sRVBStart);                                      // free reverb buffer
902  sRVBStart = NULL;
903  free(XAStart);                                        // free XA buffer
904  XAStart = NULL;
905  free(CDDAStart);                                      // free CDDA buffer
906  CDDAStart = NULL;
907 }
908
909 // INIT/EXIT STUFF
910
911 // SPUINIT: this func will be called first by the main emu
912 long CALLBACK SPUinit(void)
913 {
914  spuMemC = (unsigned char *)spuMem;                    // just small setup
915  memset((void *)&rvb, 0, sizeof(REVERBInfo));
916  InitADSR();
917
918  iVolume = 3;
919  iReverbOff = -1;
920  spuIrq = 0;
921  spuAddr = 0xffffffff;
922  bEndThread = 0;
923  bThreadEnded = 0;
924  spuMemC = (unsigned char *)spuMem;
925  pMixIrq = 0;
926  memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
927  pSpuIrq = 0;
928  iSPUIRQWait = 0;
929  lastch = -1;
930
931  //ReadConfigSPU();                                      // read user stuff
932  SetupStreams();                                       // prepare streaming
933
934  return 0;
935 }
936
937 // SPUOPEN: called by main emu after init
938 long CALLBACK SPUopen(void)
939 {
940  if (bSPUIsOpen) return 0;                             // security for some stupid main emus
941
942  SetupSound();                                         // setup sound (before init!)
943  SetupTimer();                                         // timer for feeding data
944
945  bSPUIsOpen = 1;
946
947  return PSE_SPU_ERR_SUCCESS;
948 }
949
950 // SPUCLOSE: called before shutdown
951 long CALLBACK SPUclose(void)
952 {
953  if (!bSPUIsOpen) return 0;                            // some security
954
955  bSPUIsOpen = 0;                                       // no more open
956
957  RemoveTimer();                                        // no more feeding
958  RemoveSound();                                        // no more sound handling
959
960  return 0;
961 }
962
963 // SPUSHUTDOWN: called by main emu on final exit
964 long CALLBACK SPUshutdown(void)
965 {
966  SPUclose();
967  RemoveStreams();                                      // no more streaming
968
969  return 0;
970 }
971
972 // SPUTEST: we don't test, we are always fine ;)
973 long CALLBACK SPUtest(void)
974 {
975  return 0;
976 }
977
978 // SPUCONFIGURE: call config dialog
979 long CALLBACK SPUconfigure(void)
980 {
981 #ifdef _MACOSX
982  DoConfiguration();
983 #else
984 // StartCfgTool("CFG");
985 #endif
986  return 0;
987 }
988
989 // SPUABOUT: show about window
990 void CALLBACK SPUabout(void)
991 {
992 #ifdef _MACOSX
993  DoAbout();
994 #else
995 // StartCfgTool("ABOUT");
996 #endif
997 }
998
999 // SETUP CALLBACKS
1000 // this functions will be called once, 
1001 // passes a callback that should be called on SPU-IRQ/cdda volume change
1002 void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
1003 {
1004  irqCallback = callback;
1005 }
1006
1007 void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
1008 {
1009  cddavCallback = CDDAVcallback;
1010 }
1011
1012 // COMMON PLUGIN INFO FUNCS
1013 /*
1014 char * CALLBACK PSEgetLibName(void)
1015 {
1016  return _(libraryName);
1017 }
1018
1019 unsigned long CALLBACK PSEgetLibType(void)
1020 {
1021  return  PSE_LT_SPU;
1022 }
1023
1024 unsigned long CALLBACK PSEgetLibVersion(void)
1025 {
1026  return (1 << 16) | (6 << 8);
1027 }
1028
1029 char * SPUgetLibInfos(void)
1030 {
1031  return _(libraryInfo);
1032 }
1033 */