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