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