spu: rework irq handling and loop reloading
[pcsx_rearmed.git] / plugins / dfsound / spu.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 spu.c - description
3 -------------------
4 begin : Wed May 15 2002
5 copyright : (C) 2002 by Pete Bernert
6 email : BlackDove@addcom.de
07a6dd2c 7
e4f075af 8 Portions (C) GraÅžvydas "notaz" Ignotas, 2010-2012
07a6dd2c 9
ef79bbde
P
10 ***************************************************************************/
11/***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. See also the license.txt file for *
17 * additional informations. *
18 * *
19 ***************************************************************************/
20
21#include "stdafx.h"
22
23#define _IN_SPU
24
25#include "externals.h"
3fc2a4c2 26#include "registers.h"
ef79bbde 27#include "dsoundoss.h"
ef79bbde
P
28
29#ifdef ENABLE_NLS
30#include <libintl.h>
31#include <locale.h>
32#define _(x) gettext(x)
33#define N_(x) (x)
34#else
35#define _(x) (x)
36#define N_(x) (x)
37#endif
38
a80ae4a0 39#ifdef __ARM_ARCH_7A__
1775933a 40 #define ssat32_to_16(v) \
41 asm("ssat %0,#16,%1" : "=r" (v) : "r" (v))
42#else
43 #define ssat32_to_16(v) do { \
44 if (v < -32768) v = -32768; \
45 else if (v > 32767) v = 32767; \
46 } while (0)
47#endif
48
fb552464 49#define PSXCLK 33868800 /* 33.8688 MHz */
50
6d866bb7 51/*
ef79bbde
P
52#if defined (USEMACOSX)
53static char * libraryName = N_("Mac OS X Sound");
54#elif defined (USEALSA)
55static char * libraryName = N_("ALSA Sound");
56#elif defined (USEOSS)
57static char * libraryName = N_("OSS Sound");
58#elif defined (USESDL)
59static char * libraryName = N_("SDL Sound");
60#elif defined (USEPULSEAUDIO)
61static char * libraryName = N_("PulseAudio Sound");
62#else
63static char * libraryName = N_("NULL Sound");
64#endif
65
66static char * libraryInfo = N_("P.E.Op.S. Sound Driver V1.7\nCoded by Pete Bernert and the P.E.Op.S. team\n");
6d866bb7 67*/
ef79bbde
P
68
69// globals
70
71// psx buffer / addresses
72
73unsigned short regArea[10000];
74unsigned short spuMem[256*1024];
75unsigned char * spuMemC;
76unsigned char * pSpuIrq=0;
77unsigned char * pSpuBuffer;
78unsigned char * pMixIrq=0;
79
80// user settings
81
9e7a7352 82int iVolume=768; // 1024 is 1.0
ef79bbde 83int iXAPitch=1;
ef79bbde
P
84int iUseReverb=2;
85int iUseInterpolation=2;
ef79bbde
P
86
87// MAIN infos struct for each channel
88
89SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling)
90REVERBInfo rvb;
91
b1094d0e 92unsigned int dwNoiseVal; // global noise generator
93unsigned int dwNoiseCount;
ef79bbde
P
94
95unsigned short spuCtrl=0; // some vars to store psx reg infos
96unsigned short spuStat=0;
97unsigned short spuIrq=0;
98unsigned long spuAddr=0xffffffff; // address into spu mem
ef79bbde
P
99int bSpuInit=0;
100int bSPUIsOpen=0;
101
174c454a 102unsigned int dwNewChannel=0; // flags for faster testing, if new channel starts
103unsigned int dwChannelOn=0; // not silent channels
104unsigned int dwPendingChanOff=0;
105unsigned int dwChannelDead=0; // silent+not useful channels
ef79bbde
P
106
107void (CALLBACK *irqCallback)(void)=0; // func of main emu, called on spu irq
108void (CALLBACK *cddavCallback)(unsigned short,unsigned short)=0;
109
110// certain globals (were local before, but with the new timeproc I need em global)
111
6d866bb7 112static const int f[8][2] = { { 0, 0 },
ef79bbde
P
113 { 60, 0 },
114 { 115, -52 },
115 { 98, -55 },
116 { 122, -60 } };
b17618c0 117int ChanBuf[NSSIZE+3];
118int SSumLR[(NSSIZE+3)*2];
ef79bbde
P
119int iFMod[NSSIZE];
120int iCycle = 0;
121short * pS;
122
fb552464 123int had_dma;
ef79bbde
P
124int lastch=-1; // last channel processed on spu irq in timer mode
125static int lastns=0; // last ns pos
fb552464 126static int cycles_since_update;
ef79bbde 127
983a7cfd 128#define CDDA_BUFFER_SIZE (16384 * sizeof(uint32_t)) // must be power of 2
129
ef79bbde
P
130////////////////////////////////////////////////////////////////////////
131// CODE AREA
132////////////////////////////////////////////////////////////////////////
133
134// dirty inline func includes
135
136#include "reverb.c"
137#include "adsr.c"
138
139////////////////////////////////////////////////////////////////////////
140// helpers for simple interpolation
141
142//
143// easy interpolation on upsampling, no special filter, just "Pete's common sense" tm
144//
145// instead of having n equal sample values in a row like:
146// ____
147// |____
148//
149// we compare the current delta change with the next delta change.
150//
151// if curr_delta is positive,
152//
153// - and next delta is smaller (or changing direction):
154// \.
155// -__
156//
157// - and next delta significant (at least twice) bigger:
158// --_
159// \.
160//
161// - and next delta is nearly same:
162// \.
163// \.
164//
165//
166// if curr_delta is negative,
167//
168// - and next delta is smaller (or changing direction):
169// _--
170// /
171//
172// - and next delta significant (at least twice) bigger:
173// /
174// __-
175//
176// - and next delta is nearly same:
177// /
178// /
179//
180
181
182INLINE void InterpolateUp(int ch)
183{
184 if(s_chan[ch].SB[32]==1) // flag == 1? calc step and set flag... and don't change the value in this pass
185 {
186 const int id1=s_chan[ch].SB[30]-s_chan[ch].SB[29]; // curr delta to next val
187 const int id2=s_chan[ch].SB[31]-s_chan[ch].SB[30]; // and next delta to next-next val :)
188
189 s_chan[ch].SB[32]=0;
190
191 if(id1>0) // curr delta positive
192 {
193 if(id2<id1)
194 {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
195 else
196 if(id2<(id1<<1))
197 s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
198 else
199 s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L;
200 }
201 else // curr delta negative
202 {
203 if(id2>id1)
204 {s_chan[ch].SB[28]=id1;s_chan[ch].SB[32]=2;}
205 else
206 if(id2>(id1<<1))
207 s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x10000L;
208 else
209 s_chan[ch].SB[28]=(id1*s_chan[ch].sinc)/0x20000L;
210 }
211 }
212 else
213 if(s_chan[ch].SB[32]==2) // flag 1: calc step and set flag... and don't change the value in this pass
214 {
215 s_chan[ch].SB[32]=0;
216
217 s_chan[ch].SB[28]=(s_chan[ch].SB[28]*s_chan[ch].sinc)/0x20000L;
76d1d09c 218 //if(s_chan[ch].sinc<=0x8000)
219 // s_chan[ch].SB[29]=s_chan[ch].SB[30]-(s_chan[ch].SB[28]*((0x10000/s_chan[ch].sinc)-1));
220 //else
221 s_chan[ch].SB[29]+=s_chan[ch].SB[28];
ef79bbde
P
222 }
223 else // no flags? add bigger val (if possible), calc smaller step, set flag1
224 s_chan[ch].SB[29]+=s_chan[ch].SB[28];
225}
226
227//
228// even easier interpolation on downsampling, also no special filter, again just "Pete's common sense" tm
229//
230
231INLINE void InterpolateDown(int ch)
232{
233 if(s_chan[ch].sinc>=0x20000L) // we would skip at least one val?
234 {
235 s_chan[ch].SB[29]+=(s_chan[ch].SB[30]-s_chan[ch].SB[29])/2; // add easy weight
236 if(s_chan[ch].sinc>=0x30000L) // we would skip even more vals?
237 s_chan[ch].SB[29]+=(s_chan[ch].SB[31]-s_chan[ch].SB[30])/2;// add additional next weight
238 }
239}
240
241////////////////////////////////////////////////////////////////////////
242// helpers for gauss interpolation
243
244#define gval0 (((short*)(&s_chan[ch].SB[29]))[gpos])
245#define gval(x) (((short*)(&s_chan[ch].SB[29]))[(gpos+x)&3])
246
247#include "gauss_i.h"
248
249////////////////////////////////////////////////////////////////////////
250
251#include "xa.c"
252
e4f075af 253static void do_irq(void)
254{
255 //if(!(spuStat & STAT_IRQ))
256 {
257 spuStat |= STAT_IRQ; // asserted status?
258 if(irqCallback) irqCallback();
259 }
260}
261
262static int check_irq(int ch, unsigned char *pos)
263{
264 if((spuCtrl & CTRL_IRQ) && pos == pSpuIrq)
265 {
266 //printf("ch%d irq %04x\n", ch, pos - spuMemC);
267 do_irq();
268 return 1;
269 }
270 return 0;
271}
272
ef79bbde
P
273////////////////////////////////////////////////////////////////////////
274// START SOUND... called by main thread to setup a new sound on a channel
275////////////////////////////////////////////////////////////////////////
276
277INLINE void StartSound(int ch)
278{
279 StartADSR(ch);
280 StartREVERB(ch);
281
b00afb77 282 // fussy timing issues - do in VoiceOn
283 //s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start
284 //s_chan[ch].bStop=0;
285 //s_chan[ch].bOn=1;
ef79bbde 286
381ea103 287 s_chan[ch].SB[26]=0; // init mixing vars
288 s_chan[ch].SB[27]=0;
ef79bbde
P
289 s_chan[ch].iSBPos=28;
290
ef79bbde
P
291 s_chan[ch].SB[29]=0; // init our interpolation helpers
292 s_chan[ch].SB[30]=0;
293
294 if(iUseInterpolation>=2) // gauss interpolation?
295 {s_chan[ch].spos=0x30000L;s_chan[ch].SB[28]=0;} // -> start with more decoding
296 else {s_chan[ch].spos=0x10000L;s_chan[ch].SB[31]=0;} // -> no/simple interpolation starts with one 44100 decoding
297
e4f075af 298 check_irq(ch, s_chan[ch].pCurr); // just in case
299
ef79bbde
P
300 dwNewChannel&=~(1<<ch); // clear new channel bit
301}
302
303////////////////////////////////////////////////////////////////////////
304// ALL KIND OF HELPERS
305////////////////////////////////////////////////////////////////////////
306
07a6dd2c 307INLINE int FModChangeFrequency(int ch,int ns)
ef79bbde 308{
7e44d49d 309 unsigned int NP=s_chan[ch].iRawPitch;
07a6dd2c 310 int sinc;
ef79bbde
P
311
312 NP=((32768L+iFMod[ns])*NP)/32768L;
313
314 if(NP>0x3fff) NP=0x3fff;
315 if(NP<0x1) NP=0x1;
316
7e44d49d 317 sinc=NP<<4; // calc frequency
ef79bbde 318 if(iUseInterpolation==1) // freq change in simple interpolation mode
07a6dd2c 319 s_chan[ch].SB[32]=1;
ef79bbde 320 iFMod[ns]=0;
07a6dd2c 321
322 return sinc;
ef79bbde
P
323}
324
325////////////////////////////////////////////////////////////////////////
326
ef79bbde
P
327INLINE void StoreInterpolationVal(int ch,int fa)
328{
329 if(s_chan[ch].bFMod==2) // fmod freq channel
330 s_chan[ch].SB[29]=fa;
331 else
332 {
381ea103 333 ssat32_to_16(fa);
ef79bbde
P
334
335 if(iUseInterpolation>=2) // gauss/cubic interpolation
336 {
337 int gpos = s_chan[ch].SB[28];
338 gval0 = fa;
339 gpos = (gpos+1) & 3;
340 s_chan[ch].SB[28] = gpos;
341 }
342 else
343 if(iUseInterpolation==1) // simple interpolation
344 {
345 s_chan[ch].SB[28] = 0;
346 s_chan[ch].SB[29] = s_chan[ch].SB[30]; // -> helpers for simple linear interpolation: delay real val for two slots, and calc the two deltas, for a 'look at the future behaviour'
347 s_chan[ch].SB[30] = s_chan[ch].SB[31];
348 s_chan[ch].SB[31] = fa;
349 s_chan[ch].SB[32] = 1; // -> flag: calc new interolation
350 }
351 else s_chan[ch].SB[29]=fa; // no interpolation
352 }
353}
354
355////////////////////////////////////////////////////////////////////////
356
8cd23d6d 357INLINE int iGetInterpolationVal(int ch, int spos)
ef79bbde
P
358{
359 int fa;
360
361 if(s_chan[ch].bFMod==2) return s_chan[ch].SB[29];
362
363 switch(iUseInterpolation)
364 {
365 //--------------------------------------------------//
366 case 3: // cubic interpolation
367 {
368 long xd;int gpos;
8cd23d6d 369 xd = (spos >> 1)+1;
ef79bbde
P
370 gpos = s_chan[ch].SB[28];
371
372 fa = gval(3) - 3*gval(2) + 3*gval(1) - gval0;
373 fa *= (xd - (2<<15)) / 6;
374 fa >>= 15;
375 fa += gval(2) - gval(1) - gval(1) + gval0;
376 fa *= (xd - (1<<15)) >> 1;
377 fa >>= 15;
378 fa += gval(1) - gval0;
379 fa *= xd;
380 fa >>= 15;
381 fa = fa + gval0;
382
383 } break;
384 //--------------------------------------------------//
385 case 2: // gauss interpolation
386 {
387 int vl, vr;int gpos;
8cd23d6d 388 vl = (spos >> 6) & ~3;
ef79bbde
P
389 gpos = s_chan[ch].SB[28];
390 vr=(gauss[vl]*gval0)&~2047;
391 vr+=(gauss[vl+1]*gval(1))&~2047;
392 vr+=(gauss[vl+2]*gval(2))&~2047;
393 vr+=(gauss[vl+3]*gval(3))&~2047;
394 fa = vr>>11;
395 } break;
396 //--------------------------------------------------//
397 case 1: // simple interpolation
398 {
399 if(s_chan[ch].sinc<0x10000L) // -> upsampling?
400 InterpolateUp(ch); // --> interpolate up
401 else InterpolateDown(ch); // --> else down
402 fa=s_chan[ch].SB[29];
403 } break;
404 //--------------------------------------------------//
405 default: // no interpolation
406 {
407 fa=s_chan[ch].SB[29];
408 } break;
409 //--------------------------------------------------//
410 }
411
412 return fa;
413}
414
381ea103 415static void decode_block_data(int *dest, const unsigned char *src, int predict_nr, int shift_factor)
416{
417 int nSample;
418 int fa, s_1, s_2, d, s;
419
420 s_1 = dest[27];
421 s_2 = dest[26];
422
423 for (nSample = 0; nSample < 28; src++)
424 {
425 d = (int)*src;
426 s = (int)(signed short)((d & 0x0f) << 12);
427
428 fa = s >> shift_factor;
429 fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
430 s_2=s_1;s_1=fa;
431
432 dest[nSample++] = fa;
433
434 s = (int)(signed short)((d & 0xf0) << 8);
435 fa = s >> shift_factor;
436 fa += ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
437 s_2=s_1;s_1=fa;
438
439 dest[nSample++] = fa;
440 }
441}
442
e11ae5c5 443static int decode_block(int ch)
444{
445 unsigned char *start;
381ea103 446 int predict_nr,shift_factor,flags;
e11ae5c5 447 int ret = 0;
448
e11ae5c5 449 start=s_chan[ch].pCurr; // set up the current pos
e11ae5c5 450
e4f075af 451 if(s_chan[ch].prevflags&1) // 1: stop/loop
3fc2a4c2 452 {
e4f075af 453 if(!(s_chan[ch].prevflags&2))
3fc2a4c2 454 {
e4f075af 455 dwChannelOn&=~(1<<ch); // -> turn everything off
456 s_chan[ch].bStop=1;
457 s_chan[ch].ADSRX.EnvelopeVol=0;
3fc2a4c2 458 }
e4f075af 459
460 start = s_chan[ch].pLoop;
3fc2a4c2 461 }
e11ae5c5 462
381ea103 463 predict_nr=(int)start[0];
e11ae5c5 464 shift_factor=predict_nr&0xf;
465 predict_nr >>= 4;
e11ae5c5 466
381ea103 467 decode_block_data(s_chan[ch].SB, start + 2, predict_nr, shift_factor);
e11ae5c5 468
381ea103 469 flags=(int)start[1];
470 if(flags&4)
471 s_chan[ch].pLoop=start; // loop adress
e11ae5c5 472
381ea103 473 start+=16;
3fc2a4c2 474
e4f075af 475 if(flags&1) // 1: stop/loop
3fc2a4c2 476 start = s_chan[ch].pLoop;
e11ae5c5 477
e4f075af 478 if (start - spuMemC >= 0x80000)
174c454a 479 start = spuMemC;
e4f075af 480
481 ret = check_irq(ch, start);
e11ae5c5 482
381ea103 483 s_chan[ch].pCurr = start; // store values for next cycle
e4f075af 484 s_chan[ch].prevflags = flags;
e11ae5c5 485
486 return ret;
487}
488
07a6dd2c 489// do block, but ignore sample data
490static int skip_block(int ch)
491{
492 unsigned char *start = s_chan[ch].pCurr;
493 int flags = start[1];
07a6dd2c 494
e4f075af 495 if(s_chan[ch].prevflags & 1)
496 start = s_chan[ch].pLoop;
07a6dd2c 497
381ea103 498 if(flags & 4)
be1cb678 499 s_chan[ch].pLoop = start;
07a6dd2c 500
e4f075af 501 start += 16;
07a6dd2c 502
503 if(flags & 1)
e4f075af 504 start = s_chan[ch].pLoop;
07a6dd2c 505
e4f075af 506 s_chan[ch].pCurr = start;
507 s_chan[ch].prevflags = flags;
508
509 return check_irq(ch, start);
07a6dd2c 510}
511
512#define make_do_samples(name, fmod_code, interp_start, interp1_code, interp2_code, interp_end) \
513static int do_samples_##name(int ch, int ns, int ns_to) \
514{ \
515 int sinc = s_chan[ch].sinc; \
516 int spos = s_chan[ch].spos; \
381ea103 517 int sbpos = s_chan[ch].iSBPos; \
518 int *SB = s_chan[ch].SB; \
07a6dd2c 519 int ret = -1; \
520 int d, fa; \
521 interp_start; \
522 \
523 for (; ns < ns_to; ns++) \
524 { \
525 fmod_code; \
526 \
527 while (spos >= 0x10000) \
528 { \
381ea103 529 if(sbpos == 28) \
07a6dd2c 530 { \
381ea103 531 sbpos = 0; \
07a6dd2c 532 d = decode_block(ch); \
f2aec10a 533 if(d) \
07a6dd2c 534 { \
535 ret = ns; \
536 goto out; \
537 } \
538 } \
539 \
381ea103 540 fa = SB[sbpos++]; \
07a6dd2c 541 interp1_code; \
542 spos -= 0x10000; \
543 } \
544 \
545 interp2_code; \
546 spos += sinc; \
547 } \
548 \
549out: \
550 s_chan[ch].sinc = sinc; \
551 s_chan[ch].spos = spos; \
381ea103 552 s_chan[ch].iSBPos = sbpos; \
07a6dd2c 553 interp_end; \
554 \
555 return ret; \
556}
557
558#define fmod_recv_check \
559 if(s_chan[ch].bFMod==1 && iFMod[ns]) \
560 sinc = FModChangeFrequency(ch,ns)
561
562make_do_samples(default, fmod_recv_check, ,
563 StoreInterpolationVal(ch, fa),
8cd23d6d 564 ChanBuf[ns] = iGetInterpolationVal(ch, spos), )
07a6dd2c 565make_do_samples(noint, , fa = s_chan[ch].SB[29], , ChanBuf[ns] = fa, s_chan[ch].SB[29] = fa)
566
567#define simple_interp_store \
568 s_chan[ch].SB[28] = 0; \
569 s_chan[ch].SB[29] = s_chan[ch].SB[30]; \
570 s_chan[ch].SB[30] = s_chan[ch].SB[31]; \
571 s_chan[ch].SB[31] = fa; \
572 s_chan[ch].SB[32] = 1
573
574#define simple_interp_get \
575 if(sinc<0x10000) /* -> upsampling? */ \
576 InterpolateUp(ch); /* --> interpolate up */ \
577 else InterpolateDown(ch); /* --> else down */ \
578 ChanBuf[ns] = s_chan[ch].SB[29]
579
580make_do_samples(simple, , ,
581 simple_interp_store, simple_interp_get, )
582
583static int do_samples_noise(int ch, int ns, int ns_to)
584{
b1094d0e 585 int level, shift, bit;
586
07a6dd2c 587 s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns);
588 while (s_chan[ch].spos >= 28*0x10000)
589 {
590 skip_block(ch);
591 s_chan[ch].spos -= 28*0x10000;
592 }
593
b1094d0e 594 // modified from DrHell/shalma, no fraction
595 level = (spuCtrl >> 10) & 0x0f;
596 level = 0x8000 >> level;
597
07a6dd2c 598 for (; ns < ns_to; ns++)
b1094d0e 599 {
600 dwNoiseCount += 2;
601 if (dwNoiseCount >= level)
602 {
603 dwNoiseCount -= level;
604 shift = (dwNoiseVal >> 10) & 0x1f;
605 bit = (0x69696969 >> shift) & 1;
606 if (dwNoiseVal & 0x8000)
607 bit ^= 1;
608 dwNoiseVal = (dwNoiseVal << 1) | bit;
609 }
610
611 ChanBuf[ns] = (signed short)dwNoiseVal;
612 }
07a6dd2c 613
614 return -1;
615}
616
3a721c1f 617#ifdef __arm__
618// asm code; lv and rv must be 0-3fff
b17618c0 619extern void mix_chan(int start, int count, int lv, int rv);
620extern void mix_chan_rvb(int start, int count, int lv, int rv);
621#else
622static void mix_chan(int start, int count, int lv, int rv)
623{
624 int *dst = SSumLR + start * 2;
625 const int *src = ChanBuf + start;
626 int l, r;
627
628 while (count--)
629 {
630 int sval = *src++;
631
632 l = (sval * lv) >> 14;
633 r = (sval * rv) >> 14;
634 *dst++ += l;
635 *dst++ += r;
636 }
637}
638
639static void mix_chan_rvb(int start, int count, int lv, int rv)
640{
641 int *dst = SSumLR + start * 2;
642 int *drvb = sRVBStart + start * 2;
643 const int *src = ChanBuf + start;
644 int l, r;
645
646 while (count--)
647 {
648 int sval = *src++;
649
650 l = (sval * lv) >> 14;
651 r = (sval * rv) >> 14;
652 *dst++ += l;
653 *dst++ += r;
654 *drvb++ += l;
655 *drvb++ += r;
656 }
657}
658#endif
659
ef79bbde
P
660////////////////////////////////////////////////////////////////////////
661// MAIN SPU FUNCTION
6d75977b 662// here is the main job handler...
ef79bbde
P
663// basically the whole sound processing is done in this fat func!
664////////////////////////////////////////////////////////////////////////
665
fb552464 666static int do_samples(int forced_updates)
ef79bbde 667{
9e7a7352 668 int volmult = iVolume;
07a6dd2c 669 int ns,ns_from,ns_to;
174c454a 670 int ch,d,silentch;
ef79bbde
P
671 int bIRQReturn=0;
672
6d75977b 673 while(1)
ef79bbde
P
674 {
675 // ok, at the beginning we are looking if there is
676 // enuff free place in the dsound/oss buffer to
677 // fill in new data, or if there is a new channel to start.
678 // if not, we wait (thread) or return (timer/spuasync)
679 // until enuff free place is available/a new channel gets
680 // started
681
fb552464 682 if(!forced_updates && SoundGetBytesBuffered()) // still enuff data in sound buffer?
ef79bbde 683 {
6d75977b 684 return 0;
ef79bbde
P
685 }
686
fb552464 687 cycles_since_update = 0;
688 if(forced_updates > 0)
689 forced_updates--;
690
ef79bbde
P
691 //--------------------------------------------------// continue from irq handling in timer mode?
692
8680e822 693 ns_from=0;
694 ns_to=NSSIZE;
695 ch=0;
ef79bbde
P
696 if(lastch>=0) // will be -1 if no continue is pending
697 {
e11ae5c5 698 ch=lastch; ns_from=lastns; lastch=-1; // -> setup all kind of vars to continue
ef79bbde
P
699 }
700
174c454a 701 silentch=~(dwChannelOn|dwNewChannel);
702
ef79bbde
P
703 //--------------------------------------------------//
704 //- main channel loop -//
705 //--------------------------------------------------//
706 {
8680e822 707 for(;ch<MAXCHAN;ch++) // loop em all... we will collect 1 ms of sound of each playing channel
ef79bbde 708 {
6d866bb7 709 if(dwNewChannel&(1<<ch)) StartSound(ch); // start new sound
710 if(!(dwChannelOn&(1<<ch))) continue; // channel not playing? next
ef79bbde 711
07a6dd2c 712 if(s_chan[ch].bNoise)
713 d=do_samples_noise(ch, ns_from, ns_to);
714 else if(s_chan[ch].bFMod==2 || (s_chan[ch].bFMod==0 && iUseInterpolation==0))
715 d=do_samples_noint(ch, ns_from, ns_to);
716 else if(s_chan[ch].bFMod==0 && iUseInterpolation==1)
717 d=do_samples_simple(ch, ns_from, ns_to);
718 else
719 d=do_samples_default(ch, ns_from, ns_to);
720 if(d>=0)
ef79bbde 721 {
07a6dd2c 722 bIRQReturn=1;
723 lastch=ch;
724 lastns=ns_to=d;
587fa7de 725 if(d==0)
726 break;
1ab7621a 727 }
ef79bbde 728
1ab7621a 729 MixADSR(ch, ns_from, ns_to);
730
731 if(s_chan[ch].bFMod==2) // fmod freq channel
732 memcpy(iFMod, ChanBuf, sizeof(iFMod));
b17618c0 733 else if(s_chan[ch].bRVBActive)
734 mix_chan_rvb(ns_from,ns_to-ns_from,s_chan[ch].iLeftVolume,s_chan[ch].iRightVolume);
1775933a 735 else
b17618c0 736 mix_chan(ns_from,ns_to-ns_from,s_chan[ch].iLeftVolume,s_chan[ch].iRightVolume);
ef79bbde
P
737 }
738 }
739
78c60846 740 // advance "stopped" channels that can cause irqs
741 // (all chans are always playing on the real thing..)
f2aec10a 742 if(spuCtrl&CTRL_IRQ)
78c60846 743 for(ch=0;ch<MAXCHAN;ch++)
744 {
174c454a 745 if(!(silentch&(1<<ch))) continue; // already handled
746 if(dwChannelDead&(1<<ch)) continue;
78c60846 747 if(s_chan[ch].pCurr > pSpuIrq && s_chan[ch].pLoop > pSpuIrq)
748 continue;
749
f2aec10a 750 s_chan[ch].spos += s_chan[ch].sinc * (ns_to - ns_from);
78c60846 751 while(s_chan[ch].spos >= 28 * 0x10000)
752 {
7e44d49d 753 unsigned char *start = s_chan[ch].pCurr;
78c60846 754
a3ed1915 755 // no need for bIRQReturn since the channel is silent
fb552464 756 skip_block(ch);
07a6dd2c 757 if(start == s_chan[ch].pCurr)
78c60846 758 {
759 // looping on self
7e44d49d 760 dwChannelDead |= 1<<ch;
761 s_chan[ch].spos = 0;
78c60846 762 break;
763 }
764
78c60846 765 s_chan[ch].spos -= 28 * 0x10000;
766 }
767 }
768
f2aec10a 769 if(bIRQReturn) // special return for "spu irq - wait for cpu action"
6d75977b 770 return 0;
8680e822 771
772
ef79bbde
P
773 //---------------------------------------------------//
774 //- here we have another 1 ms of sound data
775 //---------------------------------------------------//
776 // mix XA infos (if any)
777
778 MixXA();
779
780 ///////////////////////////////////////////////////////
781 // mix all channels (including reverb) into one buffer
782
1775933a 783 if(iUseReverb)
784 REVERBDo();
785
786 if((spuCtrl&0x4000)==0) // muted? (rare, don't optimize for this)
787 {
788 memset(pS, 0, NSSIZE * 2 * sizeof(pS[0]));
789 pS += NSSIZE*2;
790 }
791 else
97ea4077 792 for (ns = 0; ns < NSSIZE*2; )
ef79bbde 793 {
9e7a7352 794 d = SSumLR[ns]; SSumLR[ns] = 0;
795 d = d * volmult >> 10;
1775933a 796 ssat32_to_16(d);
ef79bbde 797 *pS++ = d;
97ea4077 798 ns++;
ef79bbde 799
9e7a7352 800 d = SSumLR[ns]; SSumLR[ns] = 0;
801 d = d * volmult >> 10;
1775933a 802 ssat32_to_16(d);
ef79bbde 803 *pS++ = d;
97ea4077 804 ns++;
ef79bbde
P
805 }
806
807 //////////////////////////////////////////////////////
808 // special irq handling in the decode buffers (0x0000-0x1000)
809 // we know:
810 // the decode buffers are located in spu memory in the following way:
811 // 0x0000-0x03ff CD audio left
812 // 0x0400-0x07ff CD audio right
813 // 0x0800-0x0bff Voice 1
814 // 0x0c00-0x0fff Voice 3
815 // and decoded data is 16 bit for one sample
816 // we assume:
817 // even if voices 1/3 are off or no cd audio is playing, the internal
818 // play positions will move on and wrap after 0x400 bytes.
819 // Therefore: we just need a pointer from spumem+0 to spumem+3ff, and
820 // increase this pointer on each sample by 2 bytes. If this pointer
821 // (or 0x400 offsets of this pointer) hits the spuirq address, we generate
822 // an IRQ. Only problem: the "wait for cpu" option is kinda hard to do here
823 // in some of Peops timer modes. So: we ignore this option here (for now).
824
e4f075af 825 if(pMixIrq && (spuCtrl&CTRL_IRQ) && pSpuIrq && pSpuIrq<spuMemC+0x1000)
ef79bbde
P
826 {
827 for(ns=0;ns<NSSIZE;ns++)
828 {
ef79bbde
P
829 for(ch=0;ch<4;ch++)
830 {
831 if(pSpuIrq>=pMixIrq+(ch*0x400) && pSpuIrq<pMixIrq+(ch*0x400)+2)
3fc2a4c2 832 do_irq();
ef79bbde 833 }
ef79bbde
P
834 pMixIrq+=2;if(pMixIrq>spuMemC+0x3ff) pMixIrq=spuMemC;
835 }
836 }
837
838 InitREVERB();
839
840 // feed the sound
841 // wanna have around 1/60 sec (16.666 ms) updates
381ea103 842 if (iCycle++ > 16/FRAG_MSECS)
ef79bbde
P
843 {
844 SoundFeedStreamData((unsigned char *)pSpuBuffer,
845 ((unsigned char *)pS) - ((unsigned char *)pSpuBuffer));
846 pS = (short *)pSpuBuffer;
847 iCycle = 0;
848 }
849 }
850
ef79bbde
P
851 return 0;
852}
853
854// SPU ASYNC... even newer epsxe func
855// 1 time every 'cycle' cycles... harhar
856
554a2220 857// rearmed: called every 2ms now
858
ef79bbde
P
859void CALLBACK SPUasync(unsigned long cycle)
860{
e4f075af 861 static int old_ctrl;
fb552464 862 int forced_updates = 0;
863 int do_update = 0;
864
f8edb5bc 865 if(!bSpuInit) return; // -> no init, no call
866
fb552464 867 cycles_since_update += cycle;
868
869 if(dwNewChannel || had_dma)
ef79bbde 870 {
fb552464 871 forced_updates = 1;
872 do_update = 1;
873 had_dma = 0;
ef79bbde
P
874 }
875
e4f075af 876 if((spuCtrl&CTRL_IRQ) && (((spuCtrl^old_ctrl)&CTRL_IRQ) // irq was enabled
877 || cycles_since_update > PSXCLK/60 / 4)) {
fb552464 878 do_update = 1;
e4f075af 879 forced_updates = cycles_since_update / (PSXCLK/44100) / NSSIZE;
880 }
881 // with no irqs, once per frame should be fine (using a bit more because of BIAS)
882 else if(cycles_since_update > PSXCLK/60 * 5/4)
883 do_update = 1;
884
885 old_ctrl = spuCtrl;
fb552464 886
887 if(do_update)
888 do_samples(forced_updates);
ef79bbde
P
889}
890
891// SPU UPDATE... new epsxe func
892// 1 time every 32 hsync lines
893// (312/32)x50 in pal
894// (262/32)x60 in ntsc
895
896// since epsxe 1.5.2 (linux) uses SPUupdate, not SPUasync, I will
897// leave that func in the linux port, until epsxe linux is using
898// the async function as well
899
900void CALLBACK SPUupdate(void)
901{
902 SPUasync(0);
903}
904
905// XA AUDIO
906
907void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap)
908{
909 if(!xap) return;
910 if(!xap->freq) return; // no xa freq ? bye
911
912 FeedXA(xap); // call main XA feeder
913}
914
915// CDDA AUDIO
983a7cfd 916int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes)
ef79bbde 917{
983a7cfd 918 if (!pcm) return -1;
919 if (nbytes<=0) return -1;
ef79bbde 920
983a7cfd 921 return FeedCDDA((unsigned char *)pcm, nbytes);
ef79bbde
P
922}
923
6d75977b 924// to be called after state load
925void ClearWorkingState(void)
ef79bbde 926{
97ea4077 927 memset(SSumLR,0,sizeof(SSumLR)); // init some mixing buffers
6d75977b 928 memset(iFMod,0,sizeof(iFMod));
ef79bbde 929 pS=(short *)pSpuBuffer; // setup soundbuffer pointer
ef79bbde
P
930}
931
932// SETUPSTREAMS: init most of the spu buffers
933void SetupStreams(void)
934{
935 int i;
936
937 pSpuBuffer=(unsigned char *)malloc(32768); // alloc mixing buffer
938
939 if(iUseReverb==1) i=88200*2;
940 else i=NSSIZE*2;
941
942 sRVBStart = (int *)malloc(i*4); // alloc reverb buffer
943 memset(sRVBStart,0,i*4);
944 sRVBEnd = sRVBStart + i;
945 sRVBPlay = sRVBStart;
946
947 XAStart = // alloc xa buffer
948 (uint32_t *)malloc(44100 * sizeof(uint32_t));
949 XAEnd = XAStart + 44100;
950 XAPlay = XAStart;
951 XAFeed = XAStart;
952
953 CDDAStart = // alloc cdda buffer
983a7cfd 954 (uint32_t *)malloc(CDDA_BUFFER_SIZE);
ef79bbde
P
955 CDDAEnd = CDDAStart + 16384;
956 CDDAPlay = CDDAStart;
b8e744ce 957 CDDAFeed = CDDAStart;
ef79bbde
P
958
959 for(i=0;i<MAXCHAN;i++) // loop sound channels
960 {
961// we don't use mutex sync... not needed, would only
962// slow us down:
963// s_chan[i].hMutex=CreateMutex(NULL,FALSE,NULL);
6d866bb7 964 s_chan[i].ADSRX.SustainLevel = 0xf; // -> init sustain
ef79bbde 965 s_chan[i].pLoop=spuMemC;
ef79bbde
P
966 s_chan[i].pCurr=spuMemC;
967 }
968
6d75977b 969 pMixIrq=spuMemC; // enable decoded buffer irqs by setting the address
970
971 ClearWorkingState();
972
973 bSpuInit=1; // flag: we are inited
ef79bbde
P
974}
975
976// REMOVESTREAMS: free most buffer
977void RemoveStreams(void)
978{
979 free(pSpuBuffer); // free mixing buffer
980 pSpuBuffer = NULL;
981 free(sRVBStart); // free reverb buffer
982 sRVBStart = NULL;
983 free(XAStart); // free XA buffer
984 XAStart = NULL;
985 free(CDDAStart); // free CDDA buffer
986 CDDAStart = NULL;
987}
988
989// INIT/EXIT STUFF
990
991// SPUINIT: this func will be called first by the main emu
992long CALLBACK SPUinit(void)
993{
994 spuMemC = (unsigned char *)spuMem; // just small setup
995 memset((void *)&rvb, 0, sizeof(REVERBInfo));
996 InitADSR();
997
ef79bbde
P
998 spuIrq = 0;
999 spuAddr = 0xffffffff;
ef79bbde
P
1000 spuMemC = (unsigned char *)spuMem;
1001 pMixIrq = 0;
1002 memset((void *)s_chan, 0, (MAXCHAN + 1) * sizeof(SPUCHAN));
1003 pSpuIrq = 0;
ef79bbde
P
1004 lastch = -1;
1005
ef79bbde
P
1006 SetupStreams(); // prepare streaming
1007
1008 return 0;
1009}
1010
1011// SPUOPEN: called by main emu after init
1012long CALLBACK SPUopen(void)
1013{
1014 if (bSPUIsOpen) return 0; // security for some stupid main emus
1015
1016 SetupSound(); // setup sound (before init!)
ef79bbde
P
1017
1018 bSPUIsOpen = 1;
1019
1020 return PSE_SPU_ERR_SUCCESS;
1021}
1022
1023// SPUCLOSE: called before shutdown
1024long CALLBACK SPUclose(void)
1025{
1026 if (!bSPUIsOpen) return 0; // some security
1027
1028 bSPUIsOpen = 0; // no more open
1029
ef79bbde
P
1030 RemoveSound(); // no more sound handling
1031
1032 return 0;
1033}
1034
1035// SPUSHUTDOWN: called by main emu on final exit
1036long CALLBACK SPUshutdown(void)
1037{
1038 SPUclose();
1039 RemoveStreams(); // no more streaming
6d75977b 1040 bSpuInit=0;
ef79bbde
P
1041
1042 return 0;
1043}
1044
1045// SPUTEST: we don't test, we are always fine ;)
1046long CALLBACK SPUtest(void)
1047{
1048 return 0;
1049}
1050
1051// SPUCONFIGURE: call config dialog
1052long CALLBACK SPUconfigure(void)
1053{
1054#ifdef _MACOSX
1055 DoConfiguration();
1056#else
ee849648 1057// StartCfgTool("CFG");
ef79bbde
P
1058#endif
1059 return 0;
1060}
1061
1062// SPUABOUT: show about window
1063void CALLBACK SPUabout(void)
1064{
1065#ifdef _MACOSX
1066 DoAbout();
1067#else
ee849648 1068// StartCfgTool("ABOUT");
ef79bbde
P
1069#endif
1070}
1071
1072// SETUP CALLBACKS
1073// this functions will be called once,
1074// passes a callback that should be called on SPU-IRQ/cdda volume change
1075void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void))
1076{
1077 irqCallback = callback;
1078}
1079
1080void CALLBACK SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short))
1081{
1082 cddavCallback = CDDAVcallback;
1083}
1084
1085// COMMON PLUGIN INFO FUNCS
e906c010 1086/*
ef79bbde
P
1087char * CALLBACK PSEgetLibName(void)
1088{
1089 return _(libraryName);
1090}
1091
1092unsigned long CALLBACK PSEgetLibType(void)
1093{
1094 return PSE_LT_SPU;
1095}
1096
1097unsigned long CALLBACK PSEgetLibVersion(void)
1098{
1099 return (1 << 16) | (6 << 8);
1100}
1101
1102char * SPUgetLibInfos(void)
1103{
1104 return _(libraryInfo);
1105}
e906c010 1106*/
6d866bb7 1107
90f1d26c 1108// debug
174c454a 1109void spu_get_debug_info(int *chans_out, int *run_chans, int *fmod_chans_out, int *noise_chans_out)
90f1d26c 1110{
174c454a 1111 int ch = 0, fmod_chans = 0, noise_chans = 0, irq_chans = 0;
90f1d26c 1112
1113 for(;ch<MAXCHAN;ch++)
1114 {
1115 if (!(dwChannelOn & (1<<ch)))
1116 continue;
1117 if (s_chan[ch].bFMod == 2)
1118 fmod_chans |= 1 << ch;
1119 if (s_chan[ch].bNoise)
1120 noise_chans |= 1 << ch;
174c454a 1121 if((spuCtrl&CTRL_IRQ) && s_chan[ch].pCurr <= pSpuIrq && s_chan[ch].pLoop <= pSpuIrq)
1122 irq_chans |= 1 << ch;
90f1d26c 1123 }
1124
1125 *chans_out = dwChannelOn;
174c454a 1126 *run_chans = ~dwChannelOn & ~dwChannelDead & irq_chans;
90f1d26c 1127 *fmod_chans_out = fmod_chans;
1128 *noise_chans_out = noise_chans;
1129}
1130
6d866bb7 1131// vim:shiftwidth=1:expandtab