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