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