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