1 /* Festalon - NSF Player
2 * Copyright (C) 2004 Xodnizel
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "common.h"
24
25 static DECLFW(FDSWaveWrite);
26 static DECLFR(FDSWaveRead);
27
28 static DECLFR(FDSSRead);
29 static DECLFW(FDSSWrite);
30
31 static void RenderSoundHQ(void *);
32
33 /* Begin FDS sound */
34
35 #define FDSClock (1789772.7272727272727272/2)
36
37 typedef struct {
38 int64 cycles; // Cycles per PCM sample
39 int64 count; // Cycle counter
40 int64 envcount; // Envelope cycle counter
41 uint32 b19shiftreg60;
42 uint32 b24adder66;
43 uint32 b24latch68;
44 uint32 b17latch76;
45 int32 clockcount; // Counter to divide frequency by 8.
46 uint8 b8shiftreg88; // Modulation register.
47 uint8 amplitude[2]; // Current amplitudes.
48 uint8 speedo[2];
49 uint8 mwcount;
50 uint8 mwstart;
51 uint8 mwave[0x20]; // Modulation waveform
52 uint8 cwave[0x40]; // Game-defined waveform(carrier)
53 uint8 SPSG[0xB];
54
55 int32 FBC;
56 int counto[2];
57
58 int disabled;
59 int32 curout;
60 NESAPU *gapu;
61 } FDSSOUND;
62
63 #define SPSG fdso->SPSG
64 #define b19shiftreg60 fdso->b19shiftreg60
65 #define b24adder66 fdso->b24adder66
66 #define b24latch68 fdso->b24latch68
67 #define b17latch76 fdso->b17latch76
68 #define b8shiftreg88 fdso->b8shiftreg88
69 #define clockcount fdso->clockcount
70 #define amplitude fdso->amplitude
71 #define speedo fdso->speedo
72
RedoCO(FDSSOUND * fdso)73 static INLINE void RedoCO(FDSSOUND *fdso)
74 {
75 int k=amplitude[0];
76 if(k>0x20) k=0x20;
77 fdso->curout = (fdso->cwave[b24latch68>>19]*k)*4/((SPSG[0x9]&0x3)+2);
78 }
79
DECLFR(FDSSRead)80 static DECLFR(FDSSRead)
81 {
82 FDSSOUND *fdso=private;
83
84 switch(A&0xF)
85 {
86 case 0x0:return(amplitude[0]|(DB&0xC0));
87 case 0x2:return(amplitude[1]|(DB&0xC0));
88 }
89 return(DB);
90 }
91
DECLFW(FDSSWrite)92 static DECLFW(FDSSWrite)
93 {
94 FDSSOUND *fdso=private;
95 RenderSoundHQ(fdso);
96
97 A-=0x4080;
98 switch(A)
99 {
100 case 0x0:
101 case 0x4: if(V&0x80)
102 amplitude[(A&0xF)>>2]=V&0x3F; //)>0x20?0x20:(V&0x3F);
103 break;
104 case 0x5://printf("$%04x:$%02x\n",A,V);
105 break;
106 case 0x7: b17latch76=0;SPSG[0x5]=0;//printf("$%04x:$%02x\n",A,V);
107 break;
108 case 0x8:
109 b17latch76=0;
110 // printf("%d:$%02x, $%02x\n",SPSG[0x5],V,b17latch76);
111 fdso->mwave[SPSG[0x5]&0x1F]=V&0x7;
112 SPSG[0x5]=(SPSG[0x5]+1)&0x1F;
113 break;
114 }
115 //if(A>=0x7 && A!=0x8 && A<=0xF)
116 //if(A==0xA || A==0x9)
117 //printf("$%04x:$%02x\n",A,V);
118 SPSG[A]=V;
119
120 if(A == 0x9) RedoCO(fdso);
121 }
122
123 // $4080 - Fundamental wave amplitude data register 92
124 // $4082 - Fundamental wave frequency data register 58
125 // $4083 - Same as $4082($4083 is the upper 4 bits).
126
127 // $4084 - Modulation amplitude data register 78
128 // $4086 - Modulation frequency data register 72
129 // $4087 - Same as $4086($4087 is the upper 4 bits)
130
131
DoEnv(FDSSOUND * fdso)132 static void DoEnv(FDSSOUND *fdso)
133 {
134 int x;
135
136 for(x=0;x<2;x++)
137 if(!(SPSG[x<<2]&0x80) && !(SPSG[0x3]&0x40))
138 {
139 if(fdso->counto[x]<=0)
140 {
141 if(!(SPSG[x<<2]&0x80))
142 {
143 if(SPSG[x<<2]&0x40)
144 {
145 if(amplitude[x]<0x3F)
146 amplitude[x]++;
147 }
148 else
149 {
150 if(amplitude[x]>0)
151 amplitude[x]--;
152 }
153 }
154 fdso->counto[x]=(SPSG[x<<2]&0x3F);
155 if(x == 0) RedoCO(fdso);
156 }
157 else
158 fdso->counto[x]--;
159 }
160 }
161
DECLFR(FDSWaveRead)162 static DECLFR(FDSWaveRead)
163 {
164 FDSSOUND *fdso=private;
165 return(fdso->cwave[A&0x3f]|(DB&0xC0));
166 }
167
DECLFW(FDSWaveWrite)168 static DECLFW(FDSWaveWrite)
169 {
170 FDSSOUND *fdso=private;
171 //printf("$%04x:$%02x, %d\n",A,V,SPSG[0x9]&0x80);
172 if(SPSG[0x9]&0x80)
173 fdso->cwave[A&0x3f]=V&0x3F;
174 }
175
ClockRise(FDSSOUND * fdso)176 static INLINE void ClockRise(FDSSOUND *fdso)
177 {
178 if(!clockcount)
179 {
180 b19shiftreg60=(SPSG[0x2]|((SPSG[0x3]&0xF)<<8));
181 b17latch76=(SPSG[0x6]|((SPSG[0x07]&0xF)<<8))+b17latch76;
182
183 if(!(SPSG[0x7]&0x80))
184 {
185 int t=fdso->mwave[(b17latch76>>13)&0x1F]&7;
186 int t2=amplitude[1];
187
188 if(t2>0x20) t2=0x20;
189
190 /*if(t&4)
191 {
192 if(t==4) t=0;
193 else t=t2*((3-t)&3);
194 t=0x80-t;
195 }
196 else
197 {
198 t=t2*(t&3);
199 t=0x80+t;
200 }
201 */
202 t=0x80+t2*t/2;
203
204 //if(t&4)
205 // t=0x80-((t&3))*t2;
206 //else
207 // t=0x80+((t&3))*t2; //(0x80+(t&3))*(amplitude[1]); //t; //amplitude[1]*3; //t; //(amplitude[1])*(fdso->mwave[(b17latch76>>13)&0x1F]&7);
208
209 b8shiftreg88=t; //(t+0x80)*(amplitude[1]);
210
211 // t=0;
212 //t=(t-4)*(amplitude[1]);
213 //FCEU_DispMessage("%d",amplitude[1]);
214 //b8shiftreg88=((fdso->mwave[(b17latch76>>11)&0x1F]&7))|(amplitude[1]<<3);
215 }
216 else
217 {
218 b8shiftreg88=0x80;
219 }
220 //b8shiftreg88=0x80;
221 }
222 else
223 {
224 b19shiftreg60<<=1;
225 b8shiftreg88>>=1;
226 }
227 // b24adder66=(b24latch68+b19shiftreg60)&0x3FFFFFF;
228 b24adder66=(b24latch68+b19shiftreg60)&0x1FFFFFF;
229 }
230
ClockFall(FDSSOUND * fdso)231 static INLINE void ClockFall(FDSSOUND *fdso)
232 {
233 //if(!(SPSG[0x7]&0x80))
234 {
235 if((b8shiftreg88&1)) // || clockcount==7)
236 {
237 b24latch68=b24adder66;
238 RedoCO(fdso);
239 }
240 }
241 clockcount=(clockcount+1)&7;
242 }
243
FDSDoSound(FDSSOUND * fdso)244 static INLINE int32 FDSDoSound(FDSSOUND *fdso)
245 {
246 fdso->count+=fdso->cycles;
247 if(fdso->count>=((int64)1<<40))
248 {
249 dogk:
250 fdso->count-=(int64)1<<40;
251 ClockRise(fdso);
252 ClockFall(fdso);
253 fdso->envcount--;
254 if(fdso->envcount<=0)
255 {
256 fdso->envcount+=SPSG[0xA]*3;
257 DoEnv(fdso);
258 }
259 }
260 if(fdso->count>=32768) goto dogk;
261
262 return (fdso->curout);
263 }
264
RenderSoundHQ(void * private)265 static void RenderSoundHQ(void *private)
266 {
267 FDSSOUND *fdso=private;
268 int32 x;
269
270 if(!(SPSG[0x9]&0x80) && !(fdso->disabled&0x1))
271 for(x=fdso->FBC;x<fdso->gapu->X->timestamp;x++)
272 {
273 uint32 t=FDSDoSound(fdso);
274 t+=t>>1;
275 fdso->gapu->WaveHi[x]+=t;
276 }
277 fdso->FBC=fdso->gapu->X->timestamp;
278 }
279
HQSync(void * private,int32 ts)280 static void HQSync(void *private, int32 ts)
281 {
282 FDSSOUND *fdso=private;
283 fdso->FBC=ts;
284 }
285
Kill(void * private)286 static void Kill(void *private)
287 {
288 free(private);
289 }
290
Disable(void * private,int mask)291 static void Disable(void *private, int mask)
292 {
293 FDSSOUND *fdso=private;
294
295 fdso->disabled=mask;
296 }
297
298
NSFFDS_Init(EXPSOUND * ep,NESAPU * apu)299 int NSFFDS_Init(EXPSOUND *ep, NESAPU *apu)
300 {
301 FDSSOUND *fdso;
302
303 fdso=malloc(sizeof(FDSSOUND));
304 memset(fdso,0,sizeof(FDSSOUND));
305 fdso->cycles=(int64)1<<39;
306 fdso->gapu=apu;
307
308 SetReadHandler(apu->X,0x4040,0x407f,FDSWaveRead,fdso);
309 SetWriteHandler(apu->X,0x4040,0x407f,FDSWaveWrite,fdso);
310 SetWriteHandler(apu->X,0x4080,0x408A,FDSSWrite,fdso);
311 SetReadHandler(apu->X,0x4090,0x4092,FDSSRead,fdso);
312
313 ep->HiSync=HQSync;
314 ep->HiFill=RenderSoundHQ;
315 ep->Disable=Disable;
316 ep->private=fdso;
317 ep->Channels = 1;
318 ep->Kill = Kill;
319
320 return(1);
321 }
322
323