spu: fix decode buffers
[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  short l, r;
63  uint32_t v;
64  int cursor = decode_pos;
65
66  if(XAPlay != XAFeed || XARepeat > 0)
67  {
68   if(XAPlay == XAFeed)
69    XARepeat--;
70
71   v = XALastVal;
72   for(ns=0;ns<NSSIZE*2;)
73    {
74     if(XAPlay != XAFeed) v=*XAPlay++;
75     if(XAPlay == XAEnd) XAPlay=XAStart;
76
77     l = ((int)(short)v * iLeftXAVol) >> 15;
78     r = ((int)(short)(v >> 16) * iLeftXAVol) >> 15;
79     SSumLR[ns++] += l;
80     SSumLR[ns++] += r;
81
82     spuMem[cursor] = v;
83     spuMem[cursor + 0x400/2] = v >> 16;
84     cursor = (cursor + 1) & 0x1ff;
85    }
86   XALastVal = v;
87  }
88
89  for(ns=0;ns<NSSIZE*2 && CDDAPlay!=CDDAFeed && (CDDAPlay!=CDDAEnd-1||CDDAFeed!=CDDAStart);)
90   {
91    v=*CDDAPlay++;
92    if(CDDAPlay==CDDAEnd) CDDAPlay=CDDAStart;
93
94    l = ((int)(short)v * iLeftXAVol) >> 15;
95    r = ((int)(short)(v >> 16) * iLeftXAVol) >> 15;
96    SSumLR[ns++] += l;
97    SSumLR[ns++] += r;
98
99    spuMem[cursor] = v;
100    spuMem[cursor + 0x400/2] = v >> 16;
101    cursor = (cursor + 1) & 0x1ff;
102   }
103 }
104
105 ////////////////////////////////////////////////////////////////////////
106 // small linux time helper... only used for watchdog
107 ////////////////////////////////////////////////////////////////////////
108
109 static unsigned long timeGetTime_spu()
110 {
111  struct timeval tv;
112  gettimeofday(&tv, 0);                                 // well, maybe there are better ways
113  return tv.tv_sec * 1000 + tv.tv_usec/1000;            // to do that, but at least it works
114 }
115
116 ////////////////////////////////////////////////////////////////////////
117 // FEED XA 
118 ////////////////////////////////////////////////////////////////////////
119
120 INLINE void FeedXA(xa_decode_t *xap)
121 {
122  int sinc,spos,i,iSize,iPlace,vl,vr;
123
124  if(!bSPUIsOpen) return;
125
126  xapGlobal = xap;                                      // store info for save states
127  XARepeat  = 100;                                      // set up repeat
128
129 #if 0//def XA_HACK
130  iSize=((45500*xap->nsamples)/xap->freq);              // get size
131 #else
132  iSize=((44100*xap->nsamples)/xap->freq);              // get size
133 #endif
134  if(!iSize) return;                                    // none? bye
135
136  if(XAFeed<XAPlay) iPlace=XAPlay-XAFeed;               // how much space in my buf?
137  else              iPlace=(XAEnd-XAFeed) + (XAPlay-XAStart);
138
139  if(iPlace==0) return;                                 // no place at all
140
141  //----------------------------------------------------//
142  if(iXAPitch)                                          // pitch change option?
143   {
144    static DWORD dwLT=0;
145    static DWORD dwFPS=0;
146    static int   iFPSCnt=0;
147    static int   iLastSize=0;
148    static DWORD dwL1=0;
149    DWORD dw=timeGetTime_spu(),dw1,dw2;
150
151    iPlace=iSize;
152
153    dwFPS+=dw-dwLT;iFPSCnt++;
154
155    dwLT=dw;
156                                        
157    if(iFPSCnt>=10)
158     {
159      if(!dwFPS) dwFPS=1;
160      dw1=1000000/dwFPS; 
161      if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1;
162      else dwL1=dw1;
163      dw2=(xap->freq*100/xap->nsamples);
164      if((!dw1)||((dw2+100)>=dw1)) iLastSize=0;
165      else
166       {
167        iLastSize=iSize*dw2/dw1;
168        if(iLastSize>iPlace) iLastSize=iPlace;
169        iSize=iLastSize;
170       }
171      iFPSCnt=0;dwFPS=0;
172     }
173    else
174     {
175      if(iLastSize) iSize=iLastSize;
176     }
177   }
178  //----------------------------------------------------//
179
180  spos=0x10000L;
181  sinc = (xap->nsamples << 16) / iSize;                 // calc freq by num / size
182
183  if(xap->stereo)
184 {
185    uint32_t * pS=(uint32_t *)xap->pcm;
186    uint32_t l=0;
187
188    if(iXAPitch)
189     {
190      int32_t l1,l2;short s;
191      for(i=0;i<iSize;i++)
192       {
193        if(iUseInterpolation==2) 
194         {
195          while(spos>=0x10000L)
196           {
197            l = *pS++;
198            gauss_window[gauss_ptr] = (short)LOWORD(l);
199            gauss_window[4+gauss_ptr] = (short)HIWORD(l);
200            gauss_ptr = (gauss_ptr+1) & 3;
201            spos -= 0x10000L;
202           }
203          vl = (spos >> 6) & ~3;
204          vr=(gauss[vl]*gvall0)&~2047;
205          vr+=(gauss[vl+1]*gvall(1))&~2047;
206          vr+=(gauss[vl+2]*gvall(2))&~2047;
207          vr+=(gauss[vl+3]*gvall(3))&~2047;
208          l= (vr >> 11) & 0xffff;
209          vr=(gauss[vl]*gvalr0)&~2047;
210          vr+=(gauss[vl+1]*gvalr(1))&~2047;
211          vr+=(gauss[vl+2]*gvalr(2))&~2047;
212          vr+=(gauss[vl+3]*gvalr(3))&~2047;
213          l |= vr << 5;
214         }
215        else
216         {
217          while(spos>=0x10000L)
218           {
219            l = *pS++;
220            spos -= 0x10000L;
221           }
222         }
223
224        s=(short)LOWORD(l);
225        l1=s;
226        l1=(l1*iPlace)/iSize;
227        ssat32_to_16(l1);
228        s=(short)HIWORD(l);
229        l2=s;
230        l2=(l2*iPlace)/iSize;
231        ssat32_to_16(l2);
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        ssat32_to_16(l1);
332        l=(l1&0xffff)|(l1<<16);
333        *XAFeed++=l;
334
335        if(XAFeed==XAEnd) XAFeed=XAStart;
336        if(XAFeed==XAPlay) 
337         {
338          if(XAPlay!=XAStart) XAFeed=XAPlay-1;
339          break;
340         }
341
342        spos += sinc;
343       }
344     }
345    else
346     {
347      for(i=0;i<iSize;i++)
348       {
349        if(iUseInterpolation==2) 
350         {
351          while(spos>=0x10000L)
352           {
353            gauss_window[gauss_ptr] = (short)*pS++;
354            gauss_ptr = (gauss_ptr+1) & 3;
355            spos -= 0x10000L;
356           }
357          vl = (spos >> 6) & ~3;
358          vr=(gauss[vl]*gvall0)&~2047;
359          vr+=(gauss[vl+1]*gvall(1))&~2047;
360          vr+=(gauss[vl+2]*gvall(2))&~2047;
361          vr+=(gauss[vl+3]*gvall(3))&~2047;
362          l=s= vr >> 11;
363         }
364        else
365         {
366          while(spos>=0x10000L)
367           {
368            s = *pS++;
369            spos -= 0x10000L;
370           }
371          l=s;
372         }
373
374        l &= 0xffff;
375        *XAFeed++=(l|(l<<16));
376
377        if(XAFeed==XAEnd) XAFeed=XAStart;
378        if(XAFeed==XAPlay) 
379         {
380          if(XAPlay!=XAStart) XAFeed=XAPlay-1;
381          break;
382         }
383
384        spos += sinc;
385       }
386     }
387   }
388 }
389
390 ////////////////////////////////////////////////////////////////////////
391 // FEED CDDA
392 ////////////////////////////////////////////////////////////////////////
393
394 INLINE int FeedCDDA(unsigned char *pcm, int nBytes)
395 {
396  int space;
397  space=(CDDAPlay-CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
398  if(space<nBytes)
399   return 0x7761; // rearmed_wait
400
401  while(nBytes>0)
402   {
403    if(CDDAFeed==CDDAEnd) CDDAFeed=CDDAStart;
404    space=(CDDAPlay-CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
405    if(CDDAFeed+space/4>CDDAEnd)
406     space=(CDDAEnd-CDDAFeed)*4;
407    if(space>nBytes)
408     space=nBytes;
409
410    memcpy(CDDAFeed,pcm,space);
411    CDDAFeed+=space/4;
412    nBytes-=space;
413    pcm+=space;
414   }
415
416  return 0x676f; // rearmed_go
417 }
418
419 #endif