dfsound: merge shalma's suggestions
[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 && flags!=7)               // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example)
590                   || s_chan[ch].pLoop==NULL)           // and checking if pLoop is set avoids crashes, yeah
591                 {
592                  start = (unsigned char*)-1;
593                  // Actua Soccer 2, Jungle Book, other games that check for this condition
594                  s_chan[ch].ADSRX.EnvelopeVol = 0;
595                 }
596                else
597                 {
598                  start = s_chan[ch].pLoop;
599                 }
600               }
601
602              if (start - spuMemC >= 0x80000)
603               start = (unsigned char*)-1;
604
605              s_chan[ch].pCurr=start;                   // store values for next cycle
606              s_chan[ch].s_1=s_1;
607              s_chan[ch].s_2=s_2;
608             }
609
610            fa=s_chan[ch].SB[s_chan[ch].iSBPos++];      // get sample data
611
612            StoreInterpolationVal(ch,fa);               // store val for later interpolation
613
614            s_chan[ch].spos -= 0x10000L;
615           }
616
617          if(s_chan[ch].bNoise)
618               fa=iGetNoiseVal(ch);                     // get noise val
619          else fa=iGetInterpolationVal(ch);             // get sample val
620
621          sval = (MixADSR(ch) * fa) / 1023;  // mix adsr
622
623          if(s_chan[ch].bFMod==2)                       // fmod freq channel
624           iFMod[ns]=sval;                              // -> store 1T sample data, use that to do fmod on next channel
625          else                                          // no fmod freq channel
626           {
627            //////////////////////////////////////////////
628            // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
629
630            SSumLR[ns*2]  +=(sval*s_chan[ch].iLeftVolume)/0x4000L;
631            SSumLR[ns*2+1]+=(sval*s_chan[ch].iRightVolume)/0x4000L;
632
633            //////////////////////////////////////////////
634            // now let us store sound data for reverb    
635
636            if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns,sval);
637           }
638
639          ////////////////////////////////////////////////
640          // ok, go on until 1 ms data of this channel is collected
641
642          s_chan[ch].spos += s_chan[ch].sinc;
643         }
644 ENDX:   ;
645       }
646     }
647
648     if(bIRQReturn)                            // special return for "spu irq - wait for cpu action"
649      {
650       bIRQReturn=0;
651       if(iUseTimer!=2)
652        { 
653         DWORD dwWatchTime=timeGetTime_spu()+2500;
654
655         while(iSpuAsyncWait && !bEndThread && 
656               timeGetTime_spu()<dwWatchTime)
657             usleep(1000L);
658         continue;
659        }
660       else
661        {
662         return 0;
663        }
664      }
665
666
667   //---------------------------------------------------//
668   //- here we have another 1 ms of sound data
669   //---------------------------------------------------//
670   // mix XA infos (if any)
671
672   MixXA();
673   
674   ///////////////////////////////////////////////////////
675   // mix all channels (including reverb) into one buffer
676
677   for (ns = 0; ns < NSSIZE*2; )
678    {
679     SSumLR[ns] += MixREVERBLeft(ns/2);
680
681     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
682     if (d < -32767) d = -32767; if (d > 32767) d = 32767;
683     *pS++ = d;
684     ns++;
685
686     SSumLR[ns] += MixREVERBRight();
687
688     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
689     if(d < -32767) d = -32767; if(d > 32767) d = 32767;
690     *pS++ = d;
691     ns++;
692    }
693
694   //////////////////////////////////////////////////////                   
695   // special irq handling in the decode buffers (0x0000-0x1000)
696   // we know: 
697   // the decode buffers are located in spu memory in the following way:
698   // 0x0000-0x03ff  CD audio left
699   // 0x0400-0x07ff  CD audio right
700   // 0x0800-0x0bff  Voice 1
701   // 0x0c00-0x0fff  Voice 3
702   // and decoded data is 16 bit for one sample
703   // we assume: 
704   // even if voices 1/3 are off or no cd audio is playing, the internal
705   // play positions will move on and wrap after 0x400 bytes.
706   // Therefore: we just need a pointer from spumem+0 to spumem+3ff, and 
707   // increase this pointer on each sample by 2 bytes. If this pointer
708   // (or 0x400 offsets of this pointer) hits the spuirq address, we generate
709   // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here
710   // in some of Peops timer modes. So: we ignore this option here (for now).
711
712   if(pMixIrq && irqCallback)
713    {
714     for(ns=0;ns<NSSIZE;ns++)
715      {
716       if((spuCtrl&0x40) && pSpuIrq && pSpuIrq<spuMemC+0x1000)                 
717        {
718         for(ch=0;ch<4;ch++)
719          {
720           if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
721            irqCallback();
722          }
723        }
724       pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
725      }
726    }
727
728   InitREVERB();
729
730   // feed the sound
731   // wanna have around 1/60 sec (16.666 ms) updates
732   if (iCycle++ > 16)
733    {
734     SoundFeedStreamData((unsigned char *)pSpuBuffer,
735                         ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer));
736     pS = (short *)pSpuBuffer;
737     iCycle = 0;
738    }
739  }
740
741  // end of big main loop...
742
743  bThreadEnded = 1;
744
745  return 0;
746 }
747
748 // SPU ASYNC... even newer epsxe func
749 //  1 time every 'cycle' cycles... harhar
750
751 void CALLBACK SPUasync(unsigned long cycle)
752 {
753  if(iSpuAsyncWait)
754   {
755    iSpuAsyncWait++;
756    if(iSpuAsyncWait<=16) return;
757    iSpuAsyncWait=0;
758   }
759
760  if(iUseTimer==2)                                      // special mode, only used in Linux by this spu (or if you enable the experimental Windows mode)
761   {
762    if(!bSpuInit) return;                               // -> no init, no call
763
764    MAINThread(0);                                      // -> linux high-compat mode
765
766    // abuse iSpuAsyncWait mechanism to reduce calls to above function
767    // to make it do larger chunks
768    // note: doing it less often than once per frame causes skips
769    iSpuAsyncWait=1;
770   }
771 }
772
773 // SPU UPDATE... new epsxe func
774 //  1 time every 32 hsync lines
775 //  (312/32)x50 in pal
776 //  (262/32)x60 in ntsc
777
778 // since epsxe 1.5.2 (linux) uses SPUupdate, not SPUasync, I will
779 // leave that func in the linux port, until epsxe linux is using
780 // the async function as well
781
782 void CALLBACK SPUupdate(void)
783 {
784  SPUasync(0);
785 }
786
787 // XA AUDIO
788
789 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap)
790 {
791  if(!xap)       return;
792  if(!xap->freq) return;                                // no xa freq ? bye
793
794  FeedXA(xap);                                          // call main XA feeder
795 }
796
797 // CDDA AUDIO
798 void CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
799 {
800  if (!pcm)      return;
801  if (nbytes<=0) return;
802
803  FeedCDDA((unsigned char *)pcm, nbytes);
804 }
805
806 // SETUPTIMER: init of certain buffers and threads/timers
807 void SetupTimer(void)
808 {
809  memset(SSumLR,0,sizeof(SSumLR));                      // init some mixing buffers
810  memset(iFMod,0,NSSIZE*sizeof(int));
811  pS=(short *)pSpuBuffer;                               // setup soundbuffer pointer
812
813  bEndThread=0;                                         // init thread vars
814  bThreadEnded=0; 
815  bSpuInit=1;                                           // flag: we are inited
816
817  if(!iUseTimer)                                        // linux: use thread
818   {
819    pthread_create(&thread, NULL, MAINThread, NULL);
820   }
821 }
822
823 // REMOVETIMER: kill threads/timers
824 void RemoveTimer(void)
825 {
826  bEndThread=1;                                         // raise flag to end thread
827
828  if(!iUseTimer)                                        // linux tread?
829   {
830    int i=0;
831    while(!bThreadEnded && i<2000) {usleep(1000L);i++;} // -> wait until thread has ended
832    if(thread!=(pthread_t)-1) {pthread_cancel(thread);thread=(pthread_t)-1;}  // -> cancel thread anyway
833   }
834
835  bThreadEnded=0;                                       // no more spu is running
836  bSpuInit=0;
837 }
838
839 // SETUPSTREAMS: init most of the spu buffers
840 void SetupStreams(void)
841
842  int i;
843
844  pSpuBuffer=(unsigned char *)malloc(32768);            // alloc mixing buffer
845
846  if(iUseReverb==1) i=88200*2;
847  else              i=NSSIZE*2;
848
849  sRVBStart = (int *)malloc(i*4);                       // alloc reverb buffer
850  memset(sRVBStart,0,i*4);
851  sRVBEnd  = sRVBStart + i;
852  sRVBPlay = sRVBStart;
853
854  XAStart =                                             // alloc xa buffer
855   (uint32_t *)malloc(44100 * sizeof(uint32_t));
856  XAEnd   = XAStart + 44100;
857  XAPlay  = XAStart;
858  XAFeed  = XAStart;
859
860  CDDAStart =                                           // alloc cdda buffer
861   (uint32_t *)malloc(16384 * sizeof(uint32_t));
862  CDDAEnd   = CDDAStart + 16384;
863  CDDAPlay  = CDDAStart;
864  CDDAFeed  = CDDAStart;
865
866  for(i=0;i<MAXCHAN;i++)                                // loop sound channels
867   {
868 // we don't use mutex sync... not needed, would only 
869 // slow us down:
870 //   s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
871    s_chan[i].ADSRX.SustainLevel = 0xf;                 // -> init sustain
872    s_chan[i].pLoop=spuMemC;
873    s_chan[i].pStart=spuMemC;
874    s_chan[i].pCurr=spuMemC;
875   }
876
877   pMixIrq=spuMemC;                                     // enable decoded buffer irqs by setting the address
878 }
879
880 // REMOVESTREAMS: free most buffer
881 void RemoveStreams(void)
882
883  free(pSpuBuffer);                                     // free mixing buffer
884  pSpuBuffer = NULL;
885  free(sRVBStart);                                      // free reverb buffer
886  sRVBStart = NULL;
887  free(XAStart);                                        // free XA buffer
888  XAStart = NULL;
889  free(CDDAStart);                                      // free CDDA buffer
890  CDDAStart = NULL;
891 }
892
893 // INIT/EXIT STUFF
894
895 // SPUINIT: this func will be called first by the main emu
896 long CALLBACK SPUinit(void)
897 {
898  spuMemC = (unsigned char *)spuMem;                    // just small setup
899  memset((void *)&rvb, 0, sizeof(REVERBInfo));
900  InitADSR();
901
902  iVolume = 3;
903  iReverbOff = -1;
904  spuIrq = 0;
905  spuAddr = 0xffffffff;
906  bEndThread = 0;
907  bThreadEnded = 0;
908  spuMemC = (unsigned char *)spuMem;
909  pMixIrq = 0;
910  memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
911  pSpuIrq = 0;
912  //iSPUIRQWait = 0;
913  lastch = -1;
914
915  //ReadConfigSPU();                                      // read user stuff
916  SetupStreams();                                       // prepare streaming
917
918  return 0;
919 }
920
921 // SPUOPEN: called by main emu after init
922 long CALLBACK SPUopen(void)
923 {
924  if (bSPUIsOpen) return 0;                             // security for some stupid main emus
925
926  SetupSound();                                         // setup sound (before init!)
927  SetupTimer();                                         // timer for feeding data
928
929  bSPUIsOpen = 1;
930
931  return PSE_SPU_ERR_SUCCESS;
932 }
933
934 // SPUCLOSE: called before shutdown
935 long CALLBACK SPUclose(void)
936 {
937  if (!bSPUIsOpen) return 0;                            // some security
938
939  bSPUIsOpen = 0;                                       // no more open
940
941  RemoveTimer();                                        // no more feeding
942  RemoveSound();                                        // no more sound handling
943
944  return 0;
945 }
946
947 // SPUSHUTDOWN: called by main emu on final exit
948 long CALLBACK SPUshutdown(void)
949 {
950  SPUclose();
951  RemoveStreams();                                      // no more streaming
952
953  return 0;
954 }
955
956 // SPUTEST: we don't test, we are always fine ;)
957 long CALLBACK SPUtest(void)
958 {
959  return 0;
960 }
961
962 // SPUCONFIGURE: call config dialog
963 long CALLBACK SPUconfigure(void)
964 {
965 #ifdef _MACOSX
966  DoConfiguration();
967 #else
968 // StartCfgTool("CFG");
969 #endif
970  return 0;
971 }
972
973 // SPUABOUT: show about window
974 void CALLBACK SPUabout(void)
975 {
976 #ifdef _MACOSX
977  DoAbout();
978 #else
979 // StartCfgTool("ABOUT");
980 #endif
981 }
982
983 // SETUP CALLBACKS
984 // this functions will be called once, 
985 // passes a callback that should be called on SPU-IRQ/cdda volume change
986 void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
987 {
988  irqCallback = callback;
989 }
990
991 void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
992 {
993  cddavCallback = CDDAVcallback;
994 }
995
996 // COMMON PLUGIN INFO FUNCS
997 /*
998 char * CALLBACK PSEgetLibName(void)
999 {
1000  return _(libraryName);
1001 }
1002
1003 unsigned long CALLBACK PSEgetLibType(void)
1004 {
1005  return  PSE_LT_SPU;
1006 }
1007
1008 unsigned long CALLBACK PSEgetLibVersion(void)
1009 {
1010  return (1 << 16) | (6 << 8);
1011 }
1012
1013 char * SPUgetLibInfos(void)
1014 {
1015  return _(libraryInfo);
1016 }
1017 */
1018
1019 // vim:shiftwidth=1:expandtab