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