initial fce ultra 0.81 import
[fceu.git] / sound.c
CommitLineData
c62d2810 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 soundtsinc;
43uint32 soundtsi;
44
45uint32 Wave[2048];
46int32 WaveFinal[2048];
47
48EXPSOUND GameExpSound={0,0,0};
49
50uint8 trimode=0;
51uint8 tricoop=0;
52uint8 PSG[0x18];
53
54uint8 decvolume[3];
55uint8 realvolume[3];
56
57static int32 count[5];
58static int64 sqacc[2]={0,0};
59uint8 sqnon=0;
60
61#undef printf
62uint16 nreg;
63
64int32 lengthcount[4];
65
66static const uint8 Slengthtable[0x20]=
67{
68 0x5,0x7f,0xA,0x1,0x14,0x2,0x28,0x3,0x50,0x4,0x1E,0x5,0x7,0x6,0x0E,0x7,
69 0x6,0x08,0xC,0x9,0x18,0xa,0x30,0xb,0x60,0xc,0x24,0xd,0x8,0xe,0x10,0xf
70};
71
72static uint32 lengthtable[0x20];
73
74static const uint32 SNoiseFreqTable[0x10]=
75{
76 2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
77};
78static uint32 NoiseFreqTable[0x10];
79
80int64 nesincsizeLL;
81
82static const uint8 NTSCPCMTable[0x10]=
83{
84 0xd6,0xbe,0xaa,0xa0,0x8f,0x7f,0x71,0x6b,
85 0x5f,0x50,0x47,0x40,0x35,0x2a,0x24,0x1b
86};
87
88static const uint8 PALPCMTable[0x10]= // These values are just guessed.
89{
90 0xc6,0xb0,0x9d,0x94,0x84,0x75,0x68,0x63,
91 0x58,0x4a,0x41,0x3b,0x31,0x27,0x21,0x19
92};
93
94uint32 PSG_base;
95
96// $4010 - Frequency
97// $4011 - Actual data outputted
98// $4012 - Address register: $c000 + V*64
99// $4013 - Size register: Size in bytes = (V+1)*64
100
101
102static int64 PCMacc=0;
103static int PCMfreq;
104int32 PCMIRQCount;
105uint8 PCMBitIndex=0;
106uint32 PCMAddressIndex=0;
107int32 PCMSizeIndex=0;
108uint8 PCMBuffer=0;
109int vdis=0;
110
111static void Dummyfunc(void) {};
112
113static void (*DoNoise)(void)=Dummyfunc;
114static void (*DoTriangle)(void)=Dummyfunc;
115static void (*DoPCM)(void)=Dummyfunc;
116static void (*DoSQ1)(void)=Dummyfunc;
117static void (*DoSQ2)(void)=Dummyfunc;
118
119static void CalcDPCMIRQ(void)
120{
121 uint32 freq;
122 uint32 honk;
123 uint32 cycles;
124
125 if(PAL)
126 freq=(PALPCMTable[PSG[0x10]&0xF]<<4);
127 else
128 freq=(NTSCPCMTable[PSG[0x10]&0xF]<<4);
129
130 cycles=(((PSG[0x13]<<4)+1));
131 cycles*=freq/14;
132 honk=((PSG[0x13]<<4)+1)*freq;
133 honk-=cycles;
134 //if(PAL) honk/=107;
135 //else honk/=(double)113.66666666;
136 PCMIRQCount=honk*48;
137 //PCMIRQCount=honk*3; //180;
138 //if(PAL) PCMIRQCount*=.93;
139 vdis=0;
140}
141
142static void PrepDPCM()
143{
144 PCMAddressIndex=0x4000+(PSG[0x12]<<6);
145 PCMSizeIndex=(PSG[0x13]<<4)+1;
146 PCMBitIndex=0;
147 //PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
148 if(PAL)
149 PCMfreq=PALPCMTable[PSG[0x10]&0xF];
150 else
151 PCMfreq=NTSCPCMTable[PSG[0x10]&0xF];
152 PCMacc=(int64)PCMfreq<<50;
153}
154
155uint8 sweepon[2]={0,0};
156int32 curfreq[2]={0,0};
157
158
159uint8 SIRQStat=0;
160
161uint8 SweepCount[2];
162uint8 DecCountTo1[3];
163
164uint8 fcnt=0;
165int32 fhcnt=0;
166int32 fhinc;
167
168static uint8 laster;
169
170/* Instantaneous? Maybe the new freq value is being calculated all of the time... */
171static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr)
172{
173 uint32 mod;
174 if(!(sr&0x8))
175 {
176 mod=cf>>(sr&7);
177 if((mod+cf)&0x800)
178 return(0);
179 }
180 return(1);
181}
182
183static DECLFW(Write0x11)
184{
185 DoPCM();
186 PSG[0x11]=V&0x7F;
187}
188
189static uint8 DutyCount[2]={0,0};
190
191static DECLFW(Write_PSG)
192{
193 //if((A>=0x4004 && A<=0x4007) || A==0x4015)
194 //printf("$%04x:$%02x, %d\n",A,V,timestamp);
195 A&=0x1f;
196 switch(A)
197 {
198 case 0x0:
199 DoSQ1();
200 if(V&0x10)
201 realvolume[0]=V&0xF;
202 break;
203 case 0x1:
204 sweepon[0]=V&0x80;
205 break;
206 case 0x2:
207 DoSQ1();
208 curfreq[0]&=0xFF00;
209 curfreq[0]|=V;
210 break;
211 case 0x3:
212 if(PSG[0x15]&1)
213 {
214 DoSQ1();
215 lengthcount[0]=lengthtable[(V>>3)&0x1f];
216 sqnon|=1;
217 }
218 sweepon[0]=PSG[1]&0x80;
219 curfreq[0]=PSG[0x2]|((V&7)<<8);
220 decvolume[0]=0xF;
221 DecCountTo1[0]=(PSG[0]&0xF)+1;
222 SweepCount[0]=((PSG[0x1]>>4)&7)+1;
223 DutyCount[0]=0;
224 sqacc[0]=((int64)curfreq[0]+1)<<50;
225 break;
226
227 case 0x4:
228 DoSQ2();
229 if(V&0x10)
230 realvolume[1]=V&0xF;
231 break;
232 case 0x5:
233 sweepon[1]=V&0x80;
234 break;
235 case 0x6:
236 DoSQ2();
237 curfreq[1]&=0xFF00;
238 curfreq[1]|=V;
239 break;
240 case 0x7:
241 if(PSG[0x15]&2)
242 {
243 DoSQ2();
244 lengthcount[1]=lengthtable[(V>>3)&0x1f];
245 sqnon|=2;
246 }
247 sweepon[1]=PSG[0x5]&0x80;
248 curfreq[1]=PSG[0x6]|((V&7)<<8);
249 decvolume[1]=0xF;
250 DecCountTo1[1]=(PSG[0x4]&0xF)+1;
251 SweepCount[1]=((PSG[0x5]>>4)&7)+1;
252 DutyCount[1]=0;
253 sqacc[1]=((int64)curfreq[1]+1)<<50;
254 break;
255 case 0x8:
256 DoTriangle();
257 if(laster&0x80)
258 {
259 tricoop=V&0x7F;
260 trimode=V&0x80;
261 }
262 if(!(V&0x7F))
263 tricoop=0;
264 laster=V&0x80;
265 break;
266 case 0xa:DoTriangle();
267 break;
268 case 0xb:
269 if(PSG[0x15]&0x4)
270 {
271 DoTriangle();
272 sqnon|=4;
273 lengthcount[2]=lengthtable[(V>>3)&0x1f];
274 }
275 laster=0x80;
276 tricoop=PSG[0x8]&0x7f;
277 trimode=PSG[0x8]&0x80;
278 break;
279 case 0xC:DoNoise();
280 if(V&0x10)
281 realvolume[2]=V&0xF;
282 break;
283 case 0xE:DoNoise();break;
284 case 0xF:
285 if(PSG[0x15]&8)
286 {
287 DoNoise();
288 sqnon|=8;
289 lengthcount[3]=lengthtable[(V>>3)&0x1f];
290 }
291 decvolume[2]=0xF;
292 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
293 break;
294 case 0x10:DoPCM();
295 if(!(V&0x80))
296 X6502_IRQEnd(FCEU_IQDPCM);
297 break;
298 case 0x15:
299 {
300 int t=V^PSG[0x15];
301
302 if(t&1)
303 DoSQ1();
304 if(t&2)
305 DoSQ2();
306 if(t&4)
307 DoTriangle();
308 if(t&8)
309 DoNoise();
310 if(t&0x10)
311 DoPCM();
312 sqnon&=V;
313 if(V&0x10)
314 {
315 if(!(PSG[0x15]&0x10))
316 {
317 PrepDPCM();
318 CalcDPCMIRQ();
319 }
320 else if(vdis)
321 CalcDPCMIRQ();
322 }
323 else
324 PCMIRQCount=0;
325 X6502_IRQEnd(FCEU_IQDPCM);
326 }
327 break;
328 case 0x17:
329 V&=0xC0;
330 fcnt=0;
331 if(V&0x80)
332 FrameSoundUpdate();
333 fhcnt=fhinc;
334 X6502_IRQEnd(FCEU_IQFCOUNT);
335 SIRQStat&=~0x40;
336 break;
337 }
338 PSG[A]=V;
339}
340
341DECLFR(Read_PSG)
342{
343 uint8 ret;
344 if(PSG[0x15]&0x10)
345 DoPCM();
346 ret=(PSG[0x15]&(sqnon|0x10))|SIRQStat;
347 SIRQStat&=~0x40;
348 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
349 return ret;
350}
351
352DECLFR(Read_PSGDummy)
353{
354 uint8 ret;
355
356 ret=(PSG[0x15]&sqnon)|SIRQStat;
357 SIRQStat&=~0x40;
358 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
359 return ret;
360}
361
362static void FASTAPASS(1) FrameSoundStuff(int V)
363{
364 int P;
365
366 DoSQ1();
367 DoSQ2();
368 DoNoise();
369
370 switch((V&1))
371 {
372 case 1: /* Envelope decay, linear counter, length counter, freq sweep */
373 if(PSG[0x15]&4 && sqnon&4)
374 if(!(PSG[8]&0x80))
375 {
376 if(lengthcount[2]>0)
377 {
378 lengthcount[2]--;
379 if(lengthcount[2]<=0)
380 {
381 DoTriangle();
382 sqnon&=~4;
383 }
384 }
385 }
386
387 for(P=0;P<2;P++)
388 {
389 if(PSG[0x15]&(P+1) && sqnon&(P+1))
390 {
391 if(!(PSG[P<<2]&0x20))
392 {
393 if(lengthcount[P]>0)
394 {
395 lengthcount[P]--;
396 if(lengthcount[P]<=0)
397 {
398 sqnon&=~(P+1);
399 }
400 }
401 }
402 }
403 /* Frequency Sweep Code Here */
404 /* xxxx 0000 */
405 /* xxxx = hz. 120/(x+1)*/
406 if(sweepon[P])
407 {
408 int32 mod=0;
409
410 if(SweepCount[P]>0) SweepCount[P]--;
411 if(SweepCount[P]<=0)
412 {
413 SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1;
414 {
415 if(PSG[(P<<2)+0x1]&0x8)
416 {
417 mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7));
418
419 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
420 {
421 curfreq[P]+=mod;
422 }
423 }
424 else
425 {
426 mod=curfreq[P]>>(PSG[(P<<2)+0x1]&7);
427 if((mod+curfreq[P])&0x800)
428 {
429 sweepon[P]=0;
430 curfreq[P]=0;
431 }
432 else
433 {
434 if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
435 {
436 curfreq[P]+=mod;
437 }
438 }
439 }
440 }
441 }
442 }
443 }
444
445 if(PSG[0x15]&0x8 && sqnon&8)
446 {
447 if(!(PSG[0xC]&0x20))
448 {
449 if(lengthcount[3]>0)
450 {
451 lengthcount[3]--;
452 if(lengthcount[3]<=0)
453 {
454 sqnon&=~8;
455 }
456 }
457 }
458 }
459
460 case 0: /* Envelope decay + linear counter */
461 if(!trimode)
462 {
463 laster=0;
464 if(tricoop)
465 {
466 if(tricoop==1) DoTriangle();
467 tricoop--;
468 }
469 }
470
471 for(P=0;P<2;P++)
472 {
473 if(DecCountTo1[P]>0) DecCountTo1[P]--;
474 if(DecCountTo1[P]<=0)
475 {
476 DecCountTo1[P]=(PSG[P<<2]&0xF)+1;
477 if(decvolume[P] || PSG[P<<2]&0x20)
478 {
479 decvolume[P]--;
480 /* Step from 0 to full volume seems to take twice as long
481 as the other steps. I don't know if this is the correct
482 way to double its length, though(or if it even matters).
483 */
484 if((PSG[P<<2]&0x20) && (decvolume[P]==0))
485 DecCountTo1[P]<<=1;
486 decvolume[P]&=15;
487 }
488 }
489 if(!(PSG[P<<2]&0x10))
490 realvolume[P]=decvolume[P];
491 }
492
493 if(DecCountTo1[2]>0) DecCountTo1[2]--;
494 if(DecCountTo1[2]<=0)
495 {
496 DecCountTo1[2]=(PSG[0xC]&0xF)+1;
497 if(decvolume[2] || PSG[0xC]&0x20)
498 {
499 decvolume[2]--;
500 /* Step from 0 to full volume seems to take twice as long
501 as the other steps. I don't know if this is the correct
502 way to double its length, though(or if it even matters).
503 */
504 if((PSG[0xC]&0x20) && (decvolume[2]==0))
505 DecCountTo1[2]<<=1;
506 decvolume[2]&=15;
507 }
508 }
509 if(!(PSG[0xC]&0x10))
510 realvolume[2]=decvolume[2];
511
512 break;
513 }
514
515}
516
517void FrameSoundUpdate(void)
518{
519 // Linear counter: Bit 0-6 of $4008
520 // Length counter: Bit 4-7 of $4003, $4007, $400b, $400f
521
522 if(fcnt==3)
523 {
524 if(PSG[0x17]&0x80)
525 fhcnt+=fhinc;
526 if(!(PSG[0x17]&0xC0))
527 {
528 SIRQStat|=0x40;
529 X6502_IRQBegin(FCEU_IQFCOUNT);
530 }
531 }
532 //if(SIRQStat&0x40) X6502_IRQBegin(FCEU_IQFCOUNT);
533 FrameSoundStuff(fcnt);
534 fcnt=(fcnt+1)&3;
535}
536
537static uint32 ChannelBC[5];
538
539static uint32 RectAmp[2][8];
540
541static void FASTAPASS(1) CalcRectAmp(int P)
542{
543 static int tal[4]={1,2,4,6};
544 int V;
545 int x;
546 uint32 *b=RectAmp[P];
547 int m;
548
549 //if(PSG[P<<2]&0x10)
550 V=realvolume[P]<<4;
551 //V=(PSG[P<<2]&15)<<4;
552 //else
553 // V=decvolume[P]<<4;
554 m=tal[(PSG[P<<2]&0xC0)>>6];
555 for(x=0;x<m;x++,b++)
556 *b=0;
557 for(;x<8;x++,b++)
558 *b=V;
559}
560
561static void RDoPCM(void)
562{
563 int32 V;
564 int32 start,end;
565 int64 freq;
566 uint32 out=PSG[0x11]<<3;
567
568 start=ChannelBC[4];
569 end=(timestamp<<16)/soundtsinc;
570 if(end<=start) return;
571 ChannelBC[4]=end;
572
573 if(PSG[0x15]&0x10)
574 {
575 freq=PCMfreq;
576 freq<<=50;
577
578 for(V=start;V<end;V++)
579 {
580 PCMacc-=nesincsizeLL;
581 if(PCMacc<=0)
582 {
583 if(!PCMBitIndex)
584 {
585 PCMSizeIndex--;
586 if(!PCMSizeIndex)
587 {
588 if(PSG[0x10]&0x40)
589 PrepDPCM();
590 else
591 {
592 PSG[0x15]&=~0x10;
593 for(;V<end;V++)
594 Wave[V>>4]+=PSG[0x11]<<3;
595 goto endopcmo;
596 }
597 }
598 else
599 {
600 PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
601 PCMAddressIndex=(PCMAddressIndex+1)&0x7fff;
602 }
603 }
604
605 {
606 int t=(((PCMBuffer>>PCMBitIndex)&1)<<2)-2;
607 uint8 bah=PSG[0x11];
608
609 PCMacc+=freq;
610 PSG[0x11]+=t;
611 if(PSG[0x11]&0x80)
612 PSG[0x11]=bah;
613 else
614 out=PSG[0x11]<<3;
615 }
616 PCMBitIndex=(PCMBitIndex+1)&7;
617 }
618 Wave[V>>4]+=out; //(PSG[0x11]-64)<<3;
619 }
620 }
621 else
622 {
623 if((end-start)>64)
624 {
625 for(V=start;V<=(start|15);V++)
626 Wave[V>>4]+=out;
627 out<<=4;
628 for(V=(start>>4)+1;V<(end>>4);V++)
629 Wave[V]+=out;
630 out>>=4;
631 for(V=end&(~15);V<end;V++)
632 Wave[V>>4]+=out;
633 }
634 else
635 for(V=start;V<end;V++)
636 Wave[V>>4]+=out;
637 }
638 endopcmo:;
639}
640
641static void RDoSQ1(void)
642{
643 int32 V;
644 int32 start,end;
645 int64 freq;
646
647 CalcRectAmp(0);
648 start=ChannelBC[0];
649 end=(timestamp<<16)/soundtsinc;
650 if(end<=start) return;
651 ChannelBC[0]=end;
652
653 if(curfreq[0]<8 || curfreq[0]>0x7ff)
654 return;
655 if(!CheckFreq(curfreq[0],PSG[0x1]))
656 return;
657
658 if(PSG[0x15]&1 && sqnon&1)
659 {
660 uint32 out=RectAmp[0][DutyCount[0]];
661 freq=curfreq[0]+1;
662 {
663 freq<<=50;
664 for(V=start;V<end;V++)
665 {
666 Wave[V>>4]+=out;
667 sqacc[0]-=nesincsizeLL;
668 if(sqacc[0]<=0)
669 {
670 rea:
671 sqacc[0]+=freq;
672 DutyCount[0]++;
673 if(sqacc[0]<=0) goto rea;
674
675 DutyCount[0]&=7;
676 out=RectAmp[0][DutyCount[0]];
677 }
678
679 }
680 }
681 }
682}
683
684static void RDoSQ2(void)
685{
686 int32 V;
687 int32 start,end;
688 int64 freq;
689
690 CalcRectAmp(1);
691 start=ChannelBC[1];
692 end=(timestamp<<16)/soundtsinc;
693 if(end<=start) return;
694 ChannelBC[1]=end;
695
696 if(curfreq[1]<8 || curfreq[1]>0x7ff)
697 return;
698 if(!CheckFreq(curfreq[1],PSG[0x5]))
699 return;
700
701 if(PSG[0x15]&2 && sqnon&2)
702 {
703 uint32 out=RectAmp[1][DutyCount[1]];
704 freq=curfreq[1]+1;
705
706 {
707 freq<<=50;
708 for(V=start;V<end;V++)
709 {
710 Wave[V>>4]+=out;
711 sqacc[1]-=nesincsizeLL;
712 if(sqacc[1]<=0)
713 {
714 rea:
715 sqacc[1]+=freq;
716 DutyCount[1]++;
717 if(sqacc[1]<=0) goto rea;
718
719 DutyCount[1]&=7;
720 out=RectAmp[1][DutyCount[1]];
721 }
722
723 }
724 }
725 }
726}
727
728
729static void RDoTriangle(void)
730{
731 static uint32 tcout=0;
732 int32 V;
733 int32 start,end; //,freq;
734 int64 freq=(((PSG[0xa]|((PSG[0xb]&7)<<8))+1));
735
736 start=ChannelBC[2];
737 end=(timestamp<<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 int64 triacc=0;
761 static uint8 tc=0;
762
763 freq<<=49;
764 for(V=start;V<end;V++)
765 {
766 triacc-=nesincsizeLL;
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(void)
784{
785 int32 inc,V;
786 int32 start,end;
787
788 start=ChannelBC[3];
789 end=(timestamp<<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}
848
849void SetNESSoundMap(void)
850{
851 SetWriteHandler(0x4000,0x4013,Write_PSG);
852 SetWriteHandler(0x4011,0x4011,Write0x11);
853 SetWriteHandler(0x4015,0x4015,Write_PSG);
854 SetWriteHandler(0x4017,0x4017,Write_PSG);
855 SetReadHandler(0x4015,0x4015,Read_PSG);
856}
857
858static int32 WaveNSF[256];
859
860int64 highp; // 0 through 65536, 0 = no high pass, 65536 = max high pass
861
862int64 lowp; // 0 through 65536, 65536 = max low pass(total attenuation)
863 // 65536 = no low pass
864static void FilterSound(uint32 *in, int32 *out, int count)
865{
866 static int64 acc=0, acc2=0;
867
868 for(;count;count--,in++,out++)
869 {
870 int64 diff;
871
872 diff=((int64)*in<<24)-acc;
873
874 acc+=(diff*highp)>>16;
875 acc2+=((diff-acc2)*lowp)>>16;
876 *in=0;
877 *out=(acc2*(int64)FSettings.SoundVolume)>>(24+16);
878 if(*out<-32767) *out=-32767;
879 if(*out>32767) *out=32767;
880 //*out=((int64)(acc2>>24)*(int64)FSettings.SoundVolume)>>16; //acc2>>24;
881 }
882}
883
884int FlushEmulateSound(void)
885{
886 uint32 end;
887 int x;
888
889 if(!timestamp) return(0);
890
891 if(!FSettings.SndRate)
892 {
893 end=0;
894 goto nosoundo;
895 }
896
897 end=(timestamp<<16)/soundtsinc;
898 DoSQ1();
899 DoSQ2();
900 DoTriangle();
901 DoNoise();
902 DoPCM();
903
904 if(GameExpSound.Fill)
905 GameExpSound.Fill(end&0xF);
906
907 FilterSound(Wave,WaveFinal,end>>4);
908
909 if(FCEUGameInfo.type==GIT_NSF)
910 {
911 int x,s=0,si=end/1024; // Only want 1/4 of the output buffer to be displayed
912 for(x=0;x<256;x++)
913 {
914 WaveNSF[x]=WaveFinal[s>>4];
915 s+=si;
916 }
917 }
918
919 if(end&0xF)
920 Wave[0]=Wave[(end>>4)];
921 Wave[(end>>4)]=0;
922
923 nosoundo:
924 for(x=0;x<5;x++)
925 ChannelBC[x]=end&0xF;
926 timestampbase+=timestamp;
927 timestamp=(soundtsinc*(end&0xF))>>16;
928 timestampbase-=timestamp;
929 return(end>>4);
930}
931
932void GetSoundBuffer(int32 **W)
933{
934 *W=WaveNSF;
935}
936
937void PowerSound(void)
938{
939 int x;
940
941 SetNESSoundMap();
942
943 for(x=0;x<0x16;x++)
944 if(x!=0x14)
945 BWrite[0x4000+x](0x4000+x,0);
946 PSG[0x17]=0; //x40;
947 fhcnt=fhinc;
948 fcnt=0;
949 nreg=1;
950}
951
952void ResetSound(void)
953{
954 int x;
955 for(x=0;x<0x16;x++)
956 if(x!=1 && x!=5 && x!=0x14) BWrite[0x4000+x](0x4000+x,0);
957 PSG[0x17]=0;
958 fhcnt=fhinc;
959 fcnt=0;
960 nreg=1;
961}
962
963void SetSoundVariables(void)
964{
965 int x;
966
967 fhinc=PAL?16626:14915; // *2 CPU clock rate
968 fhinc*=24;
969 for(x=0;x<0x20;x++)
970 lengthtable[x]=Slengthtable[x]<<1;
971
972 if(FSettings.SndRate)
973 {
974 DoNoise=RDoNoise;
975 DoTriangle=RDoTriangle;
976 DoPCM=RDoPCM;
977 DoSQ1=RDoSQ1;
978 DoSQ2=RDoSQ2;
979 }
980 else
981 {
982 DoNoise=DoTriangle=DoPCM=DoSQ1=DoSQ2=Dummyfunc;
983 }
984
985 if(!FSettings.SndRate) return;
986 if(GameExpSound.RChange)
987 GameExpSound.RChange();
988
989 nesincsizeLL=(int64)((int64)562949953421312*(long double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate OVERSAMPLE));
990 PSG_base=(uint32)(PAL?(long double)PAL_CPU/16:(long double)NTSC_CPU/16);
991
992 for(x=0;x<0x10;x++)
993 {
994 long double z;
995 z=SNoiseFreqTable[x]<<1;
996 z=(PAL?PAL_CPU:NTSC_CPU)/z;
997 z=(long double)((uint32)((FSettings.SndRate OVERSAMPLE)<<12))/z;
998 NoiseFreqTable[x]=z;
999 }
1000 soundtsinc=(uint32)((uint64)(PAL?(long double)PAL_CPU*65536:(long double)NTSC_CPU*65536)/(FSettings.SndRate OVERSAMPLE));
1001 memset(Wave,0,2048*4);
1002 for(x=0;x<5;x++)
1003 ChannelBC[x]=0;
1004 highp=(250<<16)/FSettings.SndRate; // Arbitrary
1005 lowp=((int64)25000<<16)/FSettings.SndRate; // Arbitrary
1006
1007 if(highp>(1<<16)) highp=1<<16;
1008 if(lowp>(1<<16)) lowp=1<<16;
1009}
1010
1011void FixOldSaveStateSFreq(void)
1012{
1013 int x;
1014 for(x=0;x<2;x++)
1015 {
1016 curfreq[x]=PSG[0x2+(x<<2)]|((PSG[0x3+(x<<2)]&7)<<8);
1017 }
1018}
1019
1020void FCEUI_Sound(int Rate)
1021{
1022 FSettings.SndRate=Rate;
1023 SetSoundVariables();
1024}
1025
1026void FCEUI_SetSoundVolume(uint32 volume)
1027{
1028 FSettings.SoundVolume=(volume<<16)/100;
1029}