1 /*********************************************************
2
3 Irem GA20 PCM Sound Chip
4
5 Based on MAME sources by Acho A. Tang,R. Belmont
6
7 It's not currently known whether this chip is stereo.
8
9
10 Revisions:
11
12 04-15-2002 Acho A. Tang
13 - rewrote channel mixing
14 - added prelimenary volume and sample rate emulation
15
16 05-30-2002 Acho A. Tang
17 - applied hyperbolic gain control to volume and used
18 a musical-note style progression in sample rate
19 calculation(still very inaccurate)
20
21 02-18-2004 R. Belmont
22 - sample rate calculation reverse-engineered.
23 Thanks to Fujix, Yasuhiro Ogawa, the Guru, and Tormod
24 for real PCB samples that made this possible.
25
26 02-03-2007 R. Belmont
27 - Cleaned up faux x86 assembly.
28
29 *********************************************************/
30
31 #include "burnint.h"
32 #include "iremga20.h"
33
34 #define MAX_GA20 1
35 #define MAX_VOL 256
36
37 struct IremGA20_channel_def
38 {
39 UINT32 rate;
40 UINT32 size;
41 UINT32 start;
42 UINT32 pos;
43 UINT32 frac;
44 UINT32 end;
45 UINT32 volume;
46 UINT32 pan;
47 UINT32 effect;
48 UINT32 play;
49 };
50
51 typedef struct _ga20_state ga20_state;
52 struct _ga20_state
53 {
54 UINT8 *rom;
55 INT32 rom_size;
56 UINT16 regs[0x40];
57 struct IremGA20_channel_def channel[4];
58 INT32 frequency;
59 double gain;
60 INT32 output_dir;
61 };
62
63 static struct _ga20_state chips[MAX_GA20];
64 static struct _ga20_state *chip;
65
66 static UINT32 computed_steps;
67
68 // 14318180/4 -> 3579545/4 -> 894886/60 -> 14915
69 // 44100 / 60 -> 735
70
71 static INT32 nNumChips;
72
iremga20_update(INT32 device,INT16 * buffer,INT32 length)73 void iremga20_update(INT32 device, INT16 *buffer, INT32 length)
74 {
75 #if defined FBNEO_DEBUG
76 if (!DebugSnd_IremGA20Initted) bprintf(PRINT_ERROR, _T("iremga20_update called without init\n"));
77 if (device > nNumChips) bprintf(PRINT_ERROR, _T("iremga20_update called with invalid chip %x\n"), device);
78 #endif
79
80 chip = &chips[device];
81 UINT32 rate[4], pos[4], frac[4], end[4], vol[4], play[4];
82 UINT8 *pSamples;
83 INT32 i, sampleout;
84
85 /* precache some values */
86 for (i=0; i < 4; i++)
87 {
88 rate[i] = chip->channel[i].rate;
89 pos[i] = chip->channel[i].pos;
90 frac[i] = chip->channel[i].frac;
91 end[i] = chip->channel[i].end - 0x20;
92 vol[i] = chip->channel[i].volume;
93 play[i] = chip->channel[i].play;
94 }
95
96 pSamples = chip->rom;
97
98 for (i = 0; i < length; i++, buffer+=2)
99 {
100 sampleout = 0;
101
102 // update the 4 channels inline
103 if (play[0])
104 {
105 sampleout += (pSamples[pos[0]] - 0x80) * vol[0];
106 frac[0] += rate[0] * computed_steps;
107 pos[0] += frac[0] >> 24;
108 frac[0] &= 0xffffff;
109 play[0] = (pos[0] < end[0]);
110 }
111 if (play[1])
112 {
113 sampleout += (pSamples[pos[1]] - 0x80) * vol[1];
114 frac[1] += rate[1] * computed_steps;
115 pos[1] += frac[1] >> 24;
116 frac[1] &= 0xffffff;
117 play[1] = (pos[1] < end[1]);
118 }
119 if (play[2])
120 {
121 sampleout += (pSamples[pos[2]] - 0x80) * vol[2];
122 frac[2] += rate[2] * computed_steps;
123 pos[2] += frac[2] >> 24;
124 frac[2] &= 0xffffff;
125 play[2] = (pos[2] < end[2]);
126 }
127 if (play[3])
128 {
129 sampleout += (pSamples[pos[3]] - 0x80) * vol[3];
130 frac[3] += rate[3] * computed_steps;
131 pos[3] += frac[3] >> 24;
132 frac[3] &= 0xffffff;
133 play[3] = (pos[3] < end[3]);
134 }
135
136 sampleout >>= 2;
137
138 INT32 nLeftSample = 0, nRightSample = 0;
139
140 if ((chip->output_dir & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
141 nLeftSample += (INT32)(sampleout * chip->gain);
142 }
143 if ((chip->output_dir & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
144 nRightSample += (INT32)(sampleout * chip->gain);
145 }
146
147 nLeftSample = BURN_SND_CLIP(nLeftSample);
148 nRightSample = BURN_SND_CLIP(nRightSample);
149
150 buffer[0] = BURN_SND_CLIP(buffer[0] + nLeftSample);
151 buffer[1] = BURN_SND_CLIP(buffer[1] + nRightSample);
152 }
153
154 /* update the regs now */
155 for (i=0; i < 4; i++)
156 {
157 chip->channel[i].pos = pos[i];
158 chip->channel[i].frac = frac[i];
159 chip->channel[i].play = play[i];
160 }
161 }
162
iremga20_write(INT32 device,INT32 offset,INT32 data)163 void iremga20_write(INT32 device, INT32 offset, INT32 data)
164 {
165 #if defined FBNEO_DEBUG
166 if (!DebugSnd_IremGA20Initted) bprintf(PRINT_ERROR, _T("iremga20_write called without init\n"));
167 if (device > nNumChips) bprintf(PRINT_ERROR, _T("iremga20_write called with invalid chip %x\n"), device);
168 #endif
169
170 chip = &chips[device];
171
172 INT32 channel = offset >> 3;
173
174 chip->regs[offset] = data;
175
176 switch (offset & 0x7)
177 {
178 case 0: /* start address low */
179 chip->channel[channel].start = ((chip->channel[channel].start)&0xff000) | (data<<4);
180 break;
181
182 case 1: /* start address high */
183 chip->channel[channel].start = ((chip->channel[channel].start)&0x00ff0) | (data<<12);
184 break;
185
186 case 2: /* end address low */
187 chip->channel[channel].end = ((chip->channel[channel].end)&0xff000) | (data<<4);
188 break;
189
190 case 3: /* end address high */
191 chip->channel[channel].end = ((chip->channel[channel].end)&0x00ff0) | (data<<12);
192 break;
193
194 case 4:
195 chip->channel[channel].rate = 0x1000000 / (256 - data);
196 break;
197
198 case 5: //AT: gain control
199 chip->channel[channel].volume = (data * MAX_VOL) / (data + 10);
200 break;
201
202 case 6: //AT: this is always written 2(enabling both channels?)
203 chip->channel[channel].play = data;
204 chip->channel[channel].pos = chip->channel[channel].start;
205 chip->channel[channel].frac = 0;
206 break;
207 }
208 }
209
iremga20_read(INT32 device,INT32 offset)210 UINT8 iremga20_read(INT32 device, INT32 offset)
211 {
212 #if defined FBNEO_DEBUG
213 if (!DebugSnd_IremGA20Initted) bprintf(PRINT_ERROR, _T("iremga20_read called without init\n"));
214 if (device > nNumChips) bprintf(PRINT_ERROR, _T("iremga20_read called with invalid chip %x\n"), device);
215 #endif
216
217 chip = &chips[device];
218
219 switch (offset & 0x7)
220 {
221 case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo)
222 return chip->channel[offset >> 3].play ? 1 : 0;
223
224 default:
225 break;
226 }
227
228 return 0;
229 }
230
iremga20_reset(INT32 device)231 void iremga20_reset(INT32 device)
232 {
233 #if defined FBNEO_DEBUG
234 if (!DebugSnd_IremGA20Initted) bprintf(PRINT_ERROR, _T("iremga20_reset called without init\n"));
235 if (device > nNumChips) bprintf(PRINT_ERROR, _T("iremga20_reset called with invalid chip %x\n"), device);
236 #endif
237
238 chip = &chips[device];
239
240 for(INT32 i = 0; i < 4; i++ ) {
241 chip->channel[i].rate = 0;
242 chip->channel[i].size = 0;
243 chip->channel[i].start = 0;
244 chip->channel[i].pos = 0;
245 chip->channel[i].frac = 0;
246 chip->channel[i].end = 0;
247 chip->channel[i].volume = 0;
248 chip->channel[i].pan = 0;
249 chip->channel[i].effect = 0;
250 chip->channel[i].play = 0;
251 }
252
253 for ( INT32 i = 0; i < 0x40; i++ )
254 chip->regs[i] = 0;
255 }
256
iremga20_init(INT32 device,UINT8 * rom,INT32 rom_size,INT32 frequency)257 void iremga20_init(INT32 device, UINT8 *rom, INT32 rom_size, INT32 frequency)
258 {
259 DebugSnd_IremGA20Initted = 1;
260
261 chip = &chips[device];
262
263 /* Initialize our chip structure */
264 chip->rom = rom;
265 chip->rom_size = rom_size;
266 chip->frequency = (frequency / 4) / 60;
267
268 chip->gain = 1.00;
269 chip->output_dir = BURN_SND_ROUTE_BOTH;
270
271 iremga20_reset(device);
272
273 computed_steps = (UINT32)((float)(chip->frequency / (1.00000 * nBurnSoundLen)));
274
275 nNumChips = device;
276 }
277
itemga20_set_route(INT32 device,double nVolume,INT32 nRouteDir)278 void itemga20_set_route(INT32 device, double nVolume, INT32 nRouteDir)
279 {
280 #if defined FBNEO_DEBUG
281 if (!DebugSnd_IremGA20Initted) bprintf(PRINT_ERROR, _T("itemga20_set_route called without init\n"));
282 if (device > nNumChips) bprintf(PRINT_ERROR, _T("itemga20_set_route called with invalid chip %x\n"), device);
283 #endif
284
285 chip = &chips[device];
286
287 chip->gain = nVolume;
288 chip->output_dir = nRouteDir;
289 }
290
iremga20_exit()291 void iremga20_exit()
292 {
293 #if defined FBNEO_DEBUG
294 if (!DebugSnd_IremGA20Initted) bprintf(PRINT_ERROR, _T("iremga20_exit called without init\n"));
295 #endif
296
297 DebugSnd_IremGA20Initted = 0;
298 nNumChips = 0;
299 }
300
iremga20_scan(INT32 nAction,INT32 * pnMin)301 void iremga20_scan(INT32 nAction, INT32 *pnMin)
302 {
303 #if defined FBNEO_DEBUG
304 if (!DebugSnd_IremGA20Initted) bprintf(PRINT_ERROR, _T("iremga20_scan called without init\n"));
305 #endif
306
307 if (pnMin != NULL) {
308 *pnMin = 0x029678;
309 }
310
311 if (nAction & ACB_DRIVER_DATA)
312 {
313 for (INT32 i = 0; i < MAX_GA20; i++)
314 {
315 chip = &chips[i];
316 SCAN_VAR(chip->channel);
317 SCAN_VAR(chip->regs);
318 }
319 }
320 }
321