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