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