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