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