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