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