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 "common.h"
20
21 typedef struct {
22 uint16 wl[2];
23 uint8 env[2];
24 uint8 enable;
25 uint8 running;
26 uint8 raw;
27 uint8 rawcontrol;
28 uint8 mul[2];
29
30 uint8 ExRAM[1024];
31
32 int32 dcount[2];
33
34 int32 BC[3];
35 int32 vcount[2];
36
37 int disabled;
38 NESAPU *gapu;
39 } MMC5APU;
40
41 static void Do5SQHQ(MMC5APU *, int P);
42 static void MMC5RunSoundHQ(void *);
43
DECLFW(Mapper5_write)44 static DECLFW(Mapper5_write)
45 {
46 MMC5APU *MMC5Sound=private;
47 switch(A)
48 {
49 case 0x5205:MMC5Sound->mul[0]=V;break;
50 case 0x5206:MMC5Sound->mul[1]=V;break;
51 }
52 }
53
DECLFW(MMC5_ExRAMWr)54 static DECLFW(MMC5_ExRAMWr)
55 {
56 MMC5APU *MMC5Sound=private;
57
58 MMC5Sound->ExRAM[A&0x3ff]=V;
59 }
60
DECLFR(MMC5_ExRAMRd)61 static DECLFR(MMC5_ExRAMRd)
62 {
63 MMC5APU *MMC5Sound=private;
64
65 return MMC5Sound->ExRAM[A&0x3ff];
66 }
67
DECLFR(MMC5_read)68 static DECLFR(MMC5_read)
69 {
70 MMC5APU *MMC5Sound=private;
71 switch(A)
72 {
73 case 0x5205:return (MMC5Sound->mul[0]*MMC5Sound->mul[1]);
74 case 0x5206:return ((MMC5Sound->mul[0]*MMC5Sound->mul[1])>>8);
75 }
76 return(DB);
77 }
78
Do5PCMHQ(MMC5APU * MMC5Sound)79 static void Do5PCMHQ(MMC5APU *MMC5Sound)
80 {
81 int32 V;
82 if(!(MMC5Sound->rawcontrol&0x40) && MMC5Sound->raw && !(MMC5Sound->disabled&0x4))
83 for(V=MMC5Sound->BC[2];V<MMC5Sound->gapu->X->timestamp;V++)
84 MMC5Sound->gapu->WaveHi[V]+=MMC5Sound->raw<<5;
85 MMC5Sound->BC[2]=MMC5Sound->gapu->X->timestamp;
86 }
87
88
DECLFW(Mapper5_SW)89 static DECLFW(Mapper5_SW)
90 {
91 MMC5APU *MMC5Sound=private;
92
93 A&=0x1F;
94
95 switch(A)
96 {
97 case 0x10:Do5PCMHQ(MMC5Sound);MMC5Sound->rawcontrol=V;break;
98 case 0x11:Do5PCMHQ(MMC5Sound);MMC5Sound->raw=V;break;
99
100 case 0x0:
101 case 0x4:
102 Do5SQHQ(MMC5Sound,A>>2);
103 MMC5Sound->env[A>>2]=V;
104 break;
105 case 0x2:
106 case 0x6:Do5SQHQ(MMC5Sound,A>>2);
107 MMC5Sound->wl[A>>2]&=~0x00FF;
108 MMC5Sound->wl[A>>2]|=V&0xFF;
109 break;
110 case 0x3:
111 case 0x7://printf("%04x:$%02x\n",A,V>>3);
112 MMC5Sound->wl[A>>2]&=~0x0700;
113 MMC5Sound->wl[A>>2]|=(V&0x07)<<8;
114 MMC5Sound->running|=1<<(A>>2);
115 break;
116 case 0x15:
117 Do5SQHQ(MMC5Sound,0);
118 Do5SQHQ(MMC5Sound,1);
119 MMC5Sound->running&=V;
120 MMC5Sound->enable=V;
121 break;
122 }
123 }
124
Do5SQHQ(MMC5APU * MMC5Sound,int P)125 static void Do5SQHQ(MMC5APU *MMC5Sound, int P)
126 {
127 static const int tal[4]={1,2,4,6};
128 int32 V,amp,rthresh,wl;
129
130 wl=MMC5Sound->wl[P]+1;
131 amp=((MMC5Sound->env[P]&0xF)<<8);
132 rthresh=tal[(MMC5Sound->env[P]&0xC0)>>6];
133
134 if(wl>=8 && (MMC5Sound->running&(P+1)) && !(MMC5Sound->disabled&(0x1<<P)))
135 {
136 int dc,vc;
137 int32 curout;
138 wl<<=1;
139
140 dc=MMC5Sound->dcount[P];
141 vc=MMC5Sound->vcount[P];
142
143 curout = 0;
144 if(dc<rthresh) curout = amp;
145
146 for(V=MMC5Sound->BC[P];V<MMC5Sound->gapu->X->timestamp;V++)
147 {
148 MMC5Sound->gapu->WaveHi[V]+=curout;
149 //if(dc<rthresh)
150 // MMC5Sound->gapu->WaveHi[V]+=amp;
151 vc--;
152 if(vc<=0) /* Less than zero when first started. */
153 {
154 vc=wl;
155 dc=(dc+1)&7;
156 curout = 0;
157 if(dc<rthresh) curout = amp;
158 }
159 }
160 MMC5Sound->dcount[P]=dc;
161 MMC5Sound->vcount[P]=vc;
162 }
163 MMC5Sound->BC[P]=MMC5Sound->gapu->X->timestamp;
164 }
165
MMC5RunSoundHQ(void * private)166 static void MMC5RunSoundHQ(void *private)
167 {
168 Do5SQHQ(private, 0);
169 Do5SQHQ(private, 1);
170 Do5PCMHQ(private);
171 }
172
MMC5HiSync(void * private,int32 ts)173 static void MMC5HiSync(void *private, int32 ts)
174 {
175 MMC5APU *MMC5Sound=private;
176 int x;
177 for(x=0;x<3;x++) MMC5Sound->BC[x]=ts;
178 }
179
Kill(void * private)180 static void Kill(void *private)
181 {
182 free(private);
183 }
184
Disable(void * private,int mask)185 static void Disable(void *private, int mask)
186 {
187 MMC5APU *MMC5Sound=private;
188
189 MMC5Sound->disabled=mask;
190 }
191
NSFMMC5_Init(EXPSOUND * ep,NESAPU * apu)192 int NSFMMC5_Init(EXPSOUND *ep, NESAPU *apu)
193 {
194 MMC5APU *MMC5Sound;
195
196 MMC5Sound=malloc(sizeof(MMC5APU));
197 memset(MMC5Sound,0,sizeof(MMC5APU));
198 MMC5Sound->gapu=apu;
199
200 ep->private=MMC5Sound;
201
202 ep->HiSync=MMC5HiSync;
203 ep->HiFill=MMC5RunSoundHQ;
204 ep->Kill=Kill;
205 ep->Disable=Disable;
206 ep->Channels = 3;
207
208 SetWriteHandler(apu->X,0x5c00,0x5fef,MMC5_ExRAMWr,MMC5Sound);
209 SetReadHandler(apu->X,0x5c00,0x5fef,MMC5_ExRAMRd,MMC5Sound);
210 SetWriteHandler(apu->X,0x5000,0x5015,Mapper5_SW,MMC5Sound);
211 SetWriteHandler(apu->X,0x5205,0x5206,Mapper5_write,MMC5Sound);
212 SetReadHandler(apu->X,0x5205,0x5206,MMC5_read,MMC5Sound);
213
214 return(1);
215 }
216