Merge pull request #277 from joolswills/armv6_unai_fix
[pcsx_rearmed.git] / plugins / dfsound / xa.c
CommitLineData
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
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
3bd31caf 41INLINE void MixXA(int *SSumLR, int ns_to, int decode_pos)
ef79bbde 42{
215ff9e6 43 int cursor = decode_pos;
ef79bbde 44 int ns;
efce366c 45 short l, r;
4197fb21 46 uint32_t v = spu.XALastVal;
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
650adfd2 53 for(ns = 0; ns < ns_to*2; )
efce366c 54 {
3154bfab 55 if(spu.XAPlay != spu.XAFeed) v=*spu.XAPlay++;
56 if(spu.XAPlay == spu.XAEnd) spu.XAPlay=spu.XAStart;
efce366c 57
3154bfab 58 l = ((int)(short)v * spu.iLeftXAVol) >> 15;
59 r = ((int)(short)(v >> 16) * spu.iLeftXAVol) >> 15;
efce366c 60 SSumLR[ns++] += l;
61 SSumLR[ns++] += r;
1d753163 62
3154bfab 63 spu.spuMem[cursor] = v;
64 spu.spuMem[cursor + 0x400/2] = v >> 16;
efce366c 65 cursor = (cursor + 1) & 0x1ff;
66 }
3154bfab 67 spu.XALastVal = v;
efce366c 68 }
4197fb21 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;
ef79bbde 77
4197fb21 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;
1d753163 82
4197fb21 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;
ef79bbde
P
91}
92
93////////////////////////////////////////////////////////////////////////
94// small linux time helper... only used for watchdog
95////////////////////////////////////////////////////////////////////////
96
609d9ea5 97#if 0
f05d6ca2 98static unsigned long timeGetTime_spu()
ef79bbde 99{
de4a0279 100#if defined(NO_OS)
101 return 0;
102#elif defined(_WIN32)
003cfc63 103 return GetTickCount();
104#else
ef79bbde
P
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
003cfc63 108#endif
ef79bbde 109}
609d9ea5 110#endif
ef79bbde
P
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
3154bfab 120 if(!spu.bSPUIsOpen) return;
ef79bbde 121
3154bfab 122 spu.xapGlobal = xap; // store info for save states
9cf79034 123 spu.XARepeat = 3; // set up repeat
ef79bbde 124
97ea4077 125#if 0//def XA_HACK
ef79bbde
P
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
3154bfab 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);
ef79bbde
P
134
135 if(iPlace==0) return; // no place at all
136
137 //----------------------------------------------------//
609d9ea5 138#if 0
3154bfab 139 if(spu_config.iXAPitch) // pitch change option?
ef79bbde
P
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 }
609d9ea5 175#endif
ef79bbde
P
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
609d9ea5 186#if 0
3154bfab 187 if(spu_config.iXAPitch)
ef79bbde
P
188 {
189 int32_t l1,l2;short s;
190 for(i=0;i<iSize;i++)
191 {
3154bfab 192 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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;
acc415b3
S
203 vr=(gauss[vl]*gvall0) >> 15;
204 vr+=(gauss[vl+1]*gvall(1)) >> 15;
205 vr+=(gauss[vl+2]*gvall(2)) >> 15;
206 vr+=(gauss[vl+3]*gvall(3)) >> 15;
207 l= vr & 0xffff;
208 vr=(gauss[vl]*gvalr0) >> 15;
209 vr+=(gauss[vl+1]*gvalr(1)) >> 15;
210 vr+=(gauss[vl+2]*gvalr(2)) >> 15;
211 vr+=(gauss[vl+3]*gvalr(3)) >> 15;
212 l |= vr << 16;
ef79bbde
P
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;
381ea103 226 ssat32_to_16(l1);
ef79bbde
P
227 s=(short)HIWORD(l);
228 l2=s;
229 l2=(l2*iPlace)/iSize;
381ea103 230 ssat32_to_16(l2);
ef79bbde
P
231 l=(l1&0xffff)|(l2<<16);
232
3154bfab 233 *spu.XAFeed++=l;
ef79bbde 234
3154bfab 235 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
236 if(spu.XAFeed==spu.XAPlay)
ef79bbde 237 {
3154bfab 238 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
239 break;
240 }
241
242 spos += sinc;
243 }
244 }
245 else
609d9ea5 246#endif
ef79bbde
P
247 {
248 for(i=0;i<iSize;i++)
249 {
3154bfab 250 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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;
acc415b3
S
261 vr=(gauss[vl]*gvall0) >> 15;
262 vr+=(gauss[vl+1]*gvall(1)) >> 15;
263 vr+=(gauss[vl+2]*gvall(2)) >> 15;
264 vr+=(gauss[vl+3]*gvall(3)) >> 15;
265 l= vr & 0xffff;
266 vr=(gauss[vl]*gvalr0) >> 15;
267 vr+=(gauss[vl+1]*gvalr(1)) >> 15;
268 vr+=(gauss[vl+2]*gvalr(2)) >> 15;
269 vr+=(gauss[vl+3]*gvalr(3)) >> 15;
270 l |= vr << 16;
ef79bbde
P
271 }
272 else
273 {
274 while(spos>=0x10000L)
275 {
276 l = *pS++;
277 spos -= 0x10000L;
278 }
279 }
280
3154bfab 281 *spu.XAFeed++=l;
ef79bbde 282
3154bfab 283 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
284 if(spu.XAFeed==spu.XAPlay)
ef79bbde 285 {
3154bfab 286 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
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
609d9ea5 299#if 0
3154bfab 300 if(spu_config.iXAPitch)
ef79bbde
P
301 {
302 int32_t l1;
303 for(i=0;i<iSize;i++)
304 {
3154bfab 305 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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;
acc415b3
S
314 vr=(gauss[vl]*gvall0) >> 15;
315 vr+=(gauss[vl+1]*gvall(1)) >> 15;
316 vr+=(gauss[vl+2]*gvall(2)) >> 15;
317 vr+=(gauss[vl+3]*gvall(3)) >> 15;
318 l1=s= vr;
ef79bbde
P
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;
381ea103 332 ssat32_to_16(l1);
ef79bbde 333 l=(l1&0xffff)|(l1<<16);
3154bfab 334 *spu.XAFeed++=l;
ef79bbde 335
3154bfab 336 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
337 if(spu.XAFeed==spu.XAPlay)
ef79bbde 338 {
3154bfab 339 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
340 break;
341 }
342
343 spos += sinc;
344 }
345 }
346 else
609d9ea5 347#endif
ef79bbde
P
348 {
349 for(i=0;i<iSize;i++)
350 {
3154bfab 351 if(spu_config.iUseInterpolation==2)
ef79bbde
P
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;
acc415b3
S
360 vr=(gauss[vl]*gvall0) >> 15;
361 vr+=(gauss[vl+1]*gvall(1)) >> 15;
362 vr+=(gauss[vl+2]*gvall(2)) >> 15;
363 vr+=(gauss[vl+3]*gvall(3)) >> 15;
364 l=s= vr;
ef79bbde
P
365 }
366 else
367 {
368 while(spos>=0x10000L)
369 {
370 s = *pS++;
371 spos -= 0x10000L;
372 }
373 l=s;
374 }
375
9098b863 376 l &= 0xffff;
3154bfab 377 *spu.XAFeed++=(l|(l<<16));
ef79bbde 378
3154bfab 379 if(spu.XAFeed==spu.XAEnd) spu.XAFeed=spu.XAStart;
380 if(spu.XAFeed==spu.XAPlay)
ef79bbde 381 {
3154bfab 382 if(spu.XAPlay!=spu.XAStart) spu.XAFeed=spu.XAPlay-1;
ef79bbde
P
383 break;
384 }
385
386 spos += sinc;
387 }
388 }
389 }
390}
391
392////////////////////////////////////////////////////////////////////////
393// FEED CDDA
394////////////////////////////////////////////////////////////////////////
395
983a7cfd 396INLINE int FeedCDDA(unsigned char *pcm, int nBytes)
ef79bbde 397{
983a7cfd 398 int space;
3154bfab 399 space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1);
983a7cfd 400 if(space<nBytes)
401 return 0x7761; // rearmed_wait
402
ef79bbde
P
403 while(nBytes>0)
404 {
3154bfab 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;
983a7cfd 409 if(space>nBytes)
410 space=nBytes;
411
3154bfab 412 memcpy(spu.CDDAFeed,pcm,space);
413 spu.CDDAFeed+=space/4;
983a7cfd 414 nBytes-=space;
415 pcm+=space;
ef79bbde 416 }
983a7cfd 417
418 return 0x676f; // rearmed_go
ef79bbde
P
419}
420
421#endif