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