patch up some savestate issues
[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 void FeedXA(const xa_decode_t *xap)
134 {
135  int sinc,spos,i,iSize,iPlace,vl,vr;
136
137  if(!spu.bSPUIsOpen) return;
138
139  spu.XARepeat  = 3;                                    // set up repeat
140
141 #if 0//def XA_HACK
142  iSize=((45500*xap->nsamples)/xap->freq);              // get size
143 #else
144  iSize=((44100*xap->nsamples)/xap->freq);              // get size
145 #endif
146  if(!iSize) return;                                    // none? bye
147
148  if(spu.XAFeed<spu.XAPlay) iPlace=spu.XAPlay-spu.XAFeed; // how much space in my buf?
149  else              iPlace=(spu.XAEnd-spu.XAFeed) + (spu.XAPlay-spu.XAStart);
150
151  if(iPlace==0) return;                                 // no place at all
152
153  //----------------------------------------------------//
154 #if 0
155  if(spu_config.iXAPitch)                               // pitch change option?
156   {
157    static DWORD dwLT=0;
158    static DWORD dwFPS=0;
159    static int   iFPSCnt=0;
160    static int   iLastSize=0;
161    static DWORD dwL1=0;
162    DWORD dw=timeGetTime_spu(),dw1,dw2;
163
164    iPlace=iSize;
165
166    dwFPS+=dw-dwLT;iFPSCnt++;
167
168    dwLT=dw;
169                                        
170    if(iFPSCnt>=10)
171     {
172      if(!dwFPS) dwFPS=1;
173      dw1=1000000/dwFPS; 
174      if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1;
175      else dwL1=dw1;
176      dw2=(xap->freq*100/xap->nsamples);
177      if((!dw1)||((dw2+100)>=dw1)) iLastSize=0;
178      else
179       {
180        iLastSize=iSize*dw2/dw1;
181        if(iLastSize>iPlace) iLastSize=iPlace;
182        iSize=iLastSize;
183       }
184      iFPSCnt=0;dwFPS=0;
185     }
186    else
187     {
188      if(iLastSize) iSize=iLastSize;
189     }
190   }
191 #endif
192  //----------------------------------------------------//
193
194  spos=0x10000L;
195  sinc = (xap->nsamples << 16) / iSize;                 // calc freq by num / size
196
197  if(xap->stereo)
198 {
199    uint32_t * pS=(uint32_t *)xap->pcm;
200    uint32_t l=0;
201
202 #if 0
203    if(spu_config.iXAPitch)
204     {
205      int32_t l1,l2;short s;
206      for(i=0;i<iSize;i++)
207       {
208        if(spu_config.iUseInterpolation==2)
209         {
210          while(spos>=0x10000L)
211           {
212            l = *pS++;
213            gauss_window[gauss_ptr] = (short)LOWORD(l);
214            gauss_window[4+gauss_ptr] = (short)HIWORD(l);
215            gauss_ptr = (gauss_ptr+1) & 3;
216            spos -= 0x10000L;
217           }
218          vl = (spos >> 6) & ~3;
219          vr=(gauss[vl]*gvall0) >> 15;
220          vr+=(gauss[vl+1]*gvall(1)) >> 15;
221          vr+=(gauss[vl+2]*gvall(2)) >> 15;
222          vr+=(gauss[vl+3]*gvall(3)) >> 15;
223          l= vr & 0xffff;
224          vr=(gauss[vl]*gvalr0) >> 15;
225          vr+=(gauss[vl+1]*gvalr(1)) >> 15;
226          vr+=(gauss[vl+2]*gvalr(2)) >> 15;
227          vr+=(gauss[vl+3]*gvalr(3)) >> 15;
228          l |= vr << 16;
229         }
230        else
231         {
232          while(spos>=0x10000L)
233           {
234            l = *pS++;
235            spos -= 0x10000L;
236           }
237         }
238
239        s=(short)LOWORD(l);
240        l1=s;
241        l1=(l1*iPlace)/iSize;
242        ssat32_to_16(l1);
243        s=(short)HIWORD(l);
244        l2=s;
245        l2=(l2*iPlace)/iSize;
246        ssat32_to_16(l2);
247        l=(l1&0xffff)|(l2<<16);
248
249        *spu.XAFeed++=l;
250
251        if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
252        if(spu.XAFeed==spu.XAPlay)
253         {
254          if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
255          break;
256         }
257
258        spos += sinc;
259       }
260     }
261    else
262 #endif
263     {
264      for(i=0;i<iSize;i++)
265       {
266        if(spu_config.iUseInterpolation==2)
267         {
268          while(spos>=0x10000L)
269           {
270            l = *pS++;
271            gauss_window[gauss_ptr] = (short)LOWORD(l);
272            gauss_window[4+gauss_ptr] = (short)HIWORD(l);
273            gauss_ptr = (gauss_ptr+1) & 3;
274            spos -= 0x10000L;
275           }
276          vl = (spos >> 6) & ~3;
277          vr=(gauss[vl]*gvall0) >> 15;
278          vr+=(gauss[vl+1]*gvall(1)) >> 15;
279          vr+=(gauss[vl+2]*gvall(2)) >> 15;
280          vr+=(gauss[vl+3]*gvall(3)) >> 15;
281          l= vr & 0xffff;
282          vr=(gauss[vl]*gvalr0) >> 15;
283          vr+=(gauss[vl+1]*gvalr(1)) >> 15;
284          vr+=(gauss[vl+2]*gvalr(2)) >> 15;
285          vr+=(gauss[vl+3]*gvalr(3)) >> 15;
286          l |= vr << 16;
287         }
288        else
289         {
290          while(spos>=0x10000L)
291           {
292            l = *pS++;
293            spos -= 0x10000L;
294           }
295         }
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   }
310  else
311   {
312    unsigned short * pS=(unsigned short *)xap->pcm;
313    uint32_t l;short s=0;
314
315 #if 0
316    if(spu_config.iXAPitch)
317     {
318      int32_t l1;
319      for(i=0;i<iSize;i++)
320       {
321        if(spu_config.iUseInterpolation==2)
322         {
323          while(spos>=0x10000L)
324           {
325            gauss_window[gauss_ptr] = (short)*pS++;
326            gauss_ptr = (gauss_ptr+1) & 3;
327            spos -= 0x10000L;
328           }
329          vl = (spos >> 6) & ~3;
330          vr=(gauss[vl]*gvall0) >> 15;
331          vr+=(gauss[vl+1]*gvall(1)) >> 15;
332          vr+=(gauss[vl+2]*gvall(2)) >> 15;
333          vr+=(gauss[vl+3]*gvall(3)) >> 15;
334          l1=s= vr;
335          l1 &= 0xffff;
336         }
337        else
338         {
339          while(spos>=0x10000L)
340           {
341            s = *pS++;
342            spos -= 0x10000L;
343           }
344          l1=s;
345         }
346
347        l1=(l1*iPlace)/iSize;
348        ssat32_to_16(l1);
349        l=(l1&0xffff)|(l1<<16);
350        *spu.XAFeed++=l;
351
352        if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
353        if(spu.XAFeed==spu.XAPlay)
354         {
355          if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
356          break;
357         }
358
359        spos += sinc;
360       }
361     }
362    else
363 #endif
364     {
365      for(i=0;i<iSize;i++)
366       {
367        if(spu_config.iUseInterpolation==2)
368         {
369          while(spos>=0x10000L)
370           {
371            gauss_window[gauss_ptr] = (short)*pS++;
372            gauss_ptr = (gauss_ptr+1) & 3;
373            spos -= 0x10000L;
374           }
375          vl = (spos >> 6) & ~3;
376          vr=(gauss[vl]*gvall0) >> 15;
377          vr+=(gauss[vl+1]*gvall(1)) >> 15;
378          vr+=(gauss[vl+2]*gvall(2)) >> 15;
379          vr+=(gauss[vl+3]*gvall(3)) >> 15;
380          l=s= vr;
381         }
382        else
383         {
384          while(spos>=0x10000L)
385           {
386            s = *pS++;
387            spos -= 0x10000L;
388           }
389          l=s;
390         }
391
392        l &= 0xffff;
393        *spu.XAFeed++=(l|(l<<16));
394
395        if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
396        if(spu.XAFeed==spu.XAPlay)
397         {
398          if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
399          break;
400         }
401
402        spos += sinc;
403       }
404     }
405   }
406 }
407
408 ////////////////////////////////////////////////////////////////////////
409 // FEED CDDA
410 ////////////////////////////////////////////////////////////////////////
411
412 void FeedCDDA(unsigned char *pcm, int nBytes)
413 {
414  int space;
415  space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
416  if(space<nBytes)
417   return;
418
419  while(nBytes>0)
420   {
421    if(spu.CDDAFeed==spu.CDDAEnd) spu.CDDAFeed=spu.CDDAStart;
422    space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
423    if(spu.CDDAFeed+space/4>spu.CDDAEnd)
424     space=(spu.CDDAEnd-spu.CDDAFeed)*4;
425    if(space>nBytes)
426     space=nBytes;
427
428    memcpy(spu.CDDAFeed,pcm,space);
429    spu.CDDAFeed+=space/4;
430    nBytes-=space;
431    pcm+=space;
432   }
433 }
434
435 #endif
436 // vim:shiftwidth=1:expandtab