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