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