Commit | Line | Data |
---|---|---|
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" | |
a4621d43 | 19 | #include "spu.h" |
ef79bbde P |
20 | #define _IN_XA |
21 | #include <stdint.h> | |
22 | ||
23 | // will be included from spu.c | |
24 | #ifdef _IN_SPU | |
25 | ||
26 | //////////////////////////////////////////////////////////////////////// | |
27 | // XA GLOBALS | |
28 | //////////////////////////////////////////////////////////////////////// | |
29 | ||
ef79bbde P |
30 | static int gauss_ptr = 0; |
31 | static int gauss_window[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |
32 | ||
33 | #define gvall0 gauss_window[gauss_ptr] | |
34 | #define gvall(x) gauss_window[(gauss_ptr+x)&3] | |
35 | #define gvalr0 gauss_window[4+gauss_ptr] | |
36 | #define gvalr(x) gauss_window[4+((gauss_ptr+x)&3)] | |
37 | ||
38 | //////////////////////////////////////////////////////////////////////// | |
39 | // MIX XA & CDDA | |
40 | //////////////////////////////////////////////////////////////////////// | |
41 | ||
38b8a211 | 42 | INLINE void SkipCD(int ns_to, int decode_pos) |
ef79bbde | 43 | { |
215ff9e6 | 44 | int cursor = decode_pos; |
ef79bbde | 45 | int ns; |
38b8a211 | 46 | |
47 | if(spu.XAPlay != spu.XAFeed) | |
48 | { | |
49 | for(ns = 0; ns < ns_to*2; ns += 2) | |
50 | { | |
51 | if(spu.XAPlay != spu.XAFeed) spu.XAPlay++; | |
52 | if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart; | |
53 | ||
54 | spu.spuMem[cursor] = 0; | |
55 | spu.spuMem[cursor + 0x400/2] = 0; | |
56 | cursor = (cursor + 1) & 0x1ff; | |
57 | } | |
58 | } | |
59 | else if(spu.CDDAPlay != spu.CDDAFeed) | |
60 | { | |
61 | for(ns = 0; ns < ns_to*2; ns += 2) | |
62 | { | |
63 | if(spu.CDDAPlay != spu.CDDAFeed) spu.CDDAPlay++; | |
64 | if(spu.CDDAPlay == spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart; | |
65 | ||
66 | spu.spuMem[cursor] = 0; | |
67 | spu.spuMem[cursor + 0x400/2] = 0; | |
68 | cursor = (cursor + 1) & 0x1ff; | |
69 | } | |
70 | } | |
71 | spu.XALastVal = 0; | |
72 | } | |
73 | ||
74 | INLINE void MixCD(int *SSumLR, int *RVB, int ns_to, int decode_pos) | |
75 | { | |
76 | int vll = spu.iLeftXAVol * spu.cdv.ll >> 7; | |
77 | int vrl = spu.iLeftXAVol * spu.cdv.rl >> 7; | |
78 | int vlr = spu.iRightXAVol * spu.cdv.lr >> 7; | |
79 | int vrr = spu.iRightXAVol * spu.cdv.rr >> 7; | |
80 | int cursor = decode_pos; | |
81 | int l1, r1, l, r; | |
82 | int ns; | |
4197fb21 | 83 | uint32_t v = spu.XALastVal; |
ef79bbde | 84 | |
894cbc49 | 85 | // note: spu volume doesn't affect cd capture |
86 | if ((spu.cdv.ll | spu.cdv.lr | spu.cdv.rl | spu.cdv.rr) == 0) | |
38b8a211 | 87 | { |
88 | SkipCD(ns_to, decode_pos); | |
89 | return; | |
90 | } | |
91 | ||
3154bfab | 92 | if(spu.XAPlay != spu.XAFeed || spu.XARepeat > 0) |
efce366c | 93 | { |
3154bfab | 94 | if(spu.XAPlay == spu.XAFeed) |
95 | spu.XARepeat--; | |
efce366c | 96 | |
73d2a903 | 97 | for(ns = 0; ns < ns_to*2; ns += 2) |
efce366c | 98 | { |
3154bfab | 99 | if(spu.XAPlay != spu.XAFeed) v=*spu.XAPlay++; |
100 | if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart; | |
efce366c | 101 | |
38b8a211 | 102 | l1 = (short)v, r1 = (short)(v >> 16); |
103 | l = (l1 * vll + r1 * vrl) >> 15; | |
104 | r = (r1 * vrr + l1 * vlr) >> 15; | |
105 | ssat32_to_16(l); | |
106 | ssat32_to_16(r); | |
73d2a903 | 107 | if (spu.spuCtrl & CTRL_CD) |
108 | { | |
109 | SSumLR[ns+0] += l; | |
110 | SSumLR[ns+1] += r; | |
111 | } | |
112 | if (unlikely(spu.spuCtrl & CTRL_CDREVERB)) | |
113 | { | |
114 | RVB[ns+0] += l; | |
115 | RVB[ns+1] += r; | |
116 | } | |
1d753163 | 117 | |
a4621d43 PC |
118 | spu.spuMem[cursor] = HTOLE16(v); |
119 | spu.spuMem[cursor + 0x400/2] = HTOLE16(v >> 16); | |
efce366c | 120 | cursor = (cursor + 1) & 0x1ff; |
121 | } | |
3154bfab | 122 | spu.XALastVal = v; |
efce366c | 123 | } |
4197fb21 | 124 | // occasionally CDDAFeed underflows by a few samples due to poor timing, |
125 | // hence this 'ns_to < 8' | |
126 | else if(spu.CDDAPlay != spu.CDDAFeed || ns_to < 8) | |
127 | { | |
73d2a903 | 128 | for(ns = 0; ns < ns_to*2; ns += 2) |
4197fb21 | 129 | { |
130 | if(spu.CDDAPlay != spu.CDDAFeed) v=*spu.CDDAPlay++; | |
131 | if(spu.CDDAPlay == spu.CDDAEnd) spu.CDDAPlay=spu.CDDAStart; | |
ef79bbde | 132 | |
38b8a211 | 133 | l1 = (short)v, r1 = (short)(v >> 16); |
134 | l = (l1 * vll + r1 * vrl) >> 15; | |
135 | r = (r1 * vrr + l1 * vlr) >> 15; | |
136 | ssat32_to_16(l); | |
137 | ssat32_to_16(r); | |
73d2a903 | 138 | if (spu.spuCtrl & CTRL_CD) |
139 | { | |
140 | SSumLR[ns+0] += l; | |
141 | SSumLR[ns+1] += r; | |
142 | } | |
143 | if (unlikely(spu.spuCtrl & CTRL_CDREVERB)) | |
144 | { | |
145 | RVB[ns+0] += l; | |
146 | RVB[ns+1] += r; | |
147 | } | |
1d753163 | 148 | |
a4621d43 PC |
149 | spu.spuMem[cursor] = HTOLE16(v); |
150 | spu.spuMem[cursor + 0x400/2] = HTOLE16(v >> 16); | |
4197fb21 | 151 | cursor = (cursor + 1) & 0x1ff; |
152 | } | |
153 | spu.XALastVal = v; | |
154 | } | |
67c020ee | 155 | else if (spu.cdClearSamples > 0) |
156 | { | |
157 | for(ns = 0; ns < ns_to; ns++) | |
158 | { | |
159 | spu.spuMem[cursor] = spu.spuMem[cursor + 0x400/2] = 0; | |
160 | cursor = (cursor + 1) & 0x1ff; | |
161 | } | |
162 | spu.cdClearSamples -= ns_to; | |
4197fb21 | 163 | spu.XALastVal = 0; |
67c020ee | 164 | } |
ef79bbde P |
165 | } |
166 | ||
167 | //////////////////////////////////////////////////////////////////////// | |
168 | // small linux time helper... only used for watchdog | |
169 | //////////////////////////////////////////////////////////////////////// | |
170 | ||
609d9ea5 | 171 | #if 0 |
f05d6ca2 | 172 | static unsigned long timeGetTime_spu() |
ef79bbde | 173 | { |
de4a0279 | 174 | #if defined(NO_OS) |
175 | return 0; | |
176 | #elif defined(_WIN32) | |
003cfc63 | 177 | return GetTickCount(); |
178 | #else | |
ef79bbde P |
179 | struct timeval tv; |
180 | gettimeofday(&tv, 0); // well, maybe there are better ways | |
181 | return tv.tv_sec * 1000 + tv.tv_usec/1000; // to do that, but at least it works | |
003cfc63 | 182 | #endif |
ef79bbde | 183 | } |
609d9ea5 | 184 | #endif |
ef79bbde P |
185 | |
186 | //////////////////////////////////////////////////////////////////////// | |
187 | // FEED XA | |
188 | //////////////////////////////////////////////////////////////////////// | |
189 | ||
b34d6a80 | 190 | void FeedXA(const xa_decode_t *xap) |
ef79bbde P |
191 | { |
192 | int sinc,spos,i,iSize,iPlace,vl,vr; | |
193 | ||
3154bfab | 194 | if(!spu.bSPUIsOpen) return; |
ef79bbde | 195 | |
9cf79034 | 196 | spu.XARepeat = 3; // set up repeat |
ef79bbde | 197 | |
97ea4077 | 198 | #if 0//def XA_HACK |
ef79bbde P |
199 | iSize=((45500*xap->nsamples)/xap->freq); // get size |
200 | #else | |
201 | iSize=((44100*xap->nsamples)/xap->freq); // get size | |
202 | #endif | |
203 | if(!iSize) return; // none? bye | |
204 | ||
3154bfab | 205 | if(spu.XAFeed<spu.XAPlay) iPlace=spu.XAPlay-spu.XAFeed; // how much space in my buf? |
206 | else iPlace=(spu.XAEnd-spu.XAFeed) + (spu.XAPlay-spu.XAStart); | |
ef79bbde P |
207 | |
208 | if(iPlace==0) return; // no place at all | |
209 | ||
210 | //----------------------------------------------------// | |
609d9ea5 | 211 | #if 0 |
3154bfab | 212 | if(spu_config.iXAPitch) // pitch change option? |
ef79bbde P |
213 | { |
214 | static DWORD dwLT=0; | |
215 | static DWORD dwFPS=0; | |
216 | static int iFPSCnt=0; | |
217 | static int iLastSize=0; | |
218 | static DWORD dwL1=0; | |
219 | DWORD dw=timeGetTime_spu(),dw1,dw2; | |
220 | ||
221 | iPlace=iSize; | |
222 | ||
223 | dwFPS+=dw-dwLT;iFPSCnt++; | |
224 | ||
225 | dwLT=dw; | |
226 | ||
227 | if(iFPSCnt>=10) | |
228 | { | |
229 | if(!dwFPS) dwFPS=1; | |
230 | dw1=1000000/dwFPS; | |
231 | if(dw1>=(dwL1-100) && dw1<=(dwL1+100)) dw1=dwL1; | |
232 | else dwL1=dw1; | |
233 | dw2=(xap->freq*100/xap->nsamples); | |
234 | if((!dw1)||((dw2+100)>=dw1)) iLastSize=0; | |
235 | else | |
236 | { | |
237 | iLastSize=iSize*dw2/dw1; | |
238 | if(iLastSize>iPlace) iLastSize=iPlace; | |
239 | iSize=iLastSize; | |
240 | } | |
241 | iFPSCnt=0;dwFPS=0; | |
242 | } | |
243 | else | |
244 | { | |
245 | if(iLastSize) iSize=iLastSize; | |
246 | } | |
247 | } | |
609d9ea5 | 248 | #endif |
ef79bbde P |
249 | //----------------------------------------------------// |
250 | ||
251 | spos=0x10000L; | |
252 | sinc = (xap->nsamples << 16) / iSize; // calc freq by num / size | |
253 | ||
254 | if(xap->stereo) | |
255 | { | |
256 | uint32_t * pS=(uint32_t *)xap->pcm; | |
257 | uint32_t l=0; | |
258 | ||
609d9ea5 | 259 | #if 0 |
3154bfab | 260 | if(spu_config.iXAPitch) |
ef79bbde P |
261 | { |
262 | int32_t l1,l2;short s; | |
263 | for(i=0;i<iSize;i++) | |
264 | { | |
3154bfab | 265 | if(spu_config.iUseInterpolation==2) |
ef79bbde P |
266 | { |
267 | while(spos>=0x10000L) | |
268 | { | |
269 | l = *pS++; | |
270 | gauss_window[gauss_ptr] = (short)LOWORD(l); | |
271 | gauss_window[4+gauss_ptr] = (short)HIWORD(l); | |
272 | gauss_ptr = (gauss_ptr+1) & 3; | |
273 | spos -= 0x10000L; | |
274 | } | |
275 | vl = (spos >> 6) & ~3; | |
acc415b3 S |
276 | vr=(gauss[vl]*gvall0) >> 15; |
277 | vr+=(gauss[vl+1]*gvall(1)) >> 15; | |
278 | vr+=(gauss[vl+2]*gvall(2)) >> 15; | |
279 | vr+=(gauss[vl+3]*gvall(3)) >> 15; | |
280 | l= vr & 0xffff; | |
281 | vr=(gauss[vl]*gvalr0) >> 15; | |
282 | vr+=(gauss[vl+1]*gvalr(1)) >> 15; | |
283 | vr+=(gauss[vl+2]*gvalr(2)) >> 15; | |
284 | vr+=(gauss[vl+3]*gvalr(3)) >> 15; | |
285 | l |= vr << 16; | |
ef79bbde P |
286 | } |
287 | else | |
288 | { | |
289 | while(spos>=0x10000L) | |
290 | { | |
291 | l = *pS++; | |
292 | spos -= 0x10000L; | |
293 | } | |
294 | } | |
295 | ||
296 | s=(short)LOWORD(l); | |
297 | l1=s; | |
298 | l1=(l1*iPlace)/iSize; | |
381ea103 | 299 | ssat32_to_16(l1); |
ef79bbde P |
300 | s=(short)HIWORD(l); |
301 | l2=s; | |
302 | l2=(l2*iPlace)/iSize; | |
381ea103 | 303 | ssat32_to_16(l2); |
ef79bbde P |
304 | l=(l1&0xffff)|(l2<<16); |
305 | ||
3154bfab | 306 | *spu.XAFeed++=l; |
ef79bbde | 307 | |
3154bfab | 308 | if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart; |
309 | if(spu.XAFeed==spu.XAPlay) | |
ef79bbde | 310 | { |
3154bfab | 311 | if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1; |
ef79bbde P |
312 | break; |
313 | } | |
314 | ||
315 | spos += sinc; | |
316 | } | |
317 | } | |
318 | else | |
609d9ea5 | 319 | #endif |
ef79bbde P |
320 | { |
321 | for(i=0;i<iSize;i++) | |
322 | { | |
3154bfab | 323 | if(spu_config.iUseInterpolation==2) |
ef79bbde P |
324 | { |
325 | while(spos>=0x10000L) | |
326 | { | |
327 | l = *pS++; | |
328 | gauss_window[gauss_ptr] = (short)LOWORD(l); | |
329 | gauss_window[4+gauss_ptr] = (short)HIWORD(l); | |
330 | gauss_ptr = (gauss_ptr+1) & 3; | |
331 | spos -= 0x10000L; | |
332 | } | |
333 | vl = (spos >> 6) & ~3; | |
acc415b3 S |
334 | vr=(gauss[vl]*gvall0) >> 15; |
335 | vr+=(gauss[vl+1]*gvall(1)) >> 15; | |
336 | vr+=(gauss[vl+2]*gvall(2)) >> 15; | |
337 | vr+=(gauss[vl+3]*gvall(3)) >> 15; | |
338 | l= vr & 0xffff; | |
339 | vr=(gauss[vl]*gvalr0) >> 15; | |
340 | vr+=(gauss[vl+1]*gvalr(1)) >> 15; | |
341 | vr+=(gauss[vl+2]*gvalr(2)) >> 15; | |
342 | vr+=(gauss[vl+3]*gvalr(3)) >> 15; | |
343 | l |= vr << 16; | |
ef79bbde P |
344 | } |
345 | else | |
346 | { | |
347 | while(spos>=0x10000L) | |
348 | { | |
349 | l = *pS++; | |
350 | spos -= 0x10000L; | |
351 | } | |
352 | } | |
353 | ||
3154bfab | 354 | *spu.XAFeed++=l; |
ef79bbde | 355 | |
3154bfab | 356 | if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart; |
357 | if(spu.XAFeed==spu.XAPlay) | |
ef79bbde | 358 | { |
3154bfab | 359 | if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1; |
ef79bbde P |
360 | break; |
361 | } | |
362 | ||
363 | spos += sinc; | |
364 | } | |
365 | } | |
366 | } | |
367 | else | |
368 | { | |
369 | unsigned short * pS=(unsigned short *)xap->pcm; | |
370 | uint32_t l;short s=0; | |
371 | ||
609d9ea5 | 372 | #if 0 |
3154bfab | 373 | if(spu_config.iXAPitch) |
ef79bbde P |
374 | { |
375 | int32_t l1; | |
376 | for(i=0;i<iSize;i++) | |
377 | { | |
3154bfab | 378 | if(spu_config.iUseInterpolation==2) |
ef79bbde P |
379 | { |
380 | while(spos>=0x10000L) | |
381 | { | |
382 | gauss_window[gauss_ptr] = (short)*pS++; | |
383 | gauss_ptr = (gauss_ptr+1) & 3; | |
384 | spos -= 0x10000L; | |
385 | } | |
386 | vl = (spos >> 6) & ~3; | |
acc415b3 S |
387 | vr=(gauss[vl]*gvall0) >> 15; |
388 | vr+=(gauss[vl+1]*gvall(1)) >> 15; | |
389 | vr+=(gauss[vl+2]*gvall(2)) >> 15; | |
390 | vr+=(gauss[vl+3]*gvall(3)) >> 15; | |
391 | l1=s= vr; | |
ef79bbde P |
392 | l1 &= 0xffff; |
393 | } | |
394 | else | |
395 | { | |
396 | while(spos>=0x10000L) | |
397 | { | |
398 | s = *pS++; | |
399 | spos -= 0x10000L; | |
400 | } | |
401 | l1=s; | |
402 | } | |
403 | ||
404 | l1=(l1*iPlace)/iSize; | |
381ea103 | 405 | ssat32_to_16(l1); |
ef79bbde | 406 | l=(l1&0xffff)|(l1<<16); |
3154bfab | 407 | *spu.XAFeed++=l; |
ef79bbde | 408 | |
3154bfab | 409 | if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart; |
410 | if(spu.XAFeed==spu.XAPlay) | |
ef79bbde | 411 | { |
3154bfab | 412 | if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1; |
ef79bbde P |
413 | break; |
414 | } | |
415 | ||
416 | spos += sinc; | |
417 | } | |
418 | } | |
419 | else | |
609d9ea5 | 420 | #endif |
ef79bbde P |
421 | { |
422 | for(i=0;i<iSize;i++) | |
423 | { | |
3154bfab | 424 | if(spu_config.iUseInterpolation==2) |
ef79bbde P |
425 | { |
426 | while(spos>=0x10000L) | |
427 | { | |
428 | gauss_window[gauss_ptr] = (short)*pS++; | |
429 | gauss_ptr = (gauss_ptr+1) & 3; | |
430 | spos -= 0x10000L; | |
431 | } | |
432 | vl = (spos >> 6) & ~3; | |
acc415b3 S |
433 | vr=(gauss[vl]*gvall0) >> 15; |
434 | vr+=(gauss[vl+1]*gvall(1)) >> 15; | |
435 | vr+=(gauss[vl+2]*gvall(2)) >> 15; | |
436 | vr+=(gauss[vl+3]*gvall(3)) >> 15; | |
437 | l=s= vr; | |
ef79bbde P |
438 | } |
439 | else | |
440 | { | |
441 | while(spos>=0x10000L) | |
442 | { | |
443 | s = *pS++; | |
444 | spos -= 0x10000L; | |
445 | } | |
446 | l=s; | |
447 | } | |
448 | ||
9098b863 | 449 | l &= 0xffff; |
3154bfab | 450 | *spu.XAFeed++=(l|(l<<16)); |
ef79bbde | 451 | |
3154bfab | 452 | if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart; |
453 | if(spu.XAFeed==spu.XAPlay) | |
ef79bbde | 454 | { |
3154bfab | 455 | if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1; |
ef79bbde P |
456 | break; |
457 | } | |
458 | ||
459 | spos += sinc; | |
460 | } | |
461 | } | |
462 | } | |
463 | } | |
464 | ||
465 | //////////////////////////////////////////////////////////////////////// | |
466 | // FEED CDDA | |
467 | //////////////////////////////////////////////////////////////////////// | |
468 | ||
b34d6a80 | 469 | void FeedCDDA(unsigned char *pcm, int nBytes) |
ef79bbde | 470 | { |
983a7cfd | 471 | int space; |
3154bfab | 472 | space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1); |
20ed712f | 473 | if (space < nBytes) { |
474 | log_unhandled("FeedCDDA: %d/%d\n", nBytes, space); | |
b34d6a80 | 475 | return; |
20ed712f | 476 | } |
983a7cfd | 477 | |
ef79bbde P |
478 | while(nBytes>0) |
479 | { | |
3154bfab | 480 | if(spu.CDDAFeed==spu.CDDAEnd) spu.CDDAFeed=spu.CDDAStart; |
481 | space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1); | |
482 | if(spu.CDDAFeed+space/4>spu.CDDAEnd) | |
483 | space=(spu.CDDAEnd-spu.CDDAFeed)*4; | |
983a7cfd | 484 | if(space>nBytes) |
485 | space=nBytes; | |
486 | ||
3154bfab | 487 | memcpy(spu.CDDAFeed,pcm,space); |
488 | spu.CDDAFeed+=space/4; | |
983a7cfd | 489 | nBytes-=space; |
490 | pcm+=space; | |
ef79bbde P |
491 | } |
492 | } | |
493 | ||
494 | #endif | |
73d2a903 | 495 | // vim:shiftwidth=1:expandtab |