spu: put globals into a structure
[pcsx_rearmed.git] / plugins / dfsound / xa.c
CommitLineData
ef79bbde
P
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
ef79bbde
P
29static int gauss_ptr = 0;
30static 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
650adfd2 41INLINE void MixXA(int ns_to)
ef79bbde
P
42{
43 int ns;
efce366c 44 short l, r;
45 uint32_t v;
3154bfab 46 int cursor = spu.decode_pos;
ef79bbde 47
3154bfab 48 if(spu.XAPlay != spu.XAFeed || spu.XARepeat > 0)
efce366c 49 {
3154bfab 50 if(spu.XAPlay == spu.XAFeed)
51 spu.XARepeat--;
efce366c 52
3154bfab 53 v = spu.XALastVal;
650adfd2 54 for(ns = 0; ns < ns_to*2; )
efce366c 55 {
3154bfab 56 if(spu.XAPlay != spu.XAFeed) v=*spu.XAPlay++;
57 if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart;
efce366c 58
3154bfab 59 l = ((int)(short)v * spu.iLeftXAVol) >> 15;
60 r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15;
efce366c 61 SSumLR[ns++] += l;
62 SSumLR[ns++] += r;
1d753163 63
3154bfab 64 spu.spuMem[cursor] = v;
65 spu.spuMem[cursor + 0x400/2] = v >> 16;
efce366c 66 cursor = (cursor + 1) & 0x1ff;
67 }
3154bfab 68 spu.XALastVal = v;
efce366c 69 }
ef79bbde 70
3154bfab 71 for(ns = 0; ns < ns_to * 2 && spu.CDDAPlay!=spu.CDDAFeed && (spu.CDDAPlay!=spu.CDDAEnd-1||spu.CDDAFeed!=spu.CDDAStart);)
ef79bbde 72 {
3154bfab 73 v=*spu.CDDAPlay++;
74 if(spu.CDDAPlay==spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart;
efce366c 75
3154bfab 76 l = ((int)(short)v * spu.iLeftXAVol) >> 15;
77 r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15;
efce366c 78 SSumLR[ns++] += l;
79 SSumLR[ns++] += r;
1d753163 80
3154bfab 81 spu.spuMem[cursor] = v;
82 spu.spuMem[cursor + 0x400/2] = v >> 16;
efce366c 83 cursor = (cursor + 1) & 0x1ff;
ef79bbde
P
84 }
85}
86
87////////////////////////////////////////////////////////////////////////
88// small linux time helper... only used for watchdog
89////////////////////////////////////////////////////////////////////////
90
f05d6ca2 91static unsigned long timeGetTime_spu()
ef79bbde
P
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
102INLINE void FeedXA(xa_decode_t *xap)
103{
104 int sinc,spos,i,iSize,iPlace,vl,vr;
105
3154bfab 106 if(!spu.bSPUIsOpen) return;
ef79bbde 107
3154bfab 108 spu.xapGlobal = xap; // store info for save states
109 spu.XARepeat = 100; // set up repeat
ef79bbde 110
97ea4077 111#if 0//def XA_HACK
ef79bbde
P
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
3154bfab 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);
ef79bbde
P
120
121 if(iPlace==0) return; // no place at all
122
123 //----------------------------------------------------//
3154bfab 124 if(spu_config.iXAPitch) // pitch change option?
ef79bbde
P
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
3154bfab 170 if(spu_config.iXAPitch)
ef79bbde
P
171 {
172 int32_t l1,l2;short s;
173 for(i=0;i<iSize;i++)
174 {
3154bfab 175 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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;
381ea103 209 ssat32_to_16(l1);
ef79bbde
P
210 s=(short)HIWORD(l);
211 l2=s;
212 l2=(l2*iPlace)/iSize;
381ea103 213 ssat32_to_16(l2);
ef79bbde
P
214 l=(l1&0xffff)|(l2<<16);
215
3154bfab 216 *spu.XAFeed++=l;
ef79bbde 217
3154bfab 218 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
219 if(spu.XAFeed==spu.XAPlay)
ef79bbde 220 {
3154bfab 221 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
222 break;
223 }
224
225 spos += sinc;
226 }
227 }
228 else
229 {
230 for(i=0;i<iSize;i++)
231 {
3154bfab 232 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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
3154bfab 263 *spu.XAFeed++=l;
ef79bbde 264
3154bfab 265 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
266 if(spu.XAFeed==spu.XAPlay)
ef79bbde 267 {
3154bfab 268 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
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
3154bfab 281 if(spu_config.iXAPitch)
ef79bbde
P
282 {
283 int32_t l1;
284 for(i=0;i<iSize;i++)
285 {
3154bfab 286 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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;
381ea103 313 ssat32_to_16(l1);
ef79bbde 314 l=(l1&0xffff)|(l1<<16);
3154bfab 315 *spu.XAFeed++=l;
ef79bbde 316
3154bfab 317 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
318 if(spu.XAFeed==spu.XAPlay)
ef79bbde 319 {
3154bfab 320 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
321 break;
322 }
323
324 spos += sinc;
325 }
326 }
327 else
328 {
329 for(i=0;i<iSize;i++)
330 {
3154bfab 331 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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;
ef79bbde
P
345 }
346 else
347 {
348 while(spos>=0x10000L)
349 {
350 s = *pS++;
351 spos -= 0x10000L;
352 }
353 l=s;
354 }
355
9098b863 356 l &= 0xffff;
3154bfab 357 *spu.XAFeed++=(l|(l<<16));
ef79bbde 358
3154bfab 359 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
360 if(spu.XAFeed==spu.XAPlay)
ef79bbde 361 {
3154bfab 362 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
363 break;
364 }
365
366 spos += sinc;
367 }
368 }
369 }
370}
371
372////////////////////////////////////////////////////////////////////////
373// FEED CDDA
374////////////////////////////////////////////////////////////////////////
375
983a7cfd 376INLINE int FeedCDDA(unsigned char *pcm, int nBytes)
ef79bbde 377{
983a7cfd 378 int space;
3154bfab 379 space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
983a7cfd 380 if(space<nBytes)
381 return 0x7761; // rearmed_wait
382
ef79bbde
P
383 while(nBytes>0)
384 {
3154bfab 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;
983a7cfd 389 if(space>nBytes)
390 space=nBytes;
391
3154bfab 392 memcpy(spu.CDDAFeed,pcm,space);
393 spu.CDDAFeed+=space/4;
983a7cfd 394 nBytes-=space;
395 pcm+=space;
ef79bbde 396 }
983a7cfd 397
398 return 0x676f; // rearmed_go
ef79bbde
P
399}
400
401#endif