pcsxr-1.9.92
[pcsx_rearmed.git] / plugins / dfsound / xa.c
1 /***************************************************************************
2                             xa.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 #define _IN_XA
20 #include <stdint.h>
21
22 // will be included from spu.c
23 #ifdef _IN_SPU
24
25 ////////////////////////////////////////////////////////////////////////
26 // XA GLOBALS
27 ////////////////////////////////////////////////////////////////////////
28
29 xa_decode_t   * xapGlobal=0;
30
31 uint32_t * XAFeed  = NULL;
32 uint32_t * XAPlay  = NULL;
33 uint32_t * XAStart = NULL;
34 uint32_t * XAEnd   = NULL;
35
36 uint32_t   XARepeat  = 0;
37 uint32_t   XALastVal = 0;
38
39 uint32_t * CDDAFeed  = NULL;
40 uint32_t * CDDAPlay  = NULL;
41 uint32_t * CDDAStart = NULL;
42 uint32_t * CDDAEnd   = NULL;
43
44 int             iLeftXAVol  = 32767;
45 int             iRightXAVol = 32767;
46
47 static int gauss_ptr = 0;
48 static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0};
49
50 #define gvall0 gauss_window[gauss_ptr]
51 #define gvall(x) gauss_window[(gauss_ptr+x)&3]
52 #define gvalr0 gauss_window[4+gauss_ptr]
53 #define gvalr(x) gauss_window[4+((gauss_ptr+x)&3)]
54
55 ////////////////////////////////////////////////////////////////////////
56 // MIX XA & CDDA
57 ////////////////////////////////////////////////////////////////////////
58
59 INLINE void MixXA(void)
60 {
61  int ns;
62  uint32_t l;
63
64  for(ns=0;ns<NSSIZE && XAPlay!=XAFeed;ns++)
65   {
66    XALastVal=*XAPlay++;
67    if(XAPlay==XAEnd) XAPlay=XAStart;
68 #ifdef XA_HACK
69    SSumL[ns]+=(((short)(XALastVal&0xffff))       * iLeftXAVol)/32768;
70    SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32768;
71 #else
72    SSumL[ns]+=(((short)(XALastVal&0xffff))       * iLeftXAVol)/32767;
73    SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32767;
74 #endif
75   }
76
77  if(XAPlay==XAFeed && XARepeat)
78   {
79    XARepeat--;
80    for(;ns<NSSIZE;ns++)
81     {
82 #ifdef XA_HACK
83      SSumL[ns]+=(((short)(XALastVal&0xffff))       * iLeftXAVol)/32768;
84      SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32768;
85 #else
86      SSumL[ns]+=(((short)(XALastVal&0xffff))       * iLeftXAVol)/32767;
87      SSumR[ns]+=(((short)((XALastVal>>16)&0xffff)) * iRightXAVol)/32767;
88 #endif
89     }
90   }
91
92  for(ns=0;ns<NSSIZE && CDDAPlay!=CDDAFeed && (CDDAPlay!=CDDAEnd-1||CDDAFeed!=CDDAStart);ns++)
93   {
94    l=*CDDAPlay++;
95    if(CDDAPlay==CDDAEnd) CDDAPlay=CDDAStart;
96    SSumL[ns]+=(((short)(l&0xffff))       * iLeftXAVol)/32767;
97    SSumR[ns]+=(((short)((l>>16)&0xffff)) * iRightXAVol)/32767;
98   }
99 }
100
101 ////////////////////////////////////////////////////////////////////////
102 // small linux time helper... only used for watchdog
103 ////////////////////////////////////////////////////////////////////////
104
105 unsigned long timeGetTime_spu()
106 {
107  struct timeval tv;
108  gettimeofday(&tv, 0);                                 // well, maybe there are better ways
109  return tv.tv_sec * 1000 + tv.tv_usec/1000;            // to do that, but at least it works
110 }
111
112 ////////////////////////////////////////////////////////////////////////
113 // FEED XA 
114 ////////////////////////////////////////////////////////////////////////
115
116 INLINE void FeedXA(xa_decode_t *xap)
117 {
118  int sinc,spos,i,iSize,iPlace,vl,vr;
119
120  if(!bSPUIsOpen) return;
121
122  xapGlobal = xap;                                      // store info for save states
123  XARepeat  = 100;                                      // set up repeat
124
125 #ifdef XA_HACK
126  iSize=((45500*xap->nsamples)/xap->freq);              // get size
127 #else
128  iSize=((44100*xap->nsamples)/xap->freq);              // get size
129 #endif
130  if(!iSize) return;                                    // none? bye
131
132  if(XAFeed<XAPlay) iPlace=XAPlay-XAFeed;               // how much space in my buf?
133  else              iPlace=(XAEnd-XAFeed) + (XAPlay-XAStart);
134
135  if(iPlace==0) return;                                 // no place at all
136
137  //----------------------------------------------------//
138  if(iXAPitch)                                          // pitch change option?
139   {
140    static DWORD dwLT=0;
141    static DWORD dwFPS=0;
142    static int   iFPSCnt=0;
143    static int   iLastSize=0;
144    static DWORD dwL1=0;
145    DWORD dw=timeGetTime_spu(),dw1,dw2;
146
147    iPlace=iSize;
148
149    dwFPS+=dw-dwLT;iFPSCnt++;
150
151    dwLT=dw;
152                                        
153    if(iFPSCnt>=10)
154     {
155      if(!dwFPS) dwFPS=1;
156      dw1=1000000/dwFPS; 
157      if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1;
158      else dwL1=dw1;
159      dw2=(xap->freq*100/xap->nsamples);
160      if((!dw1)||((dw2+100)>=dw1)) iLastSize=0;
161      else
162       {
163        iLastSize=iSize*dw2/dw1;
164        if(iLastSize>iPlace) iLastSize=iPlace;
165        iSize=iLastSize;
166       }
167      iFPSCnt=0;dwFPS=0;
168     }
169    else
170     {
171      if(iLastSize) iSize=iLastSize;
172     }
173   }
174  //----------------------------------------------------//
175
176  spos=0x10000L;
177  sinc = (xap->nsamples << 16) / iSize;                 // calc freq by num / size
178
179  if(xap->stereo)
180 {
181    uint32_t * pS=(uint32_t *)xap->pcm;
182    uint32_t l=0;
183
184    if(iXAPitch)
185     {
186      int32_t l1,l2;short s;
187      for(i=0;i<iSize;i++)
188       {
189        if(iUseInterpolation==2) 
190         {
191          while(spos>=0x10000L)
192           {
193            l = *pS++;
194            gauss_window[gauss_ptr] = (short)LOWORD(l);
195            gauss_window[4+gauss_ptr] = (short)HIWORD(l);
196            gauss_ptr = (gauss_ptr+1) & 3;
197            spos -= 0x10000L;
198           }
199          vl = (spos >> 6) & ~3;
200          vr=(gauss[vl]*gvall0)&~2047;
201          vr+=(gauss[vl+1]*gvall(1))&~2047;
202          vr+=(gauss[vl+2]*gvall(2))&~2047;
203          vr+=(gauss[vl+3]*gvall(3))&~2047;
204          l= (vr >> 11) & 0xffff;
205          vr=(gauss[vl]*gvalr0)&~2047;
206          vr+=(gauss[vl+1]*gvalr(1))&~2047;
207          vr+=(gauss[vl+2]*gvalr(2))&~2047;
208          vr+=(gauss[vl+3]*gvalr(3))&~2047;
209          l |= vr << 5;
210         }
211        else
212         {
213          while(spos>=0x10000L)
214           {
215            l = *pS++;
216            spos -= 0x10000L;
217           }
218         }
219
220        s=(short)LOWORD(l);
221        l1=s;
222        l1=(l1*iPlace)/iSize;
223        if(l1<-32767) l1=-32767;
224        if(l1> 32767) l1=32767;
225        s=(short)HIWORD(l);
226        l2=s;
227        l2=(l2*iPlace)/iSize;
228        if(l2<-32767) l2=-32767;
229        if(l2> 32767) l2=32767;
230        l=(l1&0xffff)|(l2<<16);
231
232        *XAFeed++=l;
233
234        if(XAFeed==XAEnd) XAFeed=XAStart;
235        if(XAFeed==XAPlay) 
236         {
237          if(XAPlay!=XAStart) XAFeed=XAPlay-1;
238          break;
239         }
240
241        spos += sinc;
242       }
243     }
244    else
245     {
246      for(i=0;i<iSize;i++)
247       {
248        if(iUseInterpolation==2) 
249         {
250          while(spos>=0x10000L)
251           {
252            l = *pS++;
253            gauss_window[gauss_ptr] = (short)LOWORD(l);
254            gauss_window[4+gauss_ptr] = (short)HIWORD(l);
255            gauss_ptr = (gauss_ptr+1) & 3;
256            spos -= 0x10000L;
257           }
258          vl = (spos >> 6) & ~3;
259          vr=(gauss[vl]*gvall0)&~2047;
260          vr+=(gauss[vl+1]*gvall(1))&~2047;
261          vr+=(gauss[vl+2]*gvall(2))&~2047;
262          vr+=(gauss[vl+3]*gvall(3))&~2047;
263          l= (vr >> 11) & 0xffff;
264          vr=(gauss[vl]*gvalr0)&~2047;
265          vr+=(gauss[vl+1]*gvalr(1))&~2047;
266          vr+=(gauss[vl+2]*gvalr(2))&~2047;
267          vr+=(gauss[vl+3]*gvalr(3))&~2047;
268          l |= vr << 5;
269         }
270        else
271         {
272          while(spos>=0x10000L)
273           {
274            l = *pS++;
275            spos -= 0x10000L;
276           }
277         }
278
279        *XAFeed++=l;
280
281        if(XAFeed==XAEnd) XAFeed=XAStart;
282        if(XAFeed==XAPlay) 
283         {
284          if(XAPlay!=XAStart) XAFeed=XAPlay-1;
285          break;
286         }
287
288        spos += sinc;
289       }
290     }
291   }
292  else
293   {
294    unsigned short * pS=(unsigned short *)xap->pcm;
295    uint32_t l;short s=0;
296
297    if(iXAPitch)
298     {
299      int32_t l1;
300      for(i=0;i<iSize;i++)
301       {
302        if(iUseInterpolation==2) 
303         {
304          while(spos>=0x10000L)
305           {
306            gauss_window[gauss_ptr] = (short)*pS++;
307            gauss_ptr = (gauss_ptr+1) & 3;
308            spos -= 0x10000L;
309           }
310          vl = (spos >> 6) & ~3;
311          vr=(gauss[vl]*gvall0)&~2047;
312          vr+=(gauss[vl+1]*gvall(1))&~2047;
313          vr+=(gauss[vl+2]*gvall(2))&~2047;
314          vr+=(gauss[vl+3]*gvall(3))&~2047;
315          l1=s= vr >> 11;
316          l1 &= 0xffff;
317         }
318        else
319         {
320          while(spos>=0x10000L)
321           {
322            s = *pS++;
323            spos -= 0x10000L;
324           }
325          l1=s;
326         }
327
328        l1=(l1*iPlace)/iSize;
329        if(l1<-32767) l1=-32767;
330        if(l1> 32767) l1=32767;
331        l=(l1&0xffff)|(l1<<16);
332        *XAFeed++=l;
333
334        if(XAFeed==XAEnd) XAFeed=XAStart;
335        if(XAFeed==XAPlay) 
336         {
337          if(XAPlay!=XAStart) XAFeed=XAPlay-1;
338          break;
339         }
340
341        spos += sinc;
342       }
343     }
344    else
345     {
346      for(i=0;i<iSize;i++)
347       {
348        if(iUseInterpolation==2) 
349         {
350          while(spos>=0x10000L)
351           {
352            gauss_window[gauss_ptr] = (short)*pS++;
353            gauss_ptr = (gauss_ptr+1) & 3;
354            spos -= 0x10000L;
355           }
356          vl = (spos >> 6) & ~3;
357          vr=(gauss[vl]*gvall0)&~2047;
358          vr+=(gauss[vl+1]*gvall(1))&~2047;
359          vr+=(gauss[vl+2]*gvall(2))&~2047;
360          vr+=(gauss[vl+3]*gvall(3))&~2047;
361          l=s= vr >> 11;
362          l &= 0xffff;
363         }
364        else
365         {
366          while(spos>=0x10000L)
367           {
368            s = *pS++;
369            spos -= 0x10000L;
370           }
371          l=s;
372         }
373
374        *XAFeed++=(l|(l<<16));
375
376        if(XAFeed==XAEnd) XAFeed=XAStart;
377        if(XAFeed==XAPlay) 
378         {
379          if(XAPlay!=XAStart) XAFeed=XAPlay-1;
380          break;
381         }
382
383        spos += sinc;
384       }
385     }
386   }
387 }
388
389 ////////////////////////////////////////////////////////////////////////
390 // FEED CDDA
391 ////////////////////////////////////////////////////////////////////////
392
393 INLINE void FeedCDDA(unsigned char *pcm, int nBytes)
394 {
395  while(nBytes>0)
396   {
397    if(CDDAFeed==CDDAEnd) CDDAFeed=CDDAStart;
398    while(CDDAFeed==CDDAPlay-1||
399          (CDDAFeed==CDDAEnd-1&&CDDAPlay==CDDAStart))
400    {
401     if (!iUseTimer) usleep(1000);
402     else return;
403    }
404    *CDDAFeed++=(*pcm | (*(pcm+1)<<8) | (*(pcm+2)<<16) | (*(pcm+3)<<24));
405    nBytes-=4;
406    pcm+=4;
407   }
408 }
409
410 #endif