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