psxinterpreter: use cycle_multiplier also
[pcsx_rearmed.git] / plugins / dfsound / xa.c
... / ...
CommitLineData
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
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
41INLINE void MixXA(int *SSumLR, int ns_to, int decode_pos)
42{
43 int cursor = decode_pos;
44 int ns;
45 short l, r;
46 uint32_t v = spu.XALastVal;
47
48 if(spu.XAPlay != spu.XAFeed || spu.XARepeat > 0)
49 {
50 if(spu.XAPlay == spu.XAFeed)
51 spu.XARepeat--;
52
53 for(ns = 0; ns < ns_to*2; )
54 {
55 if(spu.XAPlay != spu.XAFeed) v=*spu.XAPlay++;
56 if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart;
57
58 l = ((int)(short)v * spu.iLeftXAVol) >> 15;
59 r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15;
60 SSumLR[ns++] += l;
61 SSumLR[ns++] += r;
62
63 spu.spuMem[cursor] = v;
64 spu.spuMem[cursor + 0x400/2] = v >> 16;
65 cursor = (cursor + 1) & 0x1ff;
66 }
67 spu.XALastVal = v;
68 }
69 // occasionally CDDAFeed underflows by a few samples due to poor timing,
70 // hence this 'ns_to < 8'
71 else if(spu.CDDAPlay != spu.CDDAFeed || ns_to < 8)
72 {
73 for(ns = 0; ns < ns_to*2; )
74 {
75 if(spu.CDDAPlay != spu.CDDAFeed) v=*spu.CDDAPlay++;
76 if(spu.CDDAPlay == spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart;
77
78 l = ((int)(short)v * spu.iLeftXAVol) >> 15;
79 r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15;
80 SSumLR[ns++] += l;
81 SSumLR[ns++] += r;
82
83 spu.spuMem[cursor] = v;
84 spu.spuMem[cursor + 0x400/2] = v >> 16;
85 cursor = (cursor + 1) & 0x1ff;
86 }
87 spu.XALastVal = v;
88 }
89 else
90 spu.XALastVal = 0;
91}
92
93////////////////////////////////////////////////////////////////////////
94// small linux time helper... only used for watchdog
95////////////////////////////////////////////////////////////////////////
96
97#if 0
98static unsigned long timeGetTime_spu()
99{
100#if defined(NO_OS)
101 return 0;
102#elif defined(_WIN32)
103 return GetTickCount();
104#else
105 struct timeval tv;
106 gettimeofday(&tv, 0); // well, maybe there are better ways
107 return tv.tv_sec * 1000 + tv.tv_usec/1000; // to do that, but at least it works
108#endif
109}
110#endif
111
112////////////////////////////////////////////////////////////////////////
113// FEED XA
114////////////////////////////////////////////////////////////////////////
115
116INLINE void FeedXA(xa_decode_t *xap)
117{
118 int sinc,spos,i,iSize,iPlace,vl,vr;
119
120 if(!spu.bSPUIsOpen) return;
121
122 spu.xapGlobal = xap; // store info for save states
123 spu.XARepeat = 3; // set up repeat
124
125#if 0//def XA_HACK
126 iSize=((45500*xap->nsamples)/xap->freq); // get size
127#else
128 iSize=((44100*xap->nsamples)/xap->freq); // get size
129#endif
130 if(!iSize) return; // none? bye
131
132 if(spu.XAFeed<spu.XAPlay) iPlace=spu.XAPlay-spu.XAFeed; // how much space in my buf?
133 else iPlace=(spu.XAEnd-spu.XAFeed) + (spu.XAPlay-spu.XAStart);
134
135 if(iPlace==0) return; // no place at all
136
137 //----------------------------------------------------//
138#if 0
139 if(spu_config.iXAPitch) // pitch change option?
140 {
141 static DWORD dwLT=0;
142 static DWORD dwFPS=0;
143 static int iFPSCnt=0;
144 static int iLastSize=0;
145 static DWORD dwL1=0;
146 DWORD dw=timeGetTime_spu(),dw1,dw2;
147
148 iPlace=iSize;
149
150 dwFPS+=dw-dwLT;iFPSCnt++;
151
152 dwLT=dw;
153
154 if(iFPSCnt>=10)
155 {
156 if(!dwFPS) dwFPS=1;
157 dw1=1000000/dwFPS;
158 if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1;
159 else dwL1=dw1;
160 dw2=(xap->freq*100/xap->nsamples);
161 if((!dw1)||((dw2+100)>=dw1)) iLastSize=0;
162 else
163 {
164 iLastSize=iSize*dw2/dw1;
165 if(iLastSize>iPlace) iLastSize=iPlace;
166 iSize=iLastSize;
167 }
168 iFPSCnt=0;dwFPS=0;
169 }
170 else
171 {
172 if(iLastSize) iSize=iLastSize;
173 }
174 }
175#endif
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 0
187 if(spu_config.iXAPitch)
188 {
189 int32_t l1,l2;short s;
190 for(i=0;i<iSize;i++)
191 {
192 if(spu_config.iUseInterpolation==2)
193 {
194 while(spos>=0x10000L)
195 {
196 l = *pS++;
197 gauss_window[gauss_ptr] = (short)LOWORD(l);
198 gauss_window[4+gauss_ptr] = (short)HIWORD(l);
199 gauss_ptr = (gauss_ptr+1) & 3;
200 spos -= 0x10000L;
201 }
202 vl = (spos >> 6) & ~3;
203 vr=(gauss[vl]*gvall0)&~2047;
204 vr+=(gauss[vl+1]*gvall(1))&~2047;
205 vr+=(gauss[vl+2]*gvall(2))&~2047;
206 vr+=(gauss[vl+3]*gvall(3))&~2047;
207 l= (vr >> 11) & 0xffff;
208 vr=(gauss[vl]*gvalr0)&~2047;
209 vr+=(gauss[vl+1]*gvalr(1))&~2047;
210 vr+=(gauss[vl+2]*gvalr(2))&~2047;
211 vr+=(gauss[vl+3]*gvalr(3))&~2047;
212 l |= vr << 5;
213 }
214 else
215 {
216 while(spos>=0x10000L)
217 {
218 l = *pS++;
219 spos -= 0x10000L;
220 }
221 }
222
223 s=(short)LOWORD(l);
224 l1=s;
225 l1=(l1*iPlace)/iSize;
226 ssat32_to_16(l1);
227 s=(short)HIWORD(l);
228 l2=s;
229 l2=(l2*iPlace)/iSize;
230 ssat32_to_16(l2);
231 l=(l1&0xffff)|(l2<<16);
232
233 *spu.XAFeed++=l;
234
235 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
236 if(spu.XAFeed==spu.XAPlay)
237 {
238 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
239 break;
240 }
241
242 spos += sinc;
243 }
244 }
245 else
246#endif
247 {
248 for(i=0;i<iSize;i++)
249 {
250 if(spu_config.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 *spu.XAFeed++=l;
282
283 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
284 if(spu.XAFeed==spu.XAPlay)
285 {
286 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.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 0
300 if(spu_config.iXAPitch)
301 {
302 int32_t l1;
303 for(i=0;i<iSize;i++)
304 {
305 if(spu_config.iUseInterpolation==2)
306 {
307 while(spos>=0x10000L)
308 {
309 gauss_window[gauss_ptr] = (short)*pS++;
310 gauss_ptr = (gauss_ptr+1) & 3;
311 spos -= 0x10000L;
312 }
313 vl = (spos >> 6) & ~3;
314 vr=(gauss[vl]*gvall0)&~2047;
315 vr+=(gauss[vl+1]*gvall(1))&~2047;
316 vr+=(gauss[vl+2]*gvall(2))&~2047;
317 vr+=(gauss[vl+3]*gvall(3))&~2047;
318 l1=s= vr >> 11;
319 l1 &= 0xffff;
320 }
321 else
322 {
323 while(spos>=0x10000L)
324 {
325 s = *pS++;
326 spos -= 0x10000L;
327 }
328 l1=s;
329 }
330
331 l1=(l1*iPlace)/iSize;
332 ssat32_to_16(l1);
333 l=(l1&0xffff)|(l1<<16);
334 *spu.XAFeed++=l;
335
336 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
337 if(spu.XAFeed==spu.XAPlay)
338 {
339 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
340 break;
341 }
342
343 spos += sinc;
344 }
345 }
346 else
347#endif
348 {
349 for(i=0;i<iSize;i++)
350 {
351 if(spu_config.iUseInterpolation==2)
352 {
353 while(spos>=0x10000L)
354 {
355 gauss_window[gauss_ptr] = (short)*pS++;
356 gauss_ptr = (gauss_ptr+1) & 3;
357 spos -= 0x10000L;
358 }
359 vl = (spos >> 6) & ~3;
360 vr=(gauss[vl]*gvall0)&~2047;
361 vr+=(gauss[vl+1]*gvall(1))&~2047;
362 vr+=(gauss[vl+2]*gvall(2))&~2047;
363 vr+=(gauss[vl+3]*gvall(3))&~2047;
364 l=s= vr >> 11;
365 }
366 else
367 {
368 while(spos>=0x10000L)
369 {
370 s = *pS++;
371 spos -= 0x10000L;
372 }
373 l=s;
374 }
375
376 l &= 0xffff;
377 *spu.XAFeed++=(l|(l<<16));
378
379 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
380 if(spu.XAFeed==spu.XAPlay)
381 {
382 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
383 break;
384 }
385
386 spos += sinc;
387 }
388 }
389 }
390}
391
392////////////////////////////////////////////////////////////////////////
393// FEED CDDA
394////////////////////////////////////////////////////////////////////////
395
396INLINE int FeedCDDA(unsigned char *pcm, int nBytes)
397{
398 int space;
399 space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
400 if(space<nBytes)
401 return 0x7761; // rearmed_wait
402
403 while(nBytes>0)
404 {
405 if(spu.CDDAFeed==spu.CDDAEnd) spu.CDDAFeed=spu.CDDAStart;
406 space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
407 if(spu.CDDAFeed+space/4>spu.CDDAEnd)
408 space=(spu.CDDAEnd-spu.CDDAFeed)*4;
409 if(space>nBytes)
410 space=nBytes;
411
412 memcpy(spu.CDDAFeed,pcm,space);
413 spu.CDDAFeed+=space/4;
414 nBytes-=space;
415 pcm+=space;
416 }
417
418 return 0x676f; // rearmed_go
419}
420
421#endif