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