merge x6502 code FCEUX
[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
a384bf44 42uint32 Wave[2048+512];
ebde7d27 43int32 WaveHi[40000]; // unused
a384bf44 44int16 WaveFinalMono[2048+512];
c62d2810 45
a384bf44 46EXPSOUND GameExpSound={0,0,0,0,0,0};
c62d2810 47
48uint8 trimode=0;
49uint8 tricoop=0;
50uint8 PSG[0x18];
51
52uint8 decvolume[3];
53uint8 realvolume[3];
54
55static int32 count[5];
ec4d13a3 56static int32 sqacc[2]={0,0};
c62d2810 57uint8 sqnon=0;
58
4fdfab07 59uint32 soundtsoffs=0;
60
c62d2810 61#undef printf
62uint16 nreg;
9115e7d2 63
a384bf44 64static int32 lengthcount[4];
c62d2810 65
5232c20c 66extern int soundvol;
67
c62d2810 68static const uint8 Slengthtable[0x20]=
69{
70 0x5,0x7f,0xA,0x1,0x14,0x2,0x28,0x3,0x50,0x4,0x1E,0x5,0x7,0x6,0x0E,0x7,
71 0x6,0x08,0xC,0x9,0x18,0xa,0x30,0xb,0x60,0xc,0x24,0xd,0x8,0xe,0x10,0xf
72};
73
74static uint32 lengthtable[0x20];
75
76static const uint32 SNoiseFreqTable[0x10]=
77{
78 2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
79};
80static uint32 NoiseFreqTable[0x10];
81
a384bf44 82int32 nesincsize;
83uint32 soundtsinc;
84uint32 soundtsi;
85
c62d2810 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
ec4d13a3 107static int32 PCMacc=0;
c62d2810 108static int PCMfreq;
109int32 PCMIRQCount;
110uint8 PCMBitIndex=0;
111uint32 PCMAddressIndex=0;
112int32 PCMSizeIndex=0;
9115e7d2 113uint8 PCMBuffer=0;
c62d2810 114int vdis=0;
115
d447f17f 116static void Dummyfunc(int end) {};
c62d2810 117
d447f17f 118static void (*DoNoise)(int end)=Dummyfunc;
119static void (*DoTriangle)(int end)=Dummyfunc;
120static void (*DoPCM)(int end)=Dummyfunc;
121static void (*DoSQ1)(int end)=Dummyfunc;
122static void (*DoSQ2)(int end)=Dummyfunc;
c62d2810 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];
ec4d13a3 157 PCMacc=PCMfreq<<18;
c62d2810 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{
d447f17f 190 DoPCM(0);
c62d2810 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:
d447f17f 204 DoSQ1(0);
c62d2810 205 if(V&0x10)
206 realvolume[0]=V&0xF;
207 break;
208 case 0x1:
209 sweepon[0]=V&0x80;
210 break;
211 case 0x2:
d447f17f 212 DoSQ1(0);
c62d2810 213 curfreq[0]&=0xFF00;
214 curfreq[0]|=V;
215 break;
9115e7d2 216 case 0x3:
c62d2810 217 if(PSG[0x15]&1)
218 {
d447f17f 219 DoSQ1(0);
c62d2810 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;
ec4d13a3 229 sqacc[0]=((int32)curfreq[0]+1)<<18;
c62d2810 230 break;
231
9115e7d2 232 case 0x4:
d447f17f 233 DoSQ2(0);
c62d2810 234 if(V&0x10)
235 realvolume[1]=V&0xF;
236 break;
237 case 0x5:
238 sweepon[1]=V&0x80;
239 break;
240 case 0x6:
d447f17f 241 DoSQ2(0);
c62d2810 242 curfreq[1]&=0xFF00;
243 curfreq[1]|=V;
244 break;
9115e7d2 245 case 0x7:
c62d2810 246 if(PSG[0x15]&2)
247 {
d447f17f 248 DoSQ2(0);
c62d2810 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;
ec4d13a3 258 sqacc[1]=((int32)curfreq[1]+1)<<18;
c62d2810 259 break;
9115e7d2 260 case 0x8:
d447f17f 261 DoTriangle(0);
c62d2810 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;
d447f17f 271 case 0xa:DoTriangle(0);
c62d2810 272 break;
273 case 0xb:
274 if(PSG[0x15]&0x4)
275 {
d447f17f 276 DoTriangle(0);
c62d2810 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;
d447f17f 284 case 0xC:DoNoise(0);
c62d2810 285 if(V&0x10)
286 realvolume[2]=V&0xF;
287 break;
d447f17f 288 case 0xE:DoNoise(0);break;
c62d2810 289 case 0xF:
290 if(PSG[0x15]&8)
291 {
d447f17f 292 DoNoise(0);
c62d2810 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;
d447f17f 299 case 0x10:DoPCM(0);
c62d2810 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)
d447f17f 308 DoSQ1(0);
c62d2810 309 if(t&2)
d447f17f 310 DoSQ2(0);
c62d2810 311 if(t&4)
d447f17f 312 DoTriangle(0);
c62d2810 313 if(t&8)
d447f17f 314 DoNoise(0);
c62d2810 315 if(t&0x10)
d447f17f 316 DoPCM(0);
c62d2810 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;
c62d2810 333 }
334 PSG[A]=V;
335}
336
337DECLFR(Read_PSG)
338{
339 uint8 ret;
340 if(PSG[0x15]&0x10)
d447f17f 341 DoPCM(0);
c62d2810 342 ret=(PSG[0x15]&(sqnon|0x10))|SIRQStat;
343 SIRQStat&=~0x40;
344 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
345 return ret;
346}
347
348DECLFR(Read_PSGDummy)
349{
350 uint8 ret;
351
352 ret=(PSG[0x15]&sqnon)|SIRQStat;
353 SIRQStat&=~0x40;
354 X6502_IRQEnd(/*FCEU_IQDPCM|*/FCEU_IQFCOUNT);
355 return ret;
356}
357
358static void FASTAPASS(1) FrameSoundStuff(int V)
359{
360 int P;
d447f17f 361 uint32 end = (SOUNDTS<<16)/soundtsinc;
c62d2810 362
d447f17f 363 DoSQ1(end);
364 DoSQ2(end);
365 DoNoise(end);
c62d2810 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 {
d447f17f 378 DoTriangle(0);
c62d2810 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 {
d447f17f 463 if(tricoop==1) DoTriangle(0);
c62d2810 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
3ac1cc0b 558void FCEU_SoundCPUHook(int cycles48)
559{
560 fhcnt-=cycles48;
561 if(fhcnt<=0)
562 {
563 FrameSoundUpdate();
564 fhcnt+=fhinc;
565 }
566
567 if(PCMIRQCount>0)
568 {
569 PCMIRQCount-=cycles48;
570 if(PCMIRQCount<=0)
571 {
572 vdis=1;
573 if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
574 {
575 extern uint8 SIRQStat;
576 SIRQStat|=0x80;
577 X6502_IRQBegin(FCEU_IQDPCM);
578 }
579 }
580 }
581}
582
d447f17f 583static void RDoPCM(int32 end)
c62d2810 584{
585 int32 V;
d447f17f 586 int32 start;
ec4d13a3 587 int32 freq;
c62d2810 588 uint32 out=PSG[0x11]<<3;
589
590 start=ChannelBC[4];
d447f17f 591 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
c62d2810 592 if(end<=start) return;
593 ChannelBC[4]=end;
594
595 if(PSG[0x15]&0x10)
596 {
597 freq=PCMfreq;
ec4d13a3 598 freq<<=18;
c62d2810 599
600 for(V=start;V<end;V++)
601 {
a384bf44 602 PCMacc-=nesincsize;
c62d2810 603 if(PCMacc<=0)
604 {
605 if(!PCMBitIndex)
606 {
607 PCMSizeIndex--;
608 if(!PCMSizeIndex)
609 {
610 if(PSG[0x10]&0x40)
611 PrepDPCM();
612 else
613 {
614 PSG[0x15]&=~0x10;
615 for(;V<end;V++)
616 Wave[V>>4]+=PSG[0x11]<<3;
617 goto endopcmo;
618 }
619 }
620 else
621 {
622 PCMBuffer=ARead[0x8000+PCMAddressIndex](0x8000+PCMAddressIndex);
623 PCMAddressIndex=(PCMAddressIndex+1)&0x7fff;
624 }
625 }
626
627 {
628 int t=(((PCMBuffer>>PCMBitIndex)&1)<<2)-2;
629 uint8 bah=PSG[0x11];
630
631 PCMacc+=freq;
632 PSG[0x11]+=t;
633 if(PSG[0x11]&0x80)
634 PSG[0x11]=bah;
635 else
636 out=PSG[0x11]<<3;
637 }
638 PCMBitIndex=(PCMBitIndex+1)&7;
639 }
640 Wave[V>>4]+=out; //(PSG[0x11]-64)<<3;
641 }
642 }
643 else
644 {
645 if((end-start)>64)
646 {
647 for(V=start;V<=(start|15);V++)
648 Wave[V>>4]+=out;
649 out<<=4;
650 for(V=(start>>4)+1;V<(end>>4);V++)
651 Wave[V]+=out;
652 out>>=4;
653 for(V=end&(~15);V<end;V++)
654 Wave[V>>4]+=out;
655 }
656 else
657 for(V=start;V<end;V++)
658 Wave[V>>4]+=out;
659 }
660 endopcmo:;
661}
662
d447f17f 663static void RDoSQ1(int32 end)
c62d2810 664{
665 int32 V;
d447f17f 666 int32 start;
ec4d13a3 667 int32 freq;
c62d2810 668
c62d2810 669 start=ChannelBC[0];
d447f17f 670 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
c62d2810 671 if(end<=start) return;
672 ChannelBC[0]=end;
673
d447f17f 674 if(!(PSG[0x15]&1 && sqnon&1))
675 return;
676
c62d2810 677 if(curfreq[0]<8 || curfreq[0]>0x7ff)
678 return;
679 if(!CheckFreq(curfreq[0],PSG[0x1]))
680 return;
681
d447f17f 682 CalcRectAmp(0);
683
c62d2810 684 {
685 uint32 out=RectAmp[0][DutyCount[0]];
686 freq=curfreq[0]+1;
687 {
ec4d13a3 688 freq<<=18;
c62d2810 689 for(V=start;V<end;V++)
690 {
691 Wave[V>>4]+=out;
a384bf44 692 sqacc[0]-=nesincsize;
c62d2810 693 if(sqacc[0]<=0)
694 {
695 rea:
696 sqacc[0]+=freq;
697 DutyCount[0]++;
698 if(sqacc[0]<=0) goto rea;
699
700 DutyCount[0]&=7;
701 out=RectAmp[0][DutyCount[0]];
702 }
c62d2810 703 }
c62d2810 704 }
d447f17f 705 }
c62d2810 706}
707
d447f17f 708static void RDoSQ2(int32 end)
c62d2810 709{
710 int32 V;
d447f17f 711 int32 start;
ec4d13a3 712 int32 freq;
c62d2810 713
c62d2810 714 start=ChannelBC[1];
d447f17f 715 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
c62d2810 716 if(end<=start) return;
717 ChannelBC[1]=end;
718
d447f17f 719 if(!(PSG[0x15]&2 && sqnon&2))
720 return;
721
c62d2810 722 if(curfreq[1]<8 || curfreq[1]>0x7ff)
723 return;
724 if(!CheckFreq(curfreq[1],PSG[0x5]))
725 return;
726
d447f17f 727 CalcRectAmp(1);
728
c62d2810 729 {
730 uint32 out=RectAmp[1][DutyCount[1]];
731 freq=curfreq[1]+1;
732
733 {
ec4d13a3 734 freq<<=18;
c62d2810 735 for(V=start;V<end;V++)
736 {
737 Wave[V>>4]+=out;
a384bf44 738 sqacc[1]-=nesincsize;
c62d2810 739 if(sqacc[1]<=0)
740 {
741 rea:
742 sqacc[1]+=freq;
743 DutyCount[1]++;
744 if(sqacc[1]<=0) goto rea;
745
746 DutyCount[1]&=7;
747 out=RectAmp[1][DutyCount[1]];
748 }
c62d2810 749 }
c62d2810 750 }
d447f17f 751 }
c62d2810 752}
753
754
d447f17f 755static void RDoTriangle(int32 end)
c62d2810 756{
757 static uint32 tcout=0;
758 int32 V;
d447f17f 759 int32 start; //,freq;
ec4d13a3 760 int32 freq=(((PSG[0xa]|((PSG[0xb]&7)<<8))+1));
c62d2810 761
762 start=ChannelBC[2];
d447f17f 763 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
c62d2810 764 if(end<=start) return;
765 ChannelBC[2]=end;
766
767 if(! (PSG[0x15]&0x4 && sqnon&4 && tricoop) )
768 { // Counter is halted, but we still need to output.
769 for(V=start;V<end;V++)
770 Wave[V>>4]+=tcout;
771 }
772 else if(freq<=4) // 55.9Khz - Might be barely audible on a real NES, but
773 // it's too costly to generate audio at this high of a frequency
774 // (55.9Khz * 32 for the stepping).
775 // The same could probably be said for ~27.8Khz, so we'll
776 // take care of that too. We'll just output the average
777 // value(15/2 - scaled properly for our output format, of course).
778 // We'll also take care of ~18Khz and ~14Khz too, since they should be barely audible.
779 // (Some proof or anything to confirm/disprove this would be nice.).
780 {
781 for(V=start;V<end;V++)
782 Wave[V>>4]+=((0xF<<4)+(0xF<<2))>>1;
783 }
784 else
785 {
ec4d13a3 786 static int32 triacc=0;
9115e7d2 787 static uint8 tc=0;
c62d2810 788
ec4d13a3 789 freq<<=17;
c62d2810 790 for(V=start;V<end;V++)
791 {
a384bf44 792 triacc-=nesincsize;
c62d2810 793 if(triacc<=0)
794 {
795 rea:
796 triacc+=freq; //t;
797 tc=(tc+1)&0x1F;
798 if(triacc<=0) goto rea;
799
800 tcout=(tc&0xF);
801 if(tc&0x10) tcout^=0xF;
802 tcout=(tcout<<4)+(tcout<<2);
803 }
804 Wave[V>>4]+=tcout;
805 }
806 }
807}
808
d447f17f 809static void RDoNoise(int32 end)
c62d2810 810{
811 int32 inc,V;
d447f17f 812 int32 start;
c62d2810 813
814 start=ChannelBC[3];
d447f17f 815 if(end==0) end=(SOUNDTS<<16)/soundtsinc;
c62d2810 816 if(end<=start) return;
817 ChannelBC[3]=end;
818
819 if(PSG[0x15]&0x8 && sqnon&8)
820 {
821 uint32 outo;
822 uint32 amptab[2];
823 uint8 amplitude;
9115e7d2 824
c62d2810 825 amplitude=realvolume[2];
826 //if(PSG[0xC]&0x10)
827 // amplitude=(PSG[0xC]&0xF);
9115e7d2 828 //else
c62d2810 829 // amplitude=decvolume[2]&0xF;
830
9115e7d2 831 inc=NoiseFreqTable[PSG[0xE]&0xF];
c62d2810 832 amptab[0]=((amplitude<<2)+amplitude+amplitude)<<1;
833 amptab[1]=0;
834 outo=amptab[nreg&1];
835
9115e7d2 836 if(amplitude)
c62d2810 837 {
9115e7d2 838 if(PSG[0xE]&0x80) // "short" noise
c62d2810 839 for(V=start;V<end;V++)
9115e7d2 840 {
c62d2810 841 Wave[V>>4]+=outo;
842 if(count[3]>=inc)
9115e7d2 843 {
844 uint8 feedback;
c62d2810 845
846 feedback=((nreg>>8)&1)^((nreg>>14)&1);
847 nreg=(nreg<<1)+feedback;
848 nreg&=0x7fff;
849 outo=amptab[nreg&1];
850 count[3]-=inc;
851 }
852 count[3]+=0x1000;
853 }
854 else
855 for(V=start;V<end;V++)
856 {
857 Wave[V>>4]+=outo;
858 if(count[3]>=inc)
859 {
860 uint8 feedback;
861
862 feedback=((nreg>>13)&1)^((nreg>>14)&1);
863 nreg=(nreg<<1)+feedback;
864 nreg&=0x7fff;
865 outo=amptab[nreg&1];
866 count[3]-=inc;
867 }
868 count[3]+=0x1000;
869 }
870 }
c62d2810 871 }
872}
873
77887306 874DECLFW(Write_IRQFM)
d97315ac 875{
ea80a45b 876 PSG[0x17]=V;
d97315ac 877 V=(V&0xC0)>>6;
878 fcnt=0;
879 if(V&0x2)
880 FrameSoundUpdate();
881 fcnt=1;
882 fhcnt=fhinc;
883 X6502_IRQEnd(FCEU_IQFCOUNT);
884 SIRQStat&=~0x40;
ea80a45b 885 //IRQFrameMode=V; // IRQFrameMode is PSG[0x17] upper bits
d97315ac 886}
887
c62d2810 888void SetNESSoundMap(void)
9115e7d2 889{
c62d2810 890 SetWriteHandler(0x4000,0x4013,Write_PSG);
891 SetWriteHandler(0x4011,0x4011,Write0x11);
892 SetWriteHandler(0x4015,0x4015,Write_PSG);
d97315ac 893 SetWriteHandler(0x4017,0x4017,Write_IRQFM);
c62d2810 894 SetReadHandler(0x4015,0x4015,Read_PSG);
895}
896
9115e7d2 897int32 highp; // 0 through 65536, 0 = no high pass, 65536 = max high pass
c62d2810 898
9115e7d2 899int32 lowp; // 0 through 65536, 65536 = max low pass(total attenuation)
c62d2810 900 // 65536 = no low pass
7b356ee3 901static int32 flt_acc=0, flt_acc2=0;
902
d447f17f 903static void FilterSound(uint32 *in, int16 *outMono, int count)
c62d2810 904{
d447f17f 905// static int min=0, max=0;
0ab4d38f 906 int sh=2;
907 if (soundvol < 5) sh += 5 - soundvol;
ec4d13a3 908
909 for(;count;count--,in++,outMono++)
c62d2810 910 {
ec4d13a3 911 int32 diff;
c62d2810 912
7b356ee3 913 diff = *in - flt_acc;
c62d2810 914
7b356ee3 915 flt_acc += (diff*highp)>>16;
916 flt_acc2+= (int32) (((int64)((diff-flt_acc2)*lowp))>>16);
c62d2810 917 *in=0;
9115e7d2 918
0ab4d38f 919 *outMono = flt_acc2*7 >> sh; // * 7 >> 2 = * 1.75
d447f17f 920// if (acc2 < min) { printf("min: %i %04x\n", acc2, acc2); min = acc2; }
921// if (acc2 > max) { printf("max: %i %04x\n", acc2, acc2); max = acc2; }
c62d2810 922 }
923}
924
5232c20c 925
926
d97315ac 927static int32 inbuf=0;
c62d2810 928int FlushEmulateSound(void)
929{
c62d2810 930 int x;
4fdfab07 931 uint32 end;
5232c20c 932
c62d2810 933 if(!timestamp) return(0);
934
5232c20c 935 if(!FSettings.SndRate || (soundvol == 0))
c62d2810 936 {
937 end=0;
938 goto nosoundo;
939 }
940
4fdfab07 941 end=(SOUNDTS<<16)/soundtsinc;
d447f17f 942 DoSQ1(end);
943 DoSQ2(end);
944 DoTriangle(end);
945 DoNoise(end);
946 DoPCM(end);
c62d2810 947
948 if(GameExpSound.Fill)
949 GameExpSound.Fill(end&0xF);
950
d447f17f 951 FilterSound(Wave,WaveFinalMono,end>>4);
c62d2810 952
953 if(end&0xF)
954 Wave[0]=Wave[(end>>4)];
9115e7d2 955 Wave[(end>>4)]=0;
c62d2810 956
957 nosoundo:
958 for(x=0;x<5;x++)
959 ChannelBC[x]=end&0xF;
4fdfab07 960 soundtsoffs=(soundtsinc*(end&0xF))>>16;
d97315ac 961 end>>=4;
962 inbuf=end;
963 return(end);
c62d2810 964}
965
c4980f9e 966int GetSoundBuffer(int16 **W)
c62d2810 967{
c4980f9e 968 *W=WaveFinalMono;
d97315ac 969 return inbuf;
c62d2810 970}
971
972void PowerSound(void)
973{
974 int x;
975
976 SetNESSoundMap();
977
978 for(x=0;x<0x16;x++)
979 if(x!=0x14)
980 BWrite[0x4000+x](0x4000+x,0);
981 PSG[0x17]=0; //x40;
982 fhcnt=fhinc;
983 fcnt=0;
984 nreg=1;
4fdfab07 985 soundtsoffs=0;
c62d2810 986}
987
988void ResetSound(void)
989{
990 int x;
991 for(x=0;x<0x16;x++)
992 if(x!=1 && x!=5 && x!=0x14) BWrite[0x4000+x](0x4000+x,0);
993 PSG[0x17]=0;
994 fhcnt=fhinc;
995 fcnt=0;
996 nreg=1;
997}
998
77887306 999void SetSoundVariables(void)
c62d2810 1000{
9115e7d2 1001 int x;
c62d2810 1002
1003 fhinc=PAL?16626:14915; // *2 CPU clock rate
1004 fhinc*=24;
1005 for(x=0;x<0x20;x++)
1006 lengthtable[x]=Slengthtable[x]<<1;
1007
1008 if(FSettings.SndRate)
1009 {
1010 DoNoise=RDoNoise;
1011 DoTriangle=RDoTriangle;
1012 DoPCM=RDoPCM;
1013 DoSQ1=RDoSQ1;
1014 DoSQ2=RDoSQ2;
9115e7d2 1015 }
c62d2810 1016 else
1017 {
1018 DoNoise=DoTriangle=DoPCM=DoSQ1=DoSQ2=Dummyfunc;
1019 }
1020
1021 if(!FSettings.SndRate) return;
1022 if(GameExpSound.RChange)
1023 GameExpSound.RChange();
1024
ec4d13a3 1025 // nesincsizeLL=(int64)((int64)562949953421312*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate OVERSAMPLE));
a384bf44 1026 nesincsize=(int32)(((int64)1<<17)*(double)(PAL?PAL_CPU:NTSC_CPU)/(FSettings.SndRate * 16)); // 308845 - 1832727
c62d2810 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));
d447f17f 1038 memset(Wave,0,sizeof(Wave));
c62d2810 1039 for(x=0;x<5;x++)
1040 ChannelBC[x]=0;
1041 highp=(250<<16)/FSettings.SndRate; // Arbitrary
ec4d13a3 1042 lowp=(25000<<16)/FSettings.SndRate; // Arbitrary
c62d2810 1043
1044 if(highp>(1<<16)) highp=1<<16;
1045 if(lowp>(1<<16)) lowp=1<<16;
7b356ee3 1046
1047 flt_acc=flt_acc2=0;
c62d2810 1048}
1049
1050void FixOldSaveStateSFreq(void)
1051{
1052 int x;
1053 for(x=0;x<2;x++)
1054 {
1055 curfreq[x]=PSG[0x2+(x<<2)]|((PSG[0x3+(x<<2)]&7)<<8);
1056 }
1057}
1058
1059void FCEUI_Sound(int Rate)
1060{
1061 FSettings.SndRate=Rate;
1062 SetSoundVariables();
1063}
1064
1065void FCEUI_SetSoundVolume(uint32 volume)
1066{
92764e62 1067 FSettings.SoundVolume=volume;
c62d2810 1068}