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