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