e289b86196177ba13850d3522dc359e200a9ecba
[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 static int decode_block(int ch)
427 {
428  unsigned char *start;
429  unsigned int nSample;
430  int predict_nr,shift_factor,flags,d,s;
431  int fa,s_1,s_2;
432  int ret = 0;
433
434  s_chan[ch].iSBPos=0;
435
436  start=s_chan[ch].pCurr;                   // set up the current pos
437  if (start == (unsigned char*)-1)          // special "stop" sign
438  {
439   dwChannelOn&=~(1<<ch);                   // -> turn everything off
440   s_chan[ch].bStop=1;
441   s_chan[ch].ADSRX.EnvelopeVol=0;
442   return 0;                                // -> and done for this channel
443  }
444
445  //////////////////////////////////////////// spu irq handler here? mmm... do it later
446
447  s_1=s_chan[ch].s_1;
448  s_2=s_chan[ch].s_2;
449
450  predict_nr=(int)*start;start++;
451  shift_factor=predict_nr&0xf;
452  predict_nr >>= 4;
453  flags=(int)*start;start++;
454
455  // -------------------------------------- // 
456
457  for (nSample=0;nSample<28;start++)      
458  {
459   d=(int)*start;
460   s=((d&0xf)<<12);
461   if(s&0x8000) s|=0xffff0000;
462
463   fa=(s >> shift_factor);
464   fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
465   s_2=s_1;s_1=fa;
466   s=((d & 0xf0) << 8);
467
468   s_chan[ch].SB[nSample++]=fa;
469
470   if(s&0x8000) s|=0xffff0000;
471   fa=(s>>shift_factor);
472   fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
473   s_2=s_1;s_1=fa;
474
475   s_chan[ch].SB[nSample++]=fa;
476  }
477
478  //////////////////////////////////////////// irq check
479
480  if(irqCallback && (spuCtrl&0x40))         // some callback and irq active?
481  {
482   if((pSpuIrq >  start-16 &&              // irq address reached?
483      pSpuIrq <= start) ||
484     ((flags&1) &&                        // special: irq on looping addr, when stop/loop flag is set 
485      (pSpuIrq >  s_chan[ch].pLoop-16 &&
486       pSpuIrq <= s_chan[ch].pLoop)))
487   {
488    irqCallback();                        // -> call main emu
489    ret = 1;
490   }
491  }
492
493  //////////////////////////////////////////// flag handler
494
495  if((flags&4) && (!s_chan[ch].bIgnoreLoop))
496   s_chan[ch].pLoop=start-16;               // loop adress
497
498  if(flags&1)                               // 1: stop/loop
499  {
500   // We play this block out first...
501   //if(!(flags&2))                         // 1+2: do loop... otherwise: stop
502   if(flags!=3 && flags!=7)                 // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example)
503   {
504    start = (unsigned char*)-1;
505   }
506   else
507   {
508    start = s_chan[ch].pLoop;
509   }
510  }
511
512  if (start - spuMemC >= 0x80000)
513   start = (unsigned char*)-1;
514
515  s_chan[ch].pCurr=start;                   // store values for next cycle
516  s_chan[ch].s_1=s_1;
517  s_chan[ch].s_2=s_2;
518
519  return ret;
520 }
521
522 ////////////////////////////////////////////////////////////////////////
523 // MAIN SPU FUNCTION
524 // here is the main job handler... thread, timer or direct func call
525 // basically the whole sound processing is done in this fat func!
526 ////////////////////////////////////////////////////////////////////////
527
528 // 5 ms waiting phase, if buffer is full and no new sound has to get started
529 // .. can be made smaller (smallest val: 1 ms), but bigger waits give
530 // better performance
531
532 #define PAUSE_W 5
533 #define PAUSE_L 5000
534
535 ////////////////////////////////////////////////////////////////////////
536
537 static void *MAINThread(void *arg)
538 {
539  int fa,ns,ns_from,ns_to;
540 #if !defined(_MACOSX) && !defined(__arm__)
541  int voldiv = iVolume;
542 #else
543  const int voldiv = 2;
544 #endif
545  int ch,d;
546  int bIRQReturn=0;
547
548  while(!bEndThread)                                    // until we are shutting down
549   {
550    // ok, at the beginning we are looking if there is
551    // enuff free place in the dsound/oss buffer to
552    // fill in new data, or if there is a new channel to start.
553    // if not, we wait (thread) or return (timer/spuasync)
554    // until enuff free place is available/a new channel gets
555    // started
556
557    if(dwNewChannel)                                    // new channel should start immedately?
558     {                                                  // (at least one bit 0 ... MAXCHANNEL is set?)
559      iSecureStart++;                                   // -> set iSecure
560      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)
561     }
562    else iSecureStart=0;                                // 0: no new channel should start
563
564    while(!iSecureStart && !bEndThread &&               // no new start? no thread end?
565          (SoundGetBytesBuffered()>TESTSIZE))           // and still enuff data in sound buffer?
566     {
567      iSecureStart=0;                                   // reset secure
568
569      if(iUseTimer) return 0;                           // linux no-thread mode? bye
570      usleep(PAUSE_L);                                  // else sleep for x ms (linux)
571
572      if(dwNewChannel) iSecureStart=1;                  // if a new channel kicks in (or, of course, sound buffer runs low), we will leave the loop
573     }
574
575    //--------------------------------------------------// continue from irq handling in timer mode? 
576
577    ns_from=0;
578    ns_to=NSSIZE;
579    ch=0;
580    if(lastch>=0)                                       // will be -1 if no continue is pending
581     {
582      ch=lastch; ns_from=lastns; lastch=-1;             // -> setup all kind of vars to continue
583     }
584
585    //--------------------------------------------------//
586    //- main channel loop                              -// 
587    //--------------------------------------------------//
588     {
589      for(;ch<MAXCHAN;ch++)                             // loop em all... we will collect 1 ms of sound of each playing channel
590       {
591        if(dwNewChannel&(1<<ch)) StartSound(ch);        // start new sound
592        if(!(dwChannelOn&(1<<ch))) continue;            // channel not playing? next
593
594        if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq)   // new psx frequency?
595         VoiceChangeFrequency(ch);
596
597        for(ns=ns_from;ns<ns_to;ns++)                   // loop until 1 ms of data is reached
598         {
599          int sval;
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
631          sval = (MixADSR(ch) * fa) / 1024;  // mix adsr
632
633          if(s_chan[ch].bFMod==2)                       // fmod freq channel
634           iFMod[ns]=sval;                              // -> store 1T sample data, use that to do fmod on next channel
635          else                                          // no fmod freq channel
636           {
637            //////////////////////////////////////////////
638            // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
639
640            SSumLR[ns*2]  +=(sval*s_chan[ch].iLeftVolume)/0x4000L;
641            SSumLR[ns*2+1]+=(sval*s_chan[ch].iRightVolume)/0x4000L;
642
643            //////////////////////////////////////////////
644            // now let us store sound data for reverb    
645
646            if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns,sval);
647           }
648
649          ////////////////////////////////////////////////
650          // ok, go on until 1 ms data of this channel is collected
651
652          s_chan[ch].spos += s_chan[ch].sinc;
653         }
654 ENDX: ;
655       }
656     }
657
658     if(bIRQReturn && iSPUIRQWait)                      // special return for "spu irq - wait for cpu action"
659      {
660       iSpuAsyncWait=1;
661       bIRQReturn=0;
662       if(iUseTimer!=2)
663        { 
664         DWORD dwWatchTime=timeGetTime_spu()+2500;
665
666         while(iSpuAsyncWait && !bEndThread && 
667               timeGetTime_spu()<dwWatchTime)
668             usleep(1000L);
669         continue;
670        }
671       else
672        {
673         return 0;
674        }
675      }
676
677
678   //---------------------------------------------------//
679   //- here we have another 1 ms of sound data
680   //---------------------------------------------------//
681   // mix XA infos (if any)
682
683   MixXA();
684   
685   ///////////////////////////////////////////////////////
686   // mix all channels (including reverb) into one buffer
687
688   for (ns = 0; ns < NSSIZE*2; )
689    {
690     SSumLR[ns] += MixREVERBLeft(ns/2);
691
692     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
693     if (d < -32767) d = -32767; if (d > 32767) d = 32767;
694     *pS++ = d;
695     ns++;
696
697     SSumLR[ns] += MixREVERBRight();
698
699     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
700     if(d < -32767) d = -32767; if(d > 32767) d = 32767;
701     *pS++ = d;
702     ns++;
703    }
704
705   //////////////////////////////////////////////////////                   
706   // special irq handling in the decode buffers (0x0000-0x1000)
707   // we know: 
708   // the decode buffers are located in spu memory in the following way:
709   // 0x0000-0x03ff  CD audio left
710   // 0x0400-0x07ff  CD audio right
711   // 0x0800-0x0bff  Voice 1
712   // 0x0c00-0x0fff  Voice 3
713   // and decoded data is 16 bit for one sample
714   // we assume: 
715   // even if voices 1/3 are off or no cd audio is playing, the internal
716   // play positions will move on and wrap after 0x400 bytes.
717   // Therefore: we just need a pointer from spumem+0 to spumem+3ff, and 
718   // increase this pointer on each sample by 2 bytes. If this pointer
719   // (or 0x400 offsets of this pointer) hits the spuirq address, we generate
720   // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here
721   // in some of Peops timer modes. So: we ignore this option here (for now).
722
723   if(pMixIrq && irqCallback)
724    {
725     for(ns=0;ns<NSSIZE;ns++)
726      {
727       if((spuCtrl&0x40) && pSpuIrq && pSpuIrq<spuMemC+0x1000)                 
728        {
729         for(ch=0;ch<4;ch++)
730          {
731           if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
732            irqCallback();
733          }
734        }
735       pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
736      }
737    }
738
739   InitREVERB();
740
741   // feed the sound
742   // wanna have around 1/60 sec (16.666 ms) updates
743   if (iCycle++ > 16)
744    {
745     SoundFeedStreamData((unsigned char *)pSpuBuffer,
746                         ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer));
747     pS = (short *)pSpuBuffer;
748     iCycle = 0;
749    }
750  }
751
752  // end of big main loop...
753
754  bThreadEnded = 1;
755
756  return 0;
757 }
758
759 // SPU ASYNC... even newer epsxe func
760 //  1 time every 'cycle' cycles... harhar
761
762 void CALLBACK SPUasync(unsigned long cycle)
763 {
764  if(iSpuAsyncWait)
765   {
766    iSpuAsyncWait++;
767    if(iSpuAsyncWait<=16) return;
768    iSpuAsyncWait=0;
769   }
770
771  if(iUseTimer==2)                                      // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode)
772   {
773    if(!bSpuInit) return;                               // -> no init, no call
774
775    MAINThread(0);                                      // -> linux high-compat mode
776
777    // abuse iSpuAsyncWait mechanism to reduce calls to above function
778    // to make it do larger chunks
779    // note: doing it less often than once per frame causes skips
780    iSpuAsyncWait=1;
781   }
782 }
783
784 // SPU UPDATE... new epsxe func
785 //  1 time every 32 hsync lines
786 //  (312/32)x50 in pal
787 //  (262/32)x60 in ntsc
788
789 // since epsxe 1.5.2 (linux) uses SPUupdate, not SPUasync, I will
790 // leave that func in the linux port, until epsxe linux is using
791 // the async function as well
792
793 void CALLBACK SPUupdate(void)
794 {
795  SPUasync(0);
796 }
797
798 // XA AUDIO
799
800 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap)
801 {
802  if(!xap)       return;
803  if(!xap->freq) return;                                // no xa freq ? bye
804
805  FeedXA(xap);                                          // call main XA feeder
806 }
807
808 // CDDA AUDIO
809 void CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
810 {
811  if (!pcm)      return;
812  if (nbytes<=0) return;
813
814  FeedCDDA((unsigned char *)pcm, nbytes);
815 }
816
817 // SETUPTIMER: init of certain buffers and threads/timers
818 void SetupTimer(void)
819 {
820  memset(SSumLR,0,sizeof(SSumLR));                      // init some mixing buffers
821  memset(iFMod,0,NSSIZE*sizeof(int));
822  pS=(short *)pSpuBuffer;                               // setup soundbuffer pointer
823
824  bEndThread=0;                                         // init thread vars
825  bThreadEnded=0; 
826  bSpuInit=1;                                           // flag: we are inited
827
828  if(!iUseTimer)                                        // linux: use thread
829   {
830    pthread_create(&thread, NULL, MAINThread, NULL);
831   }
832 }
833
834 // REMOVETIMER: kill threads/timers
835 void RemoveTimer(void)
836 {
837  bEndThread=1;                                         // raise flag to end thread
838
839  if(!iUseTimer)                                        // linux tread?
840   {
841    int i=0;
842    while(!bThreadEnded && i<2000) {usleep(1000L);i++;} // -> wait until thread has ended
843    if(thread!=(pthread_t)-1) {pthread_cancel(thread);thread=(pthread_t)-1;}  // -> cancel thread anyway
844   }
845
846  bThreadEnded=0;                                       // no more spu is running
847  bSpuInit=0;
848 }
849
850 // SETUPSTREAMS: init most of the spu buffers
851 void SetupStreams(void)
852
853  int i;
854
855  pSpuBuffer=(unsigned char *)malloc(32768);            // alloc mixing buffer
856
857  if(iUseReverb==1) i=88200*2;
858  else              i=NSSIZE*2;
859
860  sRVBStart = (int *)malloc(i*4);                       // alloc reverb buffer
861  memset(sRVBStart,0,i*4);
862  sRVBEnd  = sRVBStart + i;
863  sRVBPlay = sRVBStart;
864
865  XAStart =                                             // alloc xa buffer
866   (uint32_t *)malloc(44100 * sizeof(uint32_t));
867  XAEnd   = XAStart + 44100;
868  XAPlay  = XAStart;
869  XAFeed  = XAStart;
870
871  CDDAStart =                                           // alloc cdda buffer
872   (uint32_t *)malloc(16384 * sizeof(uint32_t));
873  CDDAEnd   = CDDAStart + 16384;
874  CDDAPlay  = CDDAStart;
875  CDDAFeed  = CDDAStart;
876
877  for(i=0;i<MAXCHAN;i++)                                // loop sound channels
878   {
879 // we don't use mutex sync... not needed, would only 
880 // slow us down:
881 //   s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
882    s_chan[i].ADSRX.SustainLevel = 0xf;                 // -> init sustain
883    s_chan[i].pLoop=spuMemC;
884    s_chan[i].pStart=spuMemC;
885    s_chan[i].pCurr=spuMemC;
886   }
887
888   pMixIrq=spuMemC;                                     // enable decoded buffer irqs by setting the address
889 }
890
891 // REMOVESTREAMS: free most buffer
892 void RemoveStreams(void)
893
894  free(pSpuBuffer);                                     // free mixing buffer
895  pSpuBuffer = NULL;
896  free(sRVBStart);                                      // free reverb buffer
897  sRVBStart = NULL;
898  free(XAStart);                                        // free XA buffer
899  XAStart = NULL;
900  free(CDDAStart);                                      // free CDDA buffer
901  CDDAStart = NULL;
902 }
903
904 // INIT/EXIT STUFF
905
906 // SPUINIT: this func will be called first by the main emu
907 long CALLBACK SPUinit(void)
908 {
909  spuMemC = (unsigned char *)spuMem;                    // just small setup
910  memset((void *)&rvb, 0, sizeof(REVERBInfo));
911  InitADSR();
912
913  iVolume = 3;
914  iReverbOff = -1;
915  spuIrq = 0;
916  spuAddr = 0xffffffff;
917  bEndThread = 0;
918  bThreadEnded = 0;
919  spuMemC = (unsigned char *)spuMem;
920  pMixIrq = 0;
921  memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
922  pSpuIrq = 0;
923  //iSPUIRQWait = 0;
924  lastch = -1;
925
926  //ReadConfigSPU();                                      // read user stuff
927  SetupStreams();                                       // prepare streaming
928
929  return 0;
930 }
931
932 // SPUOPEN: called by main emu after init
933 long CALLBACK SPUopen(void)
934 {
935  if (bSPUIsOpen) return 0;                             // security for some stupid main emus
936
937  SetupSound();                                         // setup sound (before init!)
938  SetupTimer();                                         // timer for feeding data
939
940  bSPUIsOpen = 1;
941
942  return PSE_SPU_ERR_SUCCESS;
943 }
944
945 // SPUCLOSE: called before shutdown
946 long CALLBACK SPUclose(void)
947 {
948  if (!bSPUIsOpen) return 0;                            // some security
949
950  bSPUIsOpen = 0;                                       // no more open
951
952  RemoveTimer();                                        // no more feeding
953  RemoveSound();                                        // no more sound handling
954
955  return 0;
956 }
957
958 // SPUSHUTDOWN: called by main emu on final exit
959 long CALLBACK SPUshutdown(void)
960 {
961  SPUclose();
962  RemoveStreams();                                      // no more streaming
963
964  return 0;
965 }
966
967 // SPUTEST: we don't test, we are always fine ;)
968 long CALLBACK SPUtest(void)
969 {
970  return 0;
971 }
972
973 // SPUCONFIGURE: call config dialog
974 long CALLBACK SPUconfigure(void)
975 {
976 #ifdef _MACOSX
977  DoConfiguration();
978 #else
979 // StartCfgTool("CFG");
980 #endif
981  return 0;
982 }
983
984 // SPUABOUT: show about window
985 void CALLBACK SPUabout(void)
986 {
987 #ifdef _MACOSX
988  DoAbout();
989 #else
990 // StartCfgTool("ABOUT");
991 #endif
992 }
993
994 // SETUP CALLBACKS
995 // this functions will be called once, 
996 // passes a callback that should be called on SPU-IRQ/cdda volume change
997 void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
998 {
999  irqCallback = callback;
1000 }
1001
1002 void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
1003 {
1004  cddavCallback = CDDAVcallback;
1005 }
1006
1007 // COMMON PLUGIN INFO FUNCS
1008 /*
1009 char * CALLBACK PSEgetLibName(void)
1010 {
1011  return _(libraryName);
1012 }
1013
1014 unsigned long CALLBACK PSEgetLibType(void)
1015 {
1016  return  PSE_LT_SPU;
1017 }
1018
1019 unsigned long CALLBACK PSEgetLibVersion(void)
1020 {
1021  return (1 << 16) | (6 << 8);
1022 }
1023
1024 char * SPUgetLibInfos(void)
1025 {
1026  return _(libraryInfo);
1027 }
1028 */
1029
1030 // vim:shiftwidth=1:expandtab