comparison src/psf2/peops/spu.c @ 2737:62cc6d667119

Import a bunch of stuff for new psf2 plugin.
author William Pitcock <nenolod@atheme.org>
date Mon, 30 Jun 2008 20:20:53 -0500
parents
children f1482af6384c
comparison
equal deleted inserted replaced
2731:324f950774cb 2737:62cc6d667119
1 /***************************************************************************
2 spu.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 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. See also the license.txt file for *
15 * additional informations. *
16 * *
17 ***************************************************************************/
18
19 //*************************************************************************//
20 // History of changes:
21 //
22 // 2003/03/01 - linuzappz
23 // - libraryName changes using ALSA
24 //
25 // 2003/02/28 - Pete
26 // - added option for type of interpolation
27 // - adjusted spu irqs again (Thousant Arms, Valkyrie Profile)
28 // - added MONO support for MSWindows DirectSound
29 //
30 // 2003/02/20 - kode54
31 // - amended interpolation code, goto GOON could skip initialization of gpos and cause segfault
32 //
33 // 2003/02/19 - kode54
34 // - moved SPU IRQ handler and changed sample flag processing
35 //
36 // 2003/02/18 - kode54
37 // - moved ADSR calculation outside of the sample decode loop, somehow I doubt that
38 // ADSR timing is relative to the frequency at which a sample is played... I guess
39 // this remains to be seen, and I don't know whether ADSR is applied to noise channels...
40 //
41 // 2003/02/09 - kode54
42 // - one-shot samples now process the end block before stopping
43 // - in light of removing fmod hack, now processing ADSR on frequency channel as well
44 //
45 // 2003/02/08 - kode54
46 // - replaced easy interpolation with gaussian
47 // - removed fmod averaging hack
48 // - changed .sinc to be updated from .iRawPitch, no idea why it wasn't done this way already (<- Pete: because I sometimes fail to see the obvious, haharhar :)
49 //
50 // 2003/02/08 - linuzappz
51 // - small bugfix for one usleep that was 1 instead of 1000
52 // - added iDisStereo for no stereo (Linux)
53 //
54 // 2003/01/22 - Pete
55 // - added easy interpolation & small noise adjustments
56 //
57 // 2003/01/19 - Pete
58 // - added Neill's reverb
59 //
60 // 2003/01/12 - Pete
61 // - added recording window handlers
62 //
63 // 2003/01/06 - Pete
64 // - added Neill's ADSR timings
65 //
66 // 2002/12/28 - Pete
67 // - adjusted spu irq handling, fmod handling and loop handling
68 //
69 // 2002/08/14 - Pete
70 // - added extra reverb
71 //
72 // 2002/06/08 - linuzappz
73 // - SPUupdate changed for SPUasync
74 //
75 // 2002/05/15 - Pete
76 // - generic cleanup for the Peops release
77 //
78 //*************************************************************************//
79
80 #define _IN_SPU
81
82 #include "../peops/stdafx.h"
83 #include "../peops/externals.h"
84 #include "../peops/regs.h"
85 #include "../peops/registers.h"
86 #include "../peops/spu.h"
87
88 void SPUirq(void) ;
89
90 //#include "PsxMem.h"
91 //#include "driver.h"
92
93 ////////////////////////////////////////////////////////////////////////
94 // globals
95 ////////////////////////////////////////////////////////////////////////
96
97 // psx buffer / addresses
98
99 static u16 regArea[0x200];
100 static u16 spuMem[256*1024];
101 static u8 * spuMemC;
102 static u8 * pSpuIrq=0;
103 static u8 * pSpuBuffer;
104
105 // user settings
106 static int iVolume;
107
108 // MAIN infos struct for each channel
109
110 static SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling)
111 static REVERBInfo rvb;
112
113 static u32 dwNoiseVal=1; // global noise generator
114
115 static u16 spuCtrl=0; // some vars to store psx reg infos
116 static u16 spuStat=0;
117 static u16 spuIrq=0;
118 static u32 spuAddr=0xffffffff; // address into spu mem
119 static int bSPUIsOpen=0;
120
121 static const int f[5][2] = {
122 { 0, 0 },
123 { 60, 0 },
124 { 115, -52 },
125 { 98, -55 },
126 { 122, -60 } };
127 s16 * pS;
128 static s32 ttemp;
129
130 ////////////////////////////////////////////////////////////////////////
131 // CODE AREA
132 ////////////////////////////////////////////////////////////////////////
133
134 // dirty inline func includes
135
136 #include "../peops/reverb.c"
137 #include "../peops/adsr.c"
138
139 // Try this to increase speed.
140 #include "../peops/registers.c"
141 #include "../peops/dma.c"
142
143 ////////////////////////////////////////////////////////////////////////
144 // helpers for so-called "gauss interpolation"
145
146 #define gval0 (((int *)(&s_chan[ch].SB[29]))[gpos])
147 #define gval(x) (((int *)(&s_chan[ch].SB[29]))[(gpos+x)&3])
148
149 #include "gauss_i.h"
150
151 ////////////////////////////////////////////////////////////////////////
152
153 ////////////////////////////////////////////////////////////////////////
154 // START SOUND... called by main thread to setup a new sound on a channel
155 ////////////////////////////////////////////////////////////////////////
156
157 static INLINE void StartSound(int ch)
158 {
159 StartADSR(ch);
160
161 s_chan[ch].pCurr=s_chan[ch].pStart; // set sample start
162
163 s_chan[ch].s_1=0; // init mixing vars
164 s_chan[ch].s_2=0;
165 s_chan[ch].iSBPos=28;
166
167 s_chan[ch].bNew=0; // init channel flags
168 s_chan[ch].bStop=0;
169 s_chan[ch].bOn=1;
170
171 s_chan[ch].SB[29]=0; // init our interpolation helpers
172 s_chan[ch].SB[30]=0;
173
174 s_chan[ch].spos=0x40000L;s_chan[ch].SB[28]=0; // -> start with more decoding
175 }
176
177 ////////////////////////////////////////////////////////////////////////
178 // MAIN SPU FUNCTION
179 // here is the main job handler... thread, timer or direct func call
180 // basically the whole sound processing is done in this fat func!
181 ////////////////////////////////////////////////////////////////////////
182
183 static u32 sampcount;
184 static u32 decaybegin;
185 static u32 decayend;
186
187 // Counting to 65536 results in full volume offage.
188 void setlength(s32 stop, s32 fade)
189 {
190 if(stop==~0)
191 {
192 decaybegin=~0;
193 }
194 else
195 {
196 stop=(stop*441)/10;
197 fade=(fade*441)/10;
198
199 decaybegin=stop;
200 decayend=stop+fade;
201 }
202 }
203
204 #define CLIP(_x) {if(_x>32767) _x=32767; if(_x<-32767) _x=-32767;}
205 int SPUasync(u32 cycles)
206 {
207 int volmul=iVolume;
208 static s32 dosampies;
209 s32 temp;
210
211 ttemp+=cycles;
212 dosampies=ttemp/384;
213 if(!dosampies) return(1);
214 ttemp-=dosampies*384;
215 temp=dosampies;
216
217 while(temp)
218 {
219 s32 revLeft=0, revRight=0;
220 s32 sl=0, sr=0;
221 int ch,fa;
222
223 temp--;
224 //--------------------------------------------------//
225 //- main channel loop -//
226 //--------------------------------------------------//
227 {
228 for(ch=0;ch<MAXCHAN;ch++) // loop em all.
229 {
230 if(s_chan[ch].bNew) StartSound(ch); // start new sound
231 if(!s_chan[ch].bOn) continue; // channel not playing? next
232
233
234 if(s_chan[ch].iActFreq!=s_chan[ch].iUsedFreq) // new psx frequency?
235 {
236 s_chan[ch].iUsedFreq=s_chan[ch].iActFreq; // -> take it and calc steps
237 s_chan[ch].sinc=s_chan[ch].iRawPitch<<4;
238 if(!s_chan[ch].sinc) s_chan[ch].sinc=1;
239 }
240
241 while(s_chan[ch].spos>=0x10000L)
242 {
243 if(s_chan[ch].iSBPos==28) // 28 reached?
244 {
245 int predict_nr,shift_factor,flags,d,s;
246 u8* start;unsigned int nSample;
247 int s_1,s_2;
248
249 start=s_chan[ch].pCurr; // set up the current pos
250
251 if (start == (u8*)-1) // special "stop" sign
252 {
253 s_chan[ch].bOn=0; // -> turn everything off
254 s_chan[ch].ADSRX.lVolume=0;
255 s_chan[ch].ADSRX.EnvelopeVol=0;
256 goto ENDX; // -> and done for this channel
257 }
258
259 s_chan[ch].iSBPos=0; // Reset buffer play index.
260
261 //////////////////////////////////////////// spu irq handler here? mmm... do it later
262
263 s_1=s_chan[ch].s_1;
264 s_2=s_chan[ch].s_2;
265
266 predict_nr=(int)*start;start++;
267 shift_factor=predict_nr&0xf;
268 predict_nr >>= 4;
269 flags=(int)*start;start++;
270
271 // -------------------------------------- //
272 // Decode new samples into s_chan[ch].SB[0 through 27]
273 for (nSample=0;nSample<28;start++)
274 {
275 d=(int)*start;
276 s=((d&0xf)<<12);
277 if(s&0x8000) s|=0xffff0000;
278
279 fa=(s >> shift_factor);
280 fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
281 s_2=s_1;s_1=fa;
282 s=((d & 0xf0) << 8);
283
284 s_chan[ch].SB[nSample++]=fa;
285
286 if(s&0x8000) s|=0xffff0000;
287 fa=(s>>shift_factor);
288 fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6);
289 s_2=s_1;s_1=fa;
290
291 s_chan[ch].SB[nSample++]=fa;
292 }
293
294 //////////////////////////////////////////// irq check
295
296 if(spuCtrl&0x40) // irq active?
297 {
298 if((pSpuIrq > start-16 && // irq address reached?
299 pSpuIrq <= start) ||
300 ((flags&1) && // special: irq on looping addr, when stop/loop flag is set
301 (pSpuIrq > s_chan[ch].pLoop-16 &&
302 pSpuIrq <= s_chan[ch].pLoop)))
303 {
304 //extern s32 spuirqvoodoo;
305 s_chan[ch].iIrqDone=1; // -> debug flag
306 SPUirq();
307 //puts("IRQ");
308 //if(spuirqvoodoo!=-1)
309 //{
310 // spuirqvoodoo=temp*384;
311 // temp=0;
312 //}
313 }
314 }
315
316 //////////////////////////////////////////// flag handler
317
318 if((flags&4) && (!s_chan[ch].bIgnoreLoop))
319 s_chan[ch].pLoop=start-16; // loop adress
320
321 if(flags&1) // 1: stop/loop
322 {
323 // We play this block out first...
324 //if(!(flags&2)) // 1+2: do loop... otherwise: stop
325 if(flags!=3 || s_chan[ch].pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example)
326 { // and checking if pLoop is set avoids crashes, yeah
327 start = (u8*)-1;
328 }
329 else
330 {
331 start = s_chan[ch].pLoop;
332 }
333 }
334
335 s_chan[ch].pCurr=start; // store values for next cycle
336 s_chan[ch].s_1=s_1;
337 s_chan[ch].s_2=s_2;
338
339 ////////////////////////////////////////////
340 }
341
342 fa=s_chan[ch].SB[s_chan[ch].iSBPos++]; // get sample data
343
344 if((spuCtrl&0x4000)==0) fa=0; // muted?
345 else CLIP(fa);
346
347 {
348 int gpos;
349 gpos = s_chan[ch].SB[28];
350 gval0 = fa;
351 gpos = (gpos+1) & 3;
352 s_chan[ch].SB[28] = gpos;
353 }
354 s_chan[ch].spos -= 0x10000L;
355 }
356
357 ////////////////////////////////////////////////
358 // noise handler... just produces some noise data
359 // surely wrong... and no noise frequency (spuCtrl&0x3f00) will be used...
360 // and sometimes the noise will be used as fmod modulation... pfff
361
362 if(s_chan[ch].bNoise)
363 {
364 //puts("Noise");
365 if((dwNoiseVal<<=1)&0x80000000L)
366 {
367 dwNoiseVal^=0x0040001L;
368 fa=((dwNoiseVal>>2)&0x7fff);
369 fa=-fa;
370 }
371 else fa=(dwNoiseVal>>2)&0x7fff;
372
373 // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val
374 fa=s_chan[ch].iOldNoise+((fa-s_chan[ch].iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1));
375 if(fa>32767L) fa=32767L;
376 if(fa<-32767L) fa=-32767L;
377 s_chan[ch].iOldNoise=fa;
378
379 } //----------------------------------------
380 else // NO NOISE (NORMAL SAMPLE DATA) HERE
381 {
382 int vl, vr, gpos;
383 vl = (s_chan[ch].spos >> 6) & ~3;
384 gpos = s_chan[ch].SB[28];
385 vr=(gauss[vl]*gval0)>>9;
386 vr+=(gauss[vl+1]*gval(1))>>9;
387 vr+=(gauss[vl+2]*gval(2))>>9;
388 vr+=(gauss[vl+3]*gval(3))>>9;
389 fa = vr>>2;
390 }
391
392 s_chan[ch].sval = (MixADSR(ch) * fa)>>10; // / 1023; // add adsr
393 if(s_chan[ch].bFMod==2) // fmod freq channel
394 {
395 int NP=s_chan[ch+1].iRawPitch;
396 NP=((32768L+s_chan[ch].sval)*NP)>>15; ///32768L;
397
398 if(NP>0x3fff) NP=0x3fff;
399 if(NP<0x1) NP=0x1;
400
401 // mmmm... if I do this, all is screwed
402 // s_chan[ch+1].iRawPitch=NP;
403
404 NP=(44100L*NP)/(4096L); // calc frequency
405
406 s_chan[ch+1].iActFreq=NP;
407 s_chan[ch+1].iUsedFreq=NP;
408 s_chan[ch+1].sinc=(((NP/10)<<16)/4410);
409 if(!s_chan[ch+1].sinc) s_chan[ch+1].sinc=1;
410
411 // mmmm... set up freq decoding positions?
412 // s_chan[ch+1].iSBPos=28;
413 // s_chan[ch+1].spos=0x10000L;
414 }
415 else
416 {
417 //////////////////////////////////////////////
418 // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
419 int tmpl,tmpr;
420
421 if (1) //ao_channel_enable[ch+PSF_1]) {
422 {
423 tmpl=(s_chan[ch].sval*s_chan[ch].iLeftVolume)>>14;
424 tmpr=(s_chan[ch].sval*s_chan[ch].iRightVolume)>>14;
425 } else {
426 tmpl = 0;
427 tmpr = 0;
428 }
429 sl+=tmpl;
430 sr+=tmpr;
431
432 if(((rvb.Enabled>>ch)&1) && (spuCtrl&0x80))
433 {
434 revLeft+=tmpl;
435 revRight+=tmpr;
436 }
437 }
438
439 s_chan[ch].spos += s_chan[ch].sinc;
440 ENDX: ;
441 }
442 }
443
444 ///////////////////////////////////////////////////////
445 // mix all channels (including reverb) into one buffer
446 MixREVERBLeftRight(&sl,&sr,revLeft,revRight);
447 // printf("sampcount %d decaybegin %d decayend %d\n", sampcount, decaybegin, decayend);
448 if(sampcount>=decaybegin)
449 {
450 s32 dmul;
451 if(decaybegin!=~0) // Is anyone REALLY going to be playing a song
452 // for 13 hours?
453 {
454 if(sampcount>=decayend)
455 {
456 // ao_song_done = 1;
457 return(0);
458 }
459 dmul=256-(256*(sampcount-decaybegin)/(decayend-decaybegin));
460 sl=(sl*dmul)>>8;
461 sr=(sr*dmul)>>8;
462 }
463 }
464
465 sampcount++;
466 sl=(sl*volmul)>>8;
467 sr=(sr*volmul)>>8;
468
469 //{
470 // static double asl=0;
471 // static double asr=0;
472
473 // asl+=(sl-asl)/5;
474 // asr+=(sl-asr)/5;
475
476 //sl-=asl;
477 //sr-=asr;
478
479 // if(sl>32767 || sl < -32767) printf("Left: %d, %f\n",sl,asl);
480 // if(sr>32767 || sr < -32767) printf("Right: %d, %f\n",sl,asl);
481 //}
482
483 if(sl>32767) sl=32767; if(sl<-32767) sl=-32767;
484 if(sr>32767) sr=32767; if(sr<-32767) sr=-32767;
485
486 *pS++=sl;
487 *pS++=sr;
488 }
489
490 return(1);
491 }
492
493 void SPU_flushboot(void)
494 {
495 if((u8*)pS>((u8*)pSpuBuffer+1024))
496 {
497 spu_update((u8*)pSpuBuffer,(u8*)pS-(u8*)pSpuBuffer);
498 pS=(s16 *)pSpuBuffer;
499 }
500 }
501
502 #ifdef TIMEO
503 static u64 begintime;
504 static u64 gettime64(void)
505 {
506 struct timeval tv;
507 u64 ret;
508
509 gettimeofday(&tv,0);
510 ret=tv.tv_sec;
511 ret*=1000000;
512 ret+=tv.tv_usec;
513 return(ret);
514 }
515 #endif
516 ////////////////////////////////////////////////////////////////////////
517 // INIT/EXIT STUFF
518 ////////////////////////////////////////////////////////////////////////
519
520 ////////////////////////////////////////////////////////////////////////
521 // SPUINIT: this func will be called first by the main emu
522 ////////////////////////////////////////////////////////////////////////
523
524 int SPUinit(void)
525 {
526 spuMemC=(u8*)spuMem; // just small setup
527 memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN));
528 memset((void *)&rvb,0,sizeof(REVERBInfo));
529 memset(regArea,0,sizeof(regArea));
530 memset(spuMem,0,sizeof(spuMem));
531 InitADSR();
532 sampcount=ttemp=0;
533 #ifdef TIMEO
534 begintime=gettime64();
535 #endif
536 return 0;
537 }
538
539 ////////////////////////////////////////////////////////////////////////
540 // SETUPSTREAMS: init most of the spu buffers
541 ////////////////////////////////////////////////////////////////////////
542
543 void SetupStreams(void)
544 {
545 int i;
546
547 pSpuBuffer=(u8*)malloc(32768); // alloc mixing buffer
548 pS=(s16 *)pSpuBuffer;
549
550 for(i=0;i<MAXCHAN;i++) // loop sound channels
551 {
552 s_chan[i].ADSRX.SustainLevel = 1024; // -> init sustain
553 s_chan[i].iIrqDone=0;
554 s_chan[i].pLoop=spuMemC;
555 s_chan[i].pStart=spuMemC;
556 s_chan[i].pCurr=spuMemC;
557 }
558 }
559
560 ////////////////////////////////////////////////////////////////////////
561 // REMOVESTREAMS: free most buffer
562 ////////////////////////////////////////////////////////////////////////
563
564 void RemoveStreams(void)
565 {
566 free(pSpuBuffer); // free mixing buffer
567 pSpuBuffer=NULL;
568
569 #ifdef TIMEO
570 {
571 u64 tmp;
572 tmp=gettime64();
573 tmp-=begintime;
574 if(tmp)
575 tmp=(u64)sampcount*1000000/tmp;
576 printf("%lld samples per second\n",tmp);
577 }
578 #endif
579 }
580
581
582 ////////////////////////////////////////////////////////////////////////
583 // SPUOPEN: called by main emu after init
584 ////////////////////////////////////////////////////////////////////////
585
586 int SPUopen(void)
587 {
588 if(bSPUIsOpen) return 0; // security for some stupid main emus
589 spuIrq=0;
590
591 spuStat=spuCtrl=0;
592 spuAddr=0xffffffff;
593 dwNoiseVal=1;
594
595 spuMemC=(u8*)spuMem;
596 memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN));
597 pSpuIrq=0;
598
599 iVolume=255; //85;
600 SetupStreams(); // prepare streaming
601
602 bSPUIsOpen=1;
603
604 return 1;
605 }
606
607 ////////////////////////////////////////////////////////////////////////
608
609 ////////////////////////////////////////////////////////////////////////
610 // SPUCLOSE: called before shutdown
611 ////////////////////////////////////////////////////////////////////////
612
613 int SPUclose(void)
614 {
615 if(!bSPUIsOpen) return 0; // some security
616
617 bSPUIsOpen=0; // no more open
618
619 RemoveStreams(); // no more streaming
620
621 return 0;
622 }
623
624 ////////////////////////////////////////////////////////////////////////
625 // SPUSHUTDOWN: called by main emu on final exit
626 ////////////////////////////////////////////////////////////////////////
627
628 int SPUshutdown(void)
629 {
630 return 0;
631 }
632
633 void SPUinjectRAMImage(u16 *pIncoming)
634 {
635 int i;
636
637 for (i = 0; i < (256*1024); i++)
638 {
639 spuMem[i] = pIncoming[i];
640 }
641 }