refactor out GP2X specific stuff completely
[fceu.git] / sound.c
... / ...
CommitLineData
1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Ben Parnell
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/********************************************************/
22/******* sound.c */
23/******* */
24/******* Sound emulation code and waveform synthesis */
25/******* routines. A few ideas were inspired */
26/******* by code from Marat Fayzullin's EMUlib */
27/******* */
28/********************************************************/
29
30#include <stdlib.h>
31#include <stdio.h>
32
33#include <string.h>
34
35#include "types.h"
36#include "x6502.h"
37
38#include "fce.h"
39#include "svga.h"
40#include "sound.h"
41
42uint32 Wave[2048+512];
43int16 WaveFinalMono[2048+512];
44
45EXPSOUND GameExpSound={0,0,0,0,0,0};
46
47uint8 trimode=0;
48uint8 tricoop=0;
49uint8 PSG[0x18];
50
51uint8 decvolume[3];
52uint8 realvolume[3];
53
54static int32 count[5];
55static int32 sqacc[2]={0,0};
56uint8 sqnon=0;
57
58uint32 soundtsoffs=0;
59
60#undef printf
61uint16 nreg;
62
63static int32 lengthcount[4];
64
65extern int soundvol;
66
67static const uint8 Slengthtable[0x20]=
68{
69 0x5,0x7f,0xA,0x1,0x14,0x2,0x28,0x3,0x50,0x4,0x1E,0x5,0x7,0x6,0x0E,0x7,
70 0x6,0x08,0xC,0x9,0x18,0xa,0x30,0xb,0x60,0xc,0x24,0xd,0x8,0xe,0x10,0xf
71};
72
73static uint32 lengthtable[0x20];
74
75static const uint32 SNoiseFreqTable[0x10]=
76{
77 2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
78};
79static uint32 NoiseFreqTable[0x10];
80
81int32 nesincsize;
82uint32 soundtsinc;
83uint32 soundtsi;
84
85
86static const uint8 NTSCPCMTable[0x10]=
87{
88 0xd6,0xbe,0xaa,0xa0,0x8f,0x7f,0x71,0x6b,
89 0x5f,0x50,0x47,0x40,0x35,0x2a,0x24,0x1b
90};
91
92static const uint8 PALPCMTable[0x10]= // These values are just guessed.
93{
94 0xc6,0xb0,0x9d,0x94,0x84,0x75,0x68,0x63,
95 0x58,0x4a,0x41,0x3b,0x31,0x27,0x21,0x19
96};
97
98uint32 PSG_base;
99
100// $4010 - Frequency
101// $4011 - Actual data outputted
102// $4012 - Address register: $c000 + V*64
103// $4013 - Size register: Size in bytes = (V+1)*64
104
105
106static int32 PCMacc=0;
107static int PCMfreq;
108int32 PCMIRQCount;
109uint8 PCMBitIndex=0;
110uint32 PCMAddressIndex=0;
111int32 PCMSizeIndex=0;
112uint8 PCMBuffer=0;
113int vdis=0;
114
115static void Dummyfunc(int end) {};
116
117static void (*DoNoise)(int end)=Dummyfunc;
118static void (*DoTriangle)(int end)=Dummyfunc;
119static void (*DoPCM)(int end)=Dummyfunc;
120static void (*DoSQ1)(int end)=Dummyfunc;
121static void (*DoSQ2)(int end)=Dummyfunc;
122
123static void CalcDPCMIRQ(void)
124{
125 uint32 freq;
126 uint32 honk;
127 uint32 cycles;
128
129 if(PAL)
130 freq=(PALPCMTable[PSG[0x10]&0xF]<<4);
131 else
132 freq=(NTSCPCMTable[PSG[0x10]&0xF]<<4);
133
134 cycles=(((PSG[0x13]<<4)+1));
135 cycles*=freq/14;
136 honk=((PSG[0x13]<<4)+1)*freq;
137 honk-=cycles;
138 //if(PAL) honk/=107;
139 //else honk/=(double)113.66666666;
140 PCMIRQCount=honk*48;
141 //PCMIRQCount=honk*3; //180;
142 //if(PAL) PCMIRQCount*=.93;
143 vdis=0;
144}
145
146static void PrepDPCM()
147{
148 PCMAddressIndex=0x4000+(PSG[0x12]<<6);
149 PCMSizeIndex=(PSG[0x13]<<4)+1;
150 PCMBitIndex=0;
151 //PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
152 if(PAL)
153 PCMfreq=PALPCMTable[PSG[0x10]&0xF];
154 else
155 PCMfreq=NTSCPCMTable[PSG[0x10]&0xF];
156 PCMacc=PCMfreq<<18;
157}
158
159uint8 sweepon[2]={0,0};
160int32 curfreq[2]={0,0};
161
162
163uint8 SIRQStat=0;
164
165uint8 SweepCount[2];
166uint8 DecCountTo1[3];
167
168uint8 fcnt=0;
169int32 fhcnt=0;
170int32 fhinc;
171
172static uint8 laster;
173
174/* Instantaneous? Maybe the new freq value is being calculated all of the time... */
175static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr)
176{
177 uint32 mod;
178 if(!(sr&0x8))
179 {
180 mod=cf>>(sr&7);
181 if((mod+cf)&0x800)
182 return(0);
183 }
184 return(1);
185}
186
187static DECLFW(Write0x11)
188{
189 DoPCM(0);
190 PSG[0x11]=V&0x7F;
191}
192
193static uint8 DutyCount[2]={0,0};
194
195static DECLFW(Write_PSG)
196{
197 //if((A>=0x4004 && A<=0x4007) || A==0x4015)
198 //printf("$%04x:$%02x, %d\n",A,V,SOUNDTS);
199 A&=0x1f;
200 switch(A)
201 {
202 case 0x0:
203 DoSQ1(0);
204 if(V&0x10)
205 realvolume[0]=V&0xF;
206 break;
207 case 0x1:
208 sweepon[0]=V&0x80;
209 break;
210 case 0x2:
211 DoSQ1(0);
212 curfreq[0]&=0xFF00;
213 curfreq[0]|=V;
214 break;
215 case 0x3:
216 if(PSG[0x15]&1)
217 {
218 DoSQ1(0);
219 lengthcount[0]=lengthtable[(V>>3)&0x1f];
220 sqnon|=1;
221 }
222 sweepon[0]=PSG[1]&0x80;
223 curfreq[0]=PSG[0x2]|((V&7)<<8);
224 decvolume[0]=0xF;
225 DecCountTo1[0]=(PSG[0]&0xF)+1;
226 SweepCount[0]=((PSG[0x1]>>4)&7)+1;
227 DutyCount[0]=0;
228 sqacc[0]=((int32)curfreq[0]+1)<<18;
229 break;
230
231 case 0x4:
232 DoSQ2(0);
233 if(V&0x10)
234 realvolume[1]=V&0xF;
235 break;
236 case 0x5:
237 sweepon[1]=V&0x80;
238 break;
239 case 0x6:
240 DoSQ2(0);
241 curfreq[1]&=0xFF00;
242 curfreq[1]|=V;
243 break;
244 case 0x7:
245 if(PSG[0x15]&2)
246 {
247 DoSQ2(0);
248 lengthcount[1]=lengthtable[(V>>3)&0x1f];
249 sqnon|=2;
250 }
251 sweepon[1]=PSG[0x5]&0x80;
252 curfreq[1]=PSG[0x6]|((V&7)<<8);
253 decvolume[1]=0xF;
254 DecCountTo1[1]=(PSG[0x4]&0xF)+1;
255 SweepCount[1]=((PSG[0x5]>>4)&7)+1;
256 DutyCount[1]=0;
257 sqacc[1]=((int32)curfreq[1]+1)<<18;
258 break;
259 case 0x8:
260 DoTriangle(0);
261 if(laster&0x80)
262 {
263 tricoop=V&0x7F;
264 trimode=V&0x80;
265 }
266 if(!(V&0x7F))
267 tricoop=0;
268 laster=V&0x80;
269 break;
270 case 0xa:DoTriangle(0);
271 break;
272 case 0xb:
273 if(PSG[0x15]&0x4)
274 {
275 DoTriangle(0);
276 sqnon|=4;
277 lengthcount[2]=lengthtable[(V>>3)&0x1f];
278 }
279 laster=0x80;
280 tricoop=PSG[0x8]&0x7f;
281 trimode=PSG[0x8]&0x80;
282 break;
283 case 0xC:DoNoise(0);
284 if(V&0x10)
285 realvolume[2]=V&0xF;
286 break;
287 case 0xE:DoNoise(0);break;
288 case 0xF:
289 if(PSG[0x15]&8)
290 {
291 DoNoise(0);
292 sqnon|=8;
293 lengthcount[3]=lengthtable[(V>>3)&0x1f];
294 }
295 decvolume[2]=0xF;
296 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
297 break;
298 case 0x10:DoPCM(0);
299 if(!(V&0x80))
300 X6502_IRQEnd(FCEU_IQDPCM);
301 break;
302 case 0x15:
303 {
304 int t=V^PSG[0x15];
305
306 if(t&1)
307 DoSQ1(0);
308 if(t&2)
309 DoSQ2(0);
310 if(t&4)
311 DoTriangle(0);
312 if(t&8)
313 DoNoise(0);
314 if(t&0x10)
315 DoPCM(0);
316 sqnon&=V;
317 if(V&0x10)
318 {
319 if(!(PSG[0x15]&0x10))
320 {
321 PrepDPCM();
322 CalcDPCMIRQ();
323 }
324 else if(vdis)
325 CalcDPCMIRQ();
326 }
327 else
328 PCMIRQCount=0;
329 X6502_IRQEnd(FCEU_IQDPCM);
330 }
331 break;
332 }
333 PSG[A]=V;
334}
335
336DECLFR(Read_PSG)
337{
338 uint8 ret;
339 if(PSG[0x15]&0x10)
340 DoPCM(0);
341 ret=(PSG[0x15]&(sqnon|0x10))|SIRQStat;
342 SIRQStat&=~0x40;
343 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
344 return ret;
345}
346
347DECLFR(Read_PSGDummy)
348{
349 uint8 ret;
350
351 ret=(PSG[0x15]&sqnon)|SIRQStat;
352 SIRQStat&=~0x40;
353 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
354 return ret;
355}
356
357static void FASTAPASS(1) FrameSoundStuff(int V)
358{
359 int P;
360 uint32 end = (SOUNDTS<<16)/soundtsinc;
361
362 DoSQ1(end);
363 DoSQ2(end);
364 DoNoise(end);
365
366 switch((V&1))
367 {
368 case 1: /* Envelope decay, linear counter, length counter, freq sweep */
369 if(PSG[0x15]&4 && sqnon&4)
370 if(!(PSG[8]&0x80))
371 {
372 if(lengthcount[2]>0)
373 {
374 lengthcount[2]--;
375 if(lengthcount[2]<=0)
376 {
377 DoTriangle(0);
378 sqnon&=~4;
379 }
380 }
381 }
382
383 for(P=0;P<2;P++)
384 {
385 if(PSG[0x15]&(P+1) && sqnon&(P+1))
386 {
387 if(!(PSG[P<<2]&0x20))
388 {
389 if(lengthcount[P]>0)
390 {
391 lengthcount[P]--;
392 if(lengthcount[P]<=0)
393 {
394 sqnon&=~(P+1);
395 }
396 }
397 }
398 }
399 /* Frequency Sweep Code Here */
400 /* xxxx 0000 */
401 /* xxxx = hz. 120/(x+1)*/
402 if(sweepon[P])
403 {
404 int32 mod=0;
405
406 if(SweepCount[P]>0) SweepCount[P]--;
407 if(SweepCount[P]<=0)
408 {
409 SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1;
410 {
411 if(PSG[(P<<2)+0x1]&0x8)
412 {
413 mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7));
414
415 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
416 {
417 curfreq[P]+=mod;
418 }
419 }
420 else
421 {
422 mod=curfreq[P]>>(PSG[(P<<2)+0x1]&7);
423 if((mod+curfreq[P])&0x800)
424 {
425 sweepon[P]=0;
426 curfreq[P]=0;
427 }
428 else
429 {
430 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
431 {
432 curfreq[P]+=mod;
433 }
434 }
435 }
436 }
437 }
438 }
439 }
440
441 if(PSG[0x15]&0x8 && sqnon&8)
442 {
443 if(!(PSG[0xC]&0x20))
444 {
445 if(lengthcount[3]>0)
446 {
447 lengthcount[3]--;
448 if(lengthcount[3]<=0)
449 {
450 sqnon&=~8;
451 }
452 }
453 }
454 }
455
456 case 0: /* Envelope decay + linear counter */
457 if(!trimode)
458 {
459 laster=0;
460 if(tricoop)
461 {
462 if(tricoop==1) DoTriangle(0);
463 tricoop--;
464 }
465 }
466
467 for(P=0;P<2;P++)
468 {
469 if(DecCountTo1[P]>0) DecCountTo1[P]--;
470 if(DecCountTo1[P]<=0)
471 {
472 DecCountTo1[P]=(PSG[P<<2]&0xF)+1;
473 if(decvolume[P] || PSG[P<<2]&0x20)
474 {
475 decvolume[P]--;
476 /* Step from 0 to full volume seems to take twice as long
477 as the other steps. I don't know if this is the correct
478 way to double its length, though(or if it even matters).
479 */
480 if((PSG[P<<2]&0x20) && (decvolume[P]==0))
481 DecCountTo1[P]<<=1;
482 decvolume[P]&=15;
483 }
484 }
485 if(!(PSG[P<<2]&0x10))
486 realvolume[P]=decvolume[P];
487 }
488
489 if(DecCountTo1[2]>0) DecCountTo1[2]--;
490 if(DecCountTo1[2]<=0)
491 {
492 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
493 if(decvolume[2] || PSG[0xC]&0x20)
494 {
495 decvolume[2]--;
496 /* Step from 0 to full volume seems to take twice as long
497 as the other steps. I don't know if this is the correct
498 way to double its length, though(or if it even matters).
499 */
500 if((PSG[0xC]&0x20) && (decvolume[2]==0))
501 DecCountTo1[2]<<=1;
502 decvolume[2]&=15;
503 }
504 }
505 if(!(PSG[0xC]&0x10))
506 realvolume[2]=decvolume[2];
507
508 break;
509 }
510
511}
512
513void FrameSoundUpdate(void)
514{
515 // Linear counter: Bit 0-6 of $4008
516 // Length counter: Bit 4-7 of $4003, $4007, $400b, $400f
517
518 if(fcnt==3)
519 {
520 if(PSG[0x17]&0x80)
521 fhcnt+=fhinc;
522 if(!(PSG[0x17]&0xC0))
523 {
524 SIRQStat|=0x40;
525 X6502_IRQBegin(FCEU_IQFCOUNT);
526 }
527 }
528 //if(SIRQStat&0x40) X6502_IRQBegin(FCEU_IQFCOUNT);
529 FrameSoundStuff(fcnt);
530 fcnt=(fcnt+1)&3;
531}
532
533static uint32 ChannelBC[5];
534
535static uint32 RectAmp[2][8];
536
537static void FASTAPASS(1) CalcRectAmp(int P)
538{
539 static int tal[4]={1,2,4,6};
540 int V;
541 int x;
542 uint32 *b=RectAmp[P];
543 int m;
544
545 //if(PSG[P<<2]&0x10)
546 V=realvolume[P]<<4;
547 //V=(PSG[P<<2]&15)<<4;
548 //else
549 // V=decvolume[P]<<4;
550 m=tal[(PSG[P<<2]&0xC0)>>6];
551 for(x=0;x<m;x++,b++)
552 *b=0;
553 for(;x<8;x++,b++)
554 *b=V;
555}
556
557static void RDoPCM(int32 end)
558{
559 int32 V;
560 int32 start;
561 int32 freq;
562 uint32 out=PSG[0x11]<<3;
563
564 start=ChannelBC[4];
565 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
566 if(end<=start) return;
567 ChannelBC[4]=end;
568
569 if(PSG[0x15]&0x10)
570 {
571 freq=PCMfreq;
572 freq<<=18;
573
574 for(V=start;V<end;V++)
575 {
576 PCMacc-=nesincsize;
577 if(PCMacc<=0)
578 {
579 if(!PCMBitIndex)
580 {
581 PCMSizeIndex--;
582 if(!PCMSizeIndex)
583 {
584 if(PSG[0x10]&0x40)
585 PrepDPCM();
586 else
587 {
588 PSG[0x15]&=~0x10;
589 for(;V<end;V++)
590 Wave[V>>4]+=PSG[0x11]<<3;
591 goto endopcmo;
592 }
593 }
594 else
595 {
596 PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
597 PCMAddressIndex=(PCMAddressIndex+1)&0x7fff;
598 }
599 }
600
601 {
602 int t=(((PCMBuffer>>PCMBitIndex)&1)<<2)-2;
603 uint8 bah=PSG[0x11];
604
605 PCMacc+=freq;
606 PSG[0x11]+=t;
607 if(PSG[0x11]&0x80)
608 PSG[0x11]=bah;
609 else
610 out=PSG[0x11]<<3;
611 }
612 PCMBitIndex=(PCMBitIndex+1)&7;
613 }
614 Wave[V>>4]+=out; //(PSG[0x11]-64)<<3;
615 }
616 }
617 else
618 {
619 if((end-start)>64)
620 {
621 for(V=start;V<=(start|15);V++)
622 Wave[V>>4]+=out;
623 out<<=4;
624 for(V=(start>>4)+1;V<(end>>4);V++)
625 Wave[V]+=out;
626 out>>=4;
627 for(V=end&(~15);V<end;V++)
628 Wave[V>>4]+=out;
629 }
630 else
631 for(V=start;V<end;V++)
632 Wave[V>>4]+=out;
633 }
634 endopcmo:;
635}
636
637static void RDoSQ1(int32 end)
638{
639 int32 V;
640 int32 start;
641 int32 freq;
642
643 start=ChannelBC[0];
644 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
645 if(end<=start) return;
646 ChannelBC[0]=end;
647
648 if(!(PSG[0x15]&1 && sqnon&1))
649 return;
650
651 if(curfreq[0]<8 || curfreq[0]>0x7ff)
652 return;
653 if(!CheckFreq(curfreq[0],PSG[0x1]))
654 return;
655
656 CalcRectAmp(0);
657
658 {
659 uint32 out=RectAmp[0][DutyCount[0]];
660 freq=curfreq[0]+1;
661 {
662 freq<<=18;
663 for(V=start;V<end;V++)
664 {
665 Wave[V>>4]+=out;
666 sqacc[0]-=nesincsize;
667 if(sqacc[0]<=0)
668 {
669 rea:
670 sqacc[0]+=freq;
671 DutyCount[0]++;
672 if(sqacc[0]<=0) goto rea;
673
674 DutyCount[0]&=7;
675 out=RectAmp[0][DutyCount[0]];
676 }
677 }
678 }
679 }
680}
681
682static void RDoSQ2(int32 end)
683{
684 int32 V;
685 int32 start;
686 int32 freq;
687
688 start=ChannelBC[1];
689 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
690 if(end<=start) return;
691 ChannelBC[1]=end;
692
693 if(!(PSG[0x15]&2 && sqnon&2))
694 return;
695
696 if(curfreq[1]<8 || curfreq[1]>0x7ff)
697 return;
698 if(!CheckFreq(curfreq[1],PSG[0x5]))
699 return;
700
701 CalcRectAmp(1);
702
703 {
704 uint32 out=RectAmp[1][DutyCount[1]];
705 freq=curfreq[1]+1;
706
707 {
708 freq<<=18;
709 for(V=start;V<end;V++)
710 {
711 Wave[V>>4]+=out;
712 sqacc[1]-=nesincsize;
713 if(sqacc[1]<=0)
714 {
715 rea:
716 sqacc[1]+=freq;
717 DutyCount[1]++;
718 if(sqacc[1]<=0) goto rea;
719
720 DutyCount[1]&=7;
721 out=RectAmp[1][DutyCount[1]];
722 }
723 }
724 }
725 }
726}
727
728
729static void RDoTriangle(int32 end)
730{
731 static uint32 tcout=0;
732 int32 V;
733 int32 start; //,freq;
734 int32 freq=(((PSG[0xa]|((PSG[0xb]&7)<<8))+1));
735
736 start=ChannelBC[2];
737 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
738 if(end<=start) return;
739 ChannelBC[2]=end;
740
741 if(! (PSG[0x15]&0x4 && sqnon&4 && tricoop) )
742 { // Counter is halted, but we still need to output.
743 for(V=start;V<end;V++)
744 Wave[V>>4]+=tcout;
745 }
746 else if(freq<=4) // 55.9Khz - Might be barely audible on a real NES, but
747 // it's too costly to generate audio at this high of a frequency
748 // (55.9Khz * 32 for the stepping).
749 // The same could probably be said for ~27.8Khz, so we'll
750 // take care of that too. We'll just output the average
751 // value(15/2 - scaled properly for our output format, of course).
752 // We'll also take care of ~18Khz and ~14Khz too, since they should be barely audible.
753 // (Some proof or anything to confirm/disprove this would be nice.).
754 {
755 for(V=start;V<end;V++)
756 Wave[V>>4]+=((0xF<<4)+(0xF<<2))>>1;
757 }
758 else
759 {
760 static int32 triacc=0;
761 static uint8 tc=0;
762
763 freq<<=17;
764 for(V=start;V<end;V++)
765 {
766 triacc-=nesincsize;
767 if(triacc<=0)
768 {
769 rea:
770 triacc+=freq; //t;
771 tc=(tc+1)&0x1F;
772 if(triacc<=0) goto rea;
773
774 tcout=(tc&0xF);
775 if(tc&0x10) tcout^=0xF;
776 tcout=(tcout<<4)+(tcout<<2);
777 }
778 Wave[V>>4]+=tcout;
779 }
780 }
781}
782
783static void RDoNoise(int32 end)
784{
785 int32 inc,V;
786 int32 start;
787
788 start=ChannelBC[3];
789 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
790 if(end<=start) return;
791 ChannelBC[3]=end;
792
793 if(PSG[0x15]&0x8 && sqnon&8)
794 {
795 uint32 outo;
796 uint32 amptab[2];
797 uint8 amplitude;
798
799 amplitude=realvolume[2];
800 //if(PSG[0xC]&0x10)
801 // amplitude=(PSG[0xC]&0xF);
802 //else
803 // amplitude=decvolume[2]&0xF;
804
805 inc=NoiseFreqTable[PSG[0xE]&0xF];
806 amptab[0]=((amplitude<<2)+amplitude+amplitude)<<1;
807 amptab[1]=0;
808 outo=amptab[nreg&1];
809
810 if(amplitude)
811 {
812 if(PSG[0xE]&0x80) // "short" noise
813 for(V=start;V<end;V++)
814 {
815 Wave[V>>4]+=outo;
816 if(count[3]>=inc)
817 {
818 uint8 feedback;
819
820 feedback=((nreg>>8)&1)^((nreg>>14)&1);
821 nreg=(nreg<<1)+feedback;
822 nreg&=0x7fff;
823 outo=amptab[nreg&1];
824 count[3]-=inc;
825 }
826 count[3]+=0x1000;
827 }
828 else
829 for(V=start;V<end;V++)
830 {
831 Wave[V>>4]+=outo;
832 if(count[3]>=inc)
833 {
834 uint8 feedback;
835
836 feedback=((nreg>>13)&1)^((nreg>>14)&1);
837 nreg=(nreg<<1)+feedback;
838 nreg&=0x7fff;
839 outo=amptab[nreg&1];
840 count[3]-=inc;
841 }
842 count[3]+=0x1000;
843 }
844 }
845 }
846}
847
848DECLFW(Write_IRQFM)
849{
850 PSG[0x17]=V;
851 V=(V&0xC0)>>6;
852 fcnt=0;
853 if(V&0x2)
854 FrameSoundUpdate();
855 fcnt=1;
856 fhcnt=fhinc;
857 X6502_IRQEnd(FCEU_IQFCOUNT);
858 SIRQStat&=~0x40;
859 //IRQFrameMode=V; // IRQFrameMode is PSG[0x17] upper bits
860}
861
862void SetNESSoundMap(void)
863{
864 SetWriteHandler(0x4000,0x4013,Write_PSG);
865 SetWriteHandler(0x4011,0x4011,Write0x11);
866 SetWriteHandler(0x4015,0x4015,Write_PSG);
867 SetWriteHandler(0x4017,0x4017,Write_IRQFM);
868 SetReadHandler(0x4015,0x4015,Read_PSG);
869}
870
871int32 highp; // 0 through 65536, 0 = no high pass, 65536 = max high pass
872
873int32 lowp; // 0 through 65536, 65536 = max low pass(total attenuation)
874 // 65536 = no low pass
875static int32 flt_acc=0, flt_acc2=0;
876
877static void FilterSound(uint32 *in, int16 *outMono, int count)
878{
879// static int min=0, max=0;
880 int sh=2;
881 if (soundvol < 5) sh += 5 - soundvol;
882
883 for(;count;count--,in++,outMono++)
884 {
885 int32 diff;
886
887 diff = *in - flt_acc;
888
889 flt_acc += (diff*highp)>>16;
890 flt_acc2+= (int32) (((int64)((diff-flt_acc2)*lowp))>>16);
891 *in=0;
892
893 *outMono = flt_acc2*7 >> sh; // * 7 >> 2 = * 1.75
894// if (acc2 < min) { printf("min: %i %04x\n", acc2, acc2); min = acc2; }
895// if (acc2 > max) { printf("max: %i %04x\n", acc2, acc2); max = acc2; }
896 }
897}
898
899
900
901static int32 inbuf=0;
902int FlushEmulateSound(void)
903{
904 int x;
905 uint32 end;
906
907 if(!timestamp) return(0);
908
909 if(!FSettings.SndRate || (soundvol == 0))
910 {
911 end=0;
912 goto nosoundo;
913 }
914
915 end=(SOUNDTS<<16)/soundtsinc;
916 DoSQ1(end);
917 DoSQ2(end);
918 DoTriangle(end);
919 DoNoise(end);
920 DoPCM(end);
921
922 if(GameExpSound.Fill)
923 GameExpSound.Fill(end&0xF);
924
925 FilterSound(Wave,WaveFinalMono,end>>4);
926
927 if(end&0xF)
928 Wave[0]=Wave[(end>>4)];
929 Wave[(end>>4)]=0;
930
931 nosoundo:
932 for(x=0;x<5;x++)
933 ChannelBC[x]=end&0xF;
934 soundtsoffs=(soundtsinc*(end&0xF))>>16;
935 end>>=4;
936 inbuf=end;
937 return(end);
938}
939
940int GetSoundBuffer(int16 **W)
941{
942 *W=WaveFinalMono;
943 return inbuf;
944}
945
946void PowerSound(void)
947{
948 int x;
949
950 SetNESSoundMap();
951
952 for(x=0;x<0x16;x++)
953 if(x!=0x14)
954 BWrite[0x4000+x](0x4000+x,0);
955 PSG[0x17]=0; //x40;
956 fhcnt=fhinc;
957 fcnt=0;
958 nreg=1;
959 soundtsoffs=0;
960}
961
962void ResetSound(void)
963{
964 int x;
965 for(x=0;x<0x16;x++)
966 if(x!=1 && x!=5 && x!=0x14) BWrite[0x4000+x](0x4000+x,0);
967 PSG[0x17]=0;
968 fhcnt=fhinc;
969 fcnt=0;
970 nreg=1;
971}
972
973void SetSoundVariables(void)
974{
975 int x;
976
977 fhinc=PAL?16626:14915; // *2 CPU clock rate
978 fhinc*=24;
979 for(x=0;x<0x20;x++)
980 lengthtable[x]=Slengthtable[x]<<1;
981
982 if(FSettings.SndRate)
983 {
984 DoNoise=RDoNoise;
985 DoTriangle=RDoTriangle;
986 DoPCM=RDoPCM;
987 DoSQ1=RDoSQ1;
988 DoSQ2=RDoSQ2;
989 }
990 else
991 {
992 DoNoise=DoTriangle=DoPCM=DoSQ1=DoSQ2=Dummyfunc;
993 }
994
995 if(!FSettings.SndRate) return;
996 if(GameExpSound.RChange)
997 GameExpSound.RChange();
998
999 // nesincsizeLL=(int64)((int64)562949953421312*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate OVERSAMPLE));
1000 nesincsize=(int32)(((int64)1<<17)*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate * 16)); // 308845 - 1832727
1001 PSG_base=(uint32)(PAL?(long double)PAL_CPU/16:(long double)NTSC_CPU/16);
1002
1003 for(x=0;x<0x10;x++)
1004 {
1005 long double z;
1006 z=SNoiseFreqTable[x]<<1;
1007 z=(PAL?PAL_CPU:NTSC_CPU)/z;
1008 z=(long double)((uint32)((FSettings.SndRate OVERSAMPLE)<<12))/z;
1009 NoiseFreqTable[x]=z;
1010 }
1011 soundtsinc=(uint32)((uint64)(PAL?(long double)PAL_CPU*65536:(long double)NTSC_CPU*65536)/(FSettings.SndRate OVERSAMPLE));
1012 memset(Wave,0,sizeof(Wave));
1013 for(x=0;x<5;x++)
1014 ChannelBC[x]=0;
1015 highp=(250<<16)/FSettings.SndRate; // Arbitrary
1016 lowp=(25000<<16)/FSettings.SndRate; // Arbitrary
1017
1018 if(highp>(1<<16)) highp=1<<16;
1019 if(lowp>(1<<16)) lowp=1<<16;
1020
1021 flt_acc=flt_acc2=0;
1022}
1023
1024void FixOldSaveStateSFreq(void)
1025{
1026 int x;
1027 for(x=0;x<2;x++)
1028 {
1029 curfreq[x]=PSG[0x2+(x<<2)]|((PSG[0x3+(x<<2)]&7)<<8);
1030 }
1031}
1032
1033void FCEUI_Sound(int Rate)
1034{
1035 FSettings.SndRate=Rate;
1036 SetSoundVariables();
1037}
1038
1039void FCEUI_SetSoundVolume(uint32 volume)
1040{
1041 FSettings.SoundVolume=volume;
1042}