drc: merge Ari64's patch: 14_dont_save_or_restore_temporary
[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 /*
38 #if defined (USEMACOSX)
39 static char * libraryName     = N_("Mac OS X Sound");
40 #elif defined (USEALSA)
41 static char * libraryName     = N_("ALSA Sound");
42 #elif defined (USEOSS)
43 static char * libraryName     = N_("OSS Sound");
44 #elif defined (USESDL)
45 static char * libraryName     = N_("SDL Sound");
46 #elif defined (USEPULSEAUDIO)
47 static char * libraryName     = N_("PulseAudio Sound");
48 #else
49 static char * libraryName     = N_("NULL Sound");
50 #endif
51
52 static char * libraryInfo     = N_("P.E.Op.S. Sound Driver V1.7\nCoded by Pete Bernert and the P.E.Op.S. team\n");
53 */
54
55 // globals
56
57 // psx buffer / addresses
58
59 unsigned short  regArea[10000];
60 unsigned short  spuMem[256*1024];
61 unsigned char * spuMemC;
62 unsigned char * pSpuIrq=0;
63 unsigned char * pSpuBuffer;
64 unsigned char * pMixIrq=0;
65
66 // user settings
67
68 int             iVolume=3;
69 int             iXAPitch=1;
70 int             iUseTimer=2;
71 int             iSPUIRQWait=1;
72 int             iDebugMode=0;
73 int             iRecordMode=0;
74 int             iUseReverb=2;
75 int             iUseInterpolation=2;
76
77 // MAIN infos struct for each channel
78
79 SPUCHAN         s_chan[MAXCHAN+1];                     // channel + 1 infos (1 is security for fmod handling)
80 REVERBInfo      rvb;
81
82 unsigned long   dwNoiseVal=1;                          // global noise generator
83 int             iSpuAsyncWait=0;
84
85 unsigned short  spuCtrl=0;                             // some vars to store psx reg infos
86 unsigned short  spuStat=0;
87 unsigned short  spuIrq=0;
88 unsigned long   spuAddr=0xffffffff;                    // address into spu mem
89 int             bEndThread=0;                          // thread handlers
90 int             bThreadEnded=0;
91 int             bSpuInit=0;
92 int             bSPUIsOpen=0;
93
94 static pthread_t thread = (pthread_t)-1;               // thread id (linux)
95
96 unsigned long dwNewChannel=0;                          // flags for faster testing, if new channel starts
97 unsigned long dwChannelOn=0;
98
99 void (CALLBACK *irqCallback)(void)=0;                  // func of main emu, called on spu irq
100 void (CALLBACK *cddavCallback)(unsigned short,unsigned short)=0;
101
102 // certain globals (were local before, but with the new timeproc I need em global)
103
104 static const int f[8][2] = {   {    0,  0  },
105                         {   60,  0  },
106                         {  115, -52 },
107                         {   98, -55 },
108                         {  122, -60 } };
109 int SSumLR[NSSIZE*2];
110 int iFMod[NSSIZE];
111 int iCycle = 0;
112 short * pS;
113
114 int lastch=-1;             // last channel processed on spu irq in timer mode
115 static int lastns=0;       // last ns pos
116 static int iSecureStart=0; // secure start counter
117
118 ////////////////////////////////////////////////////////////////////////
119 // CODE AREA
120 ////////////////////////////////////////////////////////////////////////
121
122 // dirty inline func includes
123
124 #include "reverb.c"
125 #include "adsr.c"
126
127 ////////////////////////////////////////////////////////////////////////
128 // helpers for simple interpolation
129
130 //
131 // easy interpolation on upsampling, no special filter, just "Pete's common sense" tm
132 //
133 // instead of having n equal sample values in a row like:
134 //       ____
135 //           |____
136 //
137 // we compare the current delta change with the next delta change.
138 //
139 // if curr_delta is positive,
140 //
141 //  - and next delta is smaller (or changing direction):
142 //         \.
143 //          -__
144 //
145 //  - and next delta significant (at least twice) bigger:
146 //         --_
147 //            \.
148 //
149 //  - and next delta is nearly same:
150 //          \.
151 //           \.
152 //
153 //
154 // if curr_delta is negative,
155 //
156 //  - and next delta is smaller (or changing direction):
157 //          _--
158 //         /
159 //
160 //  - and next delta significant (at least twice) bigger:
161 //            /
162 //         __- 
163 //
164 //  - and next delta is nearly same:
165 //           /
166 //          /
167 //
168
169
170 INLINE void InterpolateUp(int ch)
171 {
172  if(s_chan[ch].SB[32]==1)                              // flag == 1? calc step and set flag... and don't change the value in this pass
173   {
174    const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29];  // curr delta to next val
175    const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30];  // and next delta to next-next val :)
176
177    s_chan[ch].SB[32]=0;
178
179    if(id1>0)                                           // curr delta positive
180     {
181      if(id2<id1)
182       {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
183      else
184      if(id2<(id1<<1))
185       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
186      else
187       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
188     }
189    else                                                // curr delta negative
190     {
191      if(id2>id1)
192       {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
193      else
194      if(id2>(id1<<1))
195       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
196      else
197       s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L; 
198     }
199   }
200  else
201  if(s_chan[ch].SB[32]==2)                              // flag 1: calc step and set flag... and don't change the value in this pass
202   {
203    s_chan[ch].SB[32]=0;
204
205    s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L;
206    if(s_chan[ch].sinc<=0x8000)
207         s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1));
208    else s_chan[ch].SB[29]+=s_chan[ch].SB[28];
209   }
210  else                                                  // no flags? add bigger val (if possible), calc smaller step, set flag1
211   s_chan[ch].SB[29]+=s_chan[ch].SB[28];
212 }
213
214 //
215 // even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
216 //
217
218 INLINE void InterpolateDown(int ch)
219 {
220  if(s_chan[ch].sinc>=0x20000L)                                 // we would skip at least one val?
221   {
222    s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight
223    if(s_chan[ch].sinc>=0x30000L)                               // we would skip even more vals?
224     s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight
225   }
226 }
227
228 ////////////////////////////////////////////////////////////////////////
229 // helpers for gauss interpolation
230
231 #define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos])
232 #define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3])
233
234 #include "gauss_i.h"
235
236 ////////////////////////////////////////////////////////////////////////
237
238 #include "xa.c"
239
240 ////////////////////////////////////////////////////////////////////////
241 // START SOUND... called by main thread to setup a new sound on a channel
242 ////////////////////////////////////////////////////////////////////////
243
244 INLINE void StartSound(int ch)
245 {
246  StartADSR(ch);
247  StartREVERB(ch);
248
249  // fussy timing issues - do in VoiceOn
250  //s_chan[ch].pCurr=s_chan[ch].pStart;                   // set sample start
251  //s_chan[ch].bStop=0;
252  //s_chan[ch].bOn=1;
253
254  s_chan[ch].s_1=0;                                     // init mixing vars
255  s_chan[ch].s_2=0;
256  s_chan[ch].iSBPos=28;
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,ns_from,ns_to;
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    ns_from=0;
483    ns_to=NSSIZE;
484    ch=0;
485    if(lastch>=0)                                       // will be -1 if no continue is pending
486     {
487      ch=lastch; ns_from=lastns+1; lastch=-1;           // -> setup all kind of vars to continue
488     }
489
490    //--------------------------------------------------//
491    //- main channel loop                              -// 
492    //--------------------------------------------------//
493     {
494      for(;ch<MAXCHAN;ch++)                             // loop em all... we will collect 1 ms of sound of each playing channel
495       {
496        if(dwNewChannel&(1<<ch)) StartSound(ch);        // start new sound
497        if(!(dwChannelOn&(1<<ch))) continue;            // channel not playing? next
498
499        if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq)   // new psx frequency?
500         VoiceChangeFrequency(ch);
501
502        for(ns=ns_from;ns<ns_to;ns++)                   // loop until 1 ms of data is reached
503         {
504          int sval;
505
506          if(s_chan[ch].bFMod==1 && iFMod[ns])          // fmod freq channel
507           FModChangeFrequency(ch,ns);
508
509          while(s_chan[ch].spos>=0x10000L)
510           {
511            if(s_chan[ch].iSBPos==28)                   // 28 reached?
512             {
513              start=s_chan[ch].pCurr;                   // set up the current pos
514
515              if (start == (unsigned char*)-1)          // special "stop" sign
516               {
517                dwChannelOn&=~(1<<ch);                  // -> turn everything off
518                s_chan[ch].ADSRX.EnvelopeVol=0;
519                goto ENDX;                              // -> and done for this channel
520               }
521
522              s_chan[ch].iSBPos=0;
523
524              //////////////////////////////////////////// spu irq handler here? mmm... do it later
525
526              s_1=s_chan[ch].s_1;
527              s_2=s_chan[ch].s_2;
528
529              predict_nr=(int)*start;start++;
530              shift_factor=predict_nr&0xf;
531              predict_nr >>= 4;
532              flags=(int)*start;start++;
533
534              // -------------------------------------- // 
535
536              for (nSample=0;nSample<28;start++)      
537               {
538                d=(int)*start;
539                s=((d&0xf)<<12);
540                if(s&0x8000) s|=0xffff0000;
541
542                fa=(s >> shift_factor);
543                fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
544                s_2=s_1;s_1=fa;
545                s=((d & 0xf0) << 8);
546
547                s_chan[ch].SB[nSample++]=fa;
548
549                if(s&0x8000) s|=0xffff0000;
550                fa=(s>>shift_factor);
551                fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
552                s_2=s_1;s_1=fa;
553
554                s_chan[ch].SB[nSample++]=fa;
555               }
556
557              //////////////////////////////////////////// irq check
558
559              if(irqCallback && (spuCtrl&0x40))         // some callback and irq active?
560               {
561                if((pSpuIrq >  start-16 &&              // irq address reached?
562                    pSpuIrq <= start) ||
563                   ((flags&1) &&                        // special: irq on looping addr, when stop/loop flag is set 
564                    (pSpuIrq >  s_chan[ch].pLoop-16 &&
565                     pSpuIrq <= s_chan[ch].pLoop)))
566                {
567                  irqCallback();                        // -> call main emu
568
569                  if(iSPUIRQWait)                       // -> option: wait after irq for main emu
570                   {
571                    iSpuAsyncWait=1;
572                    bIRQReturn=1;
573                    lastch=ch; 
574                    lastns=ns;
575                    ns_to=ns+1;
576                   }
577                 }
578               }
579
580              //////////////////////////////////////////// flag handler
581
582              if((flags&4) && (!s_chan[ch].bIgnoreLoop))
583               s_chan[ch].pLoop=start-16;               // loop adress
584
585              if(flags&1)                               // 1: stop/loop
586               {
587                // We play this block out first...
588                //if(!(flags&2))                          // 1+2: do loop... otherwise: stop
589                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)
590                 {                                      // and checking if pLoop is set avoids crashes, yeah
591                  start = (unsigned char*)-1;
592                 }
593                else
594                 {
595                  start = s_chan[ch].pLoop;
596                 }
597               }
598
599              s_chan[ch].pCurr=start;                   // store values for next cycle
600              s_chan[ch].s_1=s_1;
601              s_chan[ch].s_2=s_2;
602             }
603
604            fa=s_chan[ch].SB[s_chan[ch].iSBPos++];      // get sample data
605
606            StoreInterpolationVal(ch,fa);               // store val for later interpolation
607
608            s_chan[ch].spos -= 0x10000L;
609           }
610
611          if(s_chan[ch].bNoise)
612               fa=iGetNoiseVal(ch);                     // get noise val
613          else fa=iGetInterpolationVal(ch);             // get sample val
614
615          sval = (MixADSR(ch) * fa) / 1023;  // mix adsr
616
617          if(s_chan[ch].bFMod==2)                       // fmod freq channel
618           iFMod[ns]=sval;                              // -> store 1T sample data, use that to do fmod on next channel
619          else                                          // no fmod freq channel
620           {
621            //////////////////////////////////////////////
622            // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
623
624            SSumLR[ns*2]  +=(sval*s_chan[ch].iLeftVolume)/0x4000L;
625            SSumLR[ns*2+1]+=(sval*s_chan[ch].iRightVolume)/0x4000L;
626
627            //////////////////////////////////////////////
628            // now let us store sound data for reverb    
629
630            if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns,sval);
631           }
632
633          ////////////////////////////////////////////////
634          // ok, go on until 1 ms data of this channel is collected
635
636          s_chan[ch].spos += s_chan[ch].sinc;
637         }
638 ENDX:   ;
639       }
640     }
641
642     if(bIRQReturn)                            // special return for "spu irq - wait for cpu action"
643      {
644       bIRQReturn=0;
645       if(iUseTimer!=2)
646        { 
647         DWORD dwWatchTime=timeGetTime_spu()+2500;
648
649         while(iSpuAsyncWait && !bEndThread && 
650               timeGetTime_spu()<dwWatchTime)
651             usleep(1000L);
652         continue;
653        }
654       else
655        {
656         return 0;
657        }
658      }
659
660
661   //---------------------------------------------------//
662   //- here we have another 1 ms of sound data
663   //---------------------------------------------------//
664   // mix XA infos (if any)
665
666   MixXA();
667   
668   ///////////////////////////////////////////////////////
669   // mix all channels (including reverb) into one buffer
670
671   for (ns = 0; ns < NSSIZE*2; )
672    {
673     SSumLR[ns] += MixREVERBLeft(ns/2);
674
675     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
676     if (d < -32767) d = -32767; if (d > 32767) d = 32767;
677     *pS++ = d;
678     ns++;
679
680     SSumLR[ns] += MixREVERBRight();
681
682     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
683     if(d < -32767) d = -32767; if(d > 32767) d = 32767;
684     *pS++ = d;
685     ns++;
686    }
687
688   //////////////////////////////////////////////////////                   
689   // special irq handling in the decode buffers (0x0000-0x1000)
690   // we know: 
691   // the decode buffers are located in spu memory in the following way:
692   // 0x0000-0x03ff  CD audio left
693   // 0x0400-0x07ff  CD audio right
694   // 0x0800-0x0bff  Voice 1
695   // 0x0c00-0x0fff  Voice 3
696   // and decoded data is 16 bit for one sample
697   // we assume: 
698   // even if voices 1/3 are off or no cd audio is playing, the internal
699   // play positions will move on and wrap after 0x400 bytes.
700   // Therefore: we just need a pointer from spumem+0 to spumem+3ff, and 
701   // increase this pointer on each sample by 2 bytes. If this pointer
702   // (or 0x400 offsets of this pointer) hits the spuirq address, we generate
703   // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here
704   // in some of Peops timer modes. So: we ignore this option here (for now).
705
706   if(pMixIrq && irqCallback)
707    {
708     for(ns=0;ns<NSSIZE;ns++)
709      {
710       if((spuCtrl&0x40) && pSpuIrq && pSpuIrq<spuMemC+0x1000)                 
711        {
712         for(ch=0;ch<4;ch++)
713          {
714           if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
715            irqCallback();
716          }
717        }
718       pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
719      }
720    }
721
722   InitREVERB();
723
724   // feed the sound
725   // wanna have around 1/60 sec (16.666 ms) updates
726   if (iCycle++ > 16)
727    {
728     SoundFeedStreamData((unsigned char *)pSpuBuffer,
729                         ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer));
730     pS = (short *)pSpuBuffer;
731     iCycle = 0;
732    }
733  }
734
735  // end of big main loop...
736
737  bThreadEnded = 1;
738
739  return 0;
740 }
741
742 // SPU ASYNC... even newer epsxe func
743 //  1 time every 'cycle' cycles... harhar
744
745 void CALLBACK SPUasync(unsigned long cycle)
746 {
747  if(iSpuAsyncWait)
748   {
749    iSpuAsyncWait++;
750    if(iSpuAsyncWait<=16) return;
751    iSpuAsyncWait=0;
752   }
753
754  if(iUseTimer==2)                                      // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode)
755   {
756    if(!bSpuInit) return;                               // -> no init, no call
757
758    MAINThread(0);                                      // -> linux high-compat mode
759
760    // abuse iSpuAsyncWait mechanism to reduce calls to above function
761    // to make it do larger chunks
762    // note: doing it less often than once per frame causes skips
763    iSpuAsyncWait=1;
764   }
765 }
766
767 // SPU UPDATE... new epsxe func
768 //  1 time every 32 hsync lines
769 //  (312/32)x50 in pal
770 //  (262/32)x60 in ntsc
771
772 // since epsxe 1.5.2 (linux) uses SPUupdate, not SPUasync, I will
773 // leave that func in the linux port, until epsxe linux is using
774 // the async function as well
775
776 void CALLBACK SPUupdate(void)
777 {
778  SPUasync(0);
779 }
780
781 // XA AUDIO
782
783 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap)
784 {
785  if(!xap)       return;
786  if(!xap->freq) return;                                // no xa freq ? bye
787
788  FeedXA(xap);                                          // call main XA feeder
789 }
790
791 // CDDA AUDIO
792 void CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
793 {
794  if (!pcm)      return;
795  if (nbytes<=0) return;
796
797  FeedCDDA((unsigned char *)pcm, nbytes);
798 }
799
800 // SETUPTIMER: init of certain buffers and threads/timers
801 void SetupTimer(void)
802 {
803  memset(SSumLR,0,sizeof(SSumLR));                      // init some mixing buffers
804  memset(iFMod,0,NSSIZE*sizeof(int));
805  pS=(short *)pSpuBuffer;                               // setup soundbuffer pointer
806
807  bEndThread=0;                                         // init thread vars
808  bThreadEnded=0; 
809  bSpuInit=1;                                           // flag: we are inited
810
811  if(!iUseTimer)                                        // linux: use thread
812   {
813    pthread_create(&thread, NULL, MAINThread, NULL);
814   }
815 }
816
817 // REMOVETIMER: kill threads/timers
818 void RemoveTimer(void)
819 {
820  bEndThread=1;                                         // raise flag to end thread
821
822  if(!iUseTimer)                                        // linux tread?
823   {
824    int i=0;
825    while(!bThreadEnded && i<2000) {usleep(1000L);i++;} // -> wait until thread has ended
826    if(thread!=(pthread_t)-1) {pthread_cancel(thread);thread=(pthread_t)-1;}  // -> cancel thread anyway
827   }
828
829  bThreadEnded=0;                                       // no more spu is running
830  bSpuInit=0;
831 }
832
833 // SETUPSTREAMS: init most of the spu buffers
834 void SetupStreams(void)
835
836  int i;
837
838  pSpuBuffer=(unsigned char *)malloc(32768);            // alloc mixing buffer
839
840  if(iUseReverb==1) i=88200*2;
841  else              i=NSSIZE*2;
842
843  sRVBStart = (int *)malloc(i*4);                       // alloc reverb buffer
844  memset(sRVBStart,0,i*4);
845  sRVBEnd  = sRVBStart + i;
846  sRVBPlay = sRVBStart;
847
848  XAStart =                                             // alloc xa buffer
849   (uint32_t *)malloc(44100 * sizeof(uint32_t));
850  XAEnd   = XAStart + 44100;
851  XAPlay  = XAStart;
852  XAFeed  = XAStart;
853
854  CDDAStart =                                           // alloc cdda buffer
855   (uint32_t *)malloc(16384 * sizeof(uint32_t));
856  CDDAEnd   = CDDAStart + 16384;
857  CDDAPlay  = CDDAStart;
858  CDDAFeed  = CDDAStart;
859
860  for(i=0;i<MAXCHAN;i++)                                // loop sound channels
861   {
862 // we don't use mutex sync... not needed, would only 
863 // slow us down:
864 //   s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
865    s_chan[i].ADSRX.SustainLevel = 0xf;                 // -> init sustain
866    s_chan[i].pLoop=spuMemC;
867    s_chan[i].pStart=spuMemC;
868    s_chan[i].pCurr=spuMemC;
869   }
870
871   pMixIrq=spuMemC;                                     // enable decoded buffer irqs by setting the address
872 }
873
874 // REMOVESTREAMS: free most buffer
875 void RemoveStreams(void)
876
877  free(pSpuBuffer);                                     // free mixing buffer
878  pSpuBuffer = NULL;
879  free(sRVBStart);                                      // free reverb buffer
880  sRVBStart = NULL;
881  free(XAStart);                                        // free XA buffer
882  XAStart = NULL;
883  free(CDDAStart);                                      // free CDDA buffer
884  CDDAStart = NULL;
885 }
886
887 // INIT/EXIT STUFF
888
889 // SPUINIT: this func will be called first by the main emu
890 long CALLBACK SPUinit(void)
891 {
892  spuMemC = (unsigned char *)spuMem;                    // just small setup
893  memset((void *)&rvb, 0, sizeof(REVERBInfo));
894  InitADSR();
895
896  iVolume = 3;
897  iReverbOff = -1;
898  spuIrq = 0;
899  spuAddr = 0xffffffff;
900  bEndThread = 0;
901  bThreadEnded = 0;
902  spuMemC = (unsigned char *)spuMem;
903  pMixIrq = 0;
904  memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
905  pSpuIrq = 0;
906  //iSPUIRQWait = 0;
907  lastch = -1;
908
909  //ReadConfigSPU();                                      // read user stuff
910  SetupStreams();                                       // prepare streaming
911
912  return 0;
913 }
914
915 // SPUOPEN: called by main emu after init
916 long CALLBACK SPUopen(void)
917 {
918  if (bSPUIsOpen) return 0;                             // security for some stupid main emus
919
920  SetupSound();                                         // setup sound (before init!)
921  SetupTimer();                                         // timer for feeding data
922
923  bSPUIsOpen = 1;
924
925  return PSE_SPU_ERR_SUCCESS;
926 }
927
928 // SPUCLOSE: called before shutdown
929 long CALLBACK SPUclose(void)
930 {
931  if (!bSPUIsOpen) return 0;                            // some security
932
933  bSPUIsOpen = 0;                                       // no more open
934
935  RemoveTimer();                                        // no more feeding
936  RemoveSound();                                        // no more sound handling
937
938  return 0;
939 }
940
941 // SPUSHUTDOWN: called by main emu on final exit
942 long CALLBACK SPUshutdown(void)
943 {
944  SPUclose();
945  RemoveStreams();                                      // no more streaming
946
947  return 0;
948 }
949
950 // SPUTEST: we don't test, we are always fine ;)
951 long CALLBACK SPUtest(void)
952 {
953  return 0;
954 }
955
956 // SPUCONFIGURE: call config dialog
957 long CALLBACK SPUconfigure(void)
958 {
959 #ifdef _MACOSX
960  DoConfiguration();
961 #else
962 // StartCfgTool("CFG");
963 #endif
964  return 0;
965 }
966
967 // SPUABOUT: show about window
968 void CALLBACK SPUabout(void)
969 {
970 #ifdef _MACOSX
971  DoAbout();
972 #else
973 // StartCfgTool("ABOUT");
974 #endif
975 }
976
977 // SETUP CALLBACKS
978 // this functions will be called once, 
979 // passes a callback that should be called on SPU-IRQ/cdda volume change
980 void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
981 {
982  irqCallback = callback;
983 }
984
985 void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
986 {
987  cddavCallback = CDDAVcallback;
988 }
989
990 // COMMON PLUGIN INFO FUNCS
991 /*
992 char * CALLBACK PSEgetLibName(void)
993 {
994  return _(libraryName);
995 }
996
997 unsigned long CALLBACK PSEgetLibType(void)
998 {
999  return  PSE_LT_SPU;
1000 }
1001
1002 unsigned long CALLBACK PSEgetLibVersion(void)
1003 {
1004  return (1 << 16) | (6 << 8);
1005 }
1006
1007 char * SPUgetLibInfos(void)
1008 {
1009  return _(libraryInfo);
1010 }
1011 */
1012
1013 // vim:shiftwidth=1:expandtab