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