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