1 /**********************************************************************************************
2  *
3  *  Streaming singe channel ADPCM core for the ES8712 chip
4  *  Chip is branded by Excellent Systems, probably OEM'd.
5  *
6  *  Samples are currently looped, but whether they should and how, is unknown.
7  *  Interface to the chip is also not 100% clear.
8  *  Should there be any status signals signifying busy, end of sample - etc?
9  *
10  *  Heavily borrowed from the OKI M6295 source
11  *
12  *  Excellent Systems ADPCM Emulation
13  *  Copyright Nicola Salmoria and the MAME Team
14  *
15  *  From MAME 0.139u1. Modified for use in FBA Aug 23, 2010.
16  *
17  **********************************************************************************************/
18 
19 #include "burnint.h"
20 #include "math.h"
21 #include "es8712.h"
22 
23 #define MAX_ES8712_CHIPS	1
24 
25 #define MAX_SAMPLE_CHUNK	10000
26 
27 /* struct describing a playing ADPCM chip */
28 typedef struct _es8712_state es8712_state;
29 struct _es8712_state
30 {
31 	UINT8 playing;			/* 1 if we're actively playing */
32 
33 	UINT32 base_offset;		/* pointer to the base memory location */
34 	UINT32 sample;			/* current sample number */
35 	UINT32 count;			/* total samples to play */
36 
37 	UINT32 signal;			/* current ADPCM signal */
38 	UINT32 step;			/* current ADPCM step */
39 
40 	UINT32 start;			/* starting address for the next loop */
41 	UINT32 end;				/* ending address for the next loop */
42 	UINT8  repeat;			/* Repeat current sample when 1 */
43 
44 	INT32 bank_offset;
45 
46 // non volatile
47 	UINT8 *region_base;		/* pointer to the base of the region */
48 
49 	INT32 sample_rate;		/* samples per frame */
50 	double volume;			/* set gain */
51 	INT32 output_dir;
52 	INT32 addSignal;			/* add signal to stream? */
53 };
54 
55 static INT16 *tbuf[MAX_ES8712_CHIPS] = { NULL };
56 
57 static _es8712_state chips[MAX_ES8712_CHIPS];
58 static _es8712_state *chip;
59 
60 static const INT32 index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
61 static INT32 diff_lookup[49*16];
62 
63 /**********************************************************************************************
64 
65      compute_tables -- compute the difference tables
66 
67 ***********************************************************************************************/
68 
compute_tables()69 static void compute_tables()
70 {
71 	/* nibble to bit map */
72 	static const INT32 nbl2bit[16][4] =
73 	{
74 		{ 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1},
75 		{ 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1},
76 		{-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1},
77 		{-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1}
78 	};
79 
80 	INT32 step, nib;
81 
82 	/* loop over all possible steps */
83 	for (step = 0; step <= 48; step++)
84 	{
85 		/* compute the step value */
86 		INT32 stepval = (INT32)(floor(16.0 * pow(11.0 / 10.0, (double)step)));
87 
88 		/* loop over all nibbles and compute the difference */
89 		for (nib = 0; nib < 16; nib++)
90 		{
91 			diff_lookup[step*16 + nib] = nbl2bit[nib][0] *
92 				(stepval   * nbl2bit[nib][1] +
93 				 stepval/2 * nbl2bit[nib][2] +
94 				 stepval/4 * nbl2bit[nib][3] +
95 				 stepval/8);
96 		}
97 	}
98 }
99 
100 
101 /**********************************************************************************************
102 
103     generate_adpcm -- general ADPCM decoding routine
104 
105 ***********************************************************************************************/
106 
generate_adpcm(INT16 * buffer,INT32 samples)107 static void generate_adpcm(INT16 *buffer, INT32 samples)
108 {
109 	/* if this chip is active */
110 	if (chip->playing)
111 	{
112 		UINT8 *base = chip->region_base + chip->bank_offset + chip->base_offset;
113 		INT32 sample = chip->sample;
114 		INT32 signal = chip->signal;
115 		INT32 count = chip->count;
116 		INT32 step = chip->step;
117 		double volume = chip->volume;
118 		INT32 val;
119 
120 		/* loop while we still have samples to generate */
121 		while (samples)
122 		{
123 			/* compute the new amplitude and update the current step */
124 			val = base[sample / 2] >> (((sample & 1) << 2) ^ 4);
125 			signal += diff_lookup[step * 16 + (val & 15)];
126 
127 			/* clamp to the maximum */
128 			if (signal > 2047)
129 				signal = 2047;
130 			else if (signal < -2048)
131 				signal = -2048;
132 
133 			/* adjust the step size and clamp */
134 			step += index_shift[val & 7];
135 			if (step > 48)
136 				step = 48;
137 			else if (step < 0)
138 				step = 0;
139 
140 			/* output to the buffer */
141 			*buffer++ = (INT32)(signal * 16 * volume);
142 			samples--;
143 
144 			/* next! */
145 			if (++sample >= count)
146 			{
147 				if (chip->repeat)
148 				{
149 					sample = 0;
150 					signal = -2;
151 					step = 0;
152 				}
153 				else
154 				{
155 					chip->playing = 0;
156 					break;
157 				}
158 			}
159 		}
160 
161 		/* update the parameters */
162 		chip->sample = sample;
163 		chip->signal = signal;
164 		chip->step = step;
165 	}
166 
167 	/* fill the rest with silence */
168 	while (samples--)
169 		*buffer++ = 0;
170 }
171 
172 
173 /**********************************************************************************************
174 
175     es8712Update -- update the sound chip so that it is in sync with CPU execution
176 
177 ***********************************************************************************************/
178 
es8712Update(INT32 device,INT16 * buffer,INT32 samples)179 void es8712Update(INT32 device, INT16 *buffer, INT32 samples)
180 {
181 #if defined FBA_DEBUG
182 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712Update called without init\n"));
183 #endif
184 
185 	if (device >= MAX_ES8712_CHIPS) return;
186 
187 	chip = &chips[device];
188 
189 	INT32 sample_num = (INT32)((float)(((samples / nBurnSoundLen) * 1.0000) * chip->sample_rate));
190 
191 	float step = ((chip->sample_rate * 1.00000) / nBurnSoundLen);
192 
193 	INT16 *buf = tbuf[device];
194 
195 	generate_adpcm(buf, sample_num);
196 
197 	float r = 0;
198 	for (INT32 i = 0; i < samples; i++, r += step, buffer+=2) {
199 		INT32 nLeftSample = 0, nRightSample = 0;
200 
201 		if ((chip->output_dir & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
202 			nLeftSample += (INT32)(buf[(INT32)r] * chip->volume);
203 		}
204 		if ((chip->output_dir & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
205 			nRightSample += (INT32)(buf[(INT32)r] * chip->volume);
206 		}
207 
208 		nLeftSample = BURN_SND_CLIP(nLeftSample);
209 		nRightSample = BURN_SND_CLIP(nRightSample);
210 
211 		if (chip->addSignal) {
212 			buffer[0] += nLeftSample;
213 			buffer[1] += nRightSample;
214 		} else {
215 			buffer[0] = nLeftSample;
216 			buffer[1] = nRightSample;
217 		}
218 	}
219 
220 }
221 
222 
223 /**********************************************************************************************
224 
225     es8712Init -- start emulation of an ES8712 chip
226 
227 ***********************************************************************************************/
228 
es8712Init(INT32 device,UINT8 * rom,INT32 sample_rate,INT32 addSignal)229 void es8712Init(INT32 device, UINT8 *rom, INT32 sample_rate, INT32 addSignal)
230 {
231 	DebugSnd_ES8712Initted = 1;
232 
233 	if (device >= MAX_ES8712_CHIPS) return;
234 
235 	chip = &chips[device];
236 
237 	compute_tables();
238 
239 	chip->start = 0;
240 	chip->end = 0;
241 	chip->repeat = 0;
242 
243 	chip->bank_offset = 0;
244 	chip->region_base = (UINT8*)rom;
245 
246 	/* initialize the rest of the structure */
247 	chip->signal = (UINT32)-2;
248 
249 	chip->sample_rate = sample_rate;
250 
251 	chip->volume = 1.00;
252 	chip->output_dir = BURN_SND_ROUTE_BOTH;
253 	chip->addSignal = addSignal;
254 
255 	if (tbuf[device] == NULL) {
256 		tbuf[device] = (INT16*)BurnMalloc(sample_rate * sizeof(INT16));
257 	}
258 }
259 
es8712SetRoute(INT32 device,double nVolume,INT32 nRouteDir)260 void es8712SetRoute(INT32 device, double nVolume, INT32 nRouteDir)
261 {
262 #if defined FBA_DEBUG
263 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712SetRoute called without init\n"));
264 #endif
265 
266 	if (device >= MAX_ES8712_CHIPS) return;
267 
268 	chip = &chips[device];
269 	chip->volume = nVolume;
270 	chip->output_dir = nRouteDir;
271 }
272 
273 /**********************************************************************************************
274 
275     es8712Exit -- stop emulation of an ES8712 chip
276 
277 ***********************************************************************************************/
278 
es8712Exit(INT32 device)279 void es8712Exit(INT32 device)
280 {
281 #if defined FBA_DEBUG
282 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712Exit called without init\n"));
283 #endif
284 
285 	if (!DebugSnd_ES8712Initted) return;
286 
287 	if (device >= MAX_ES8712_CHIPS) return;
288 
289 	chip = &chips[device];
290 
291 	memset (chip, 0, sizeof(_es8712_state));
292 
293 	BurnFree (tbuf[device]);
294 
295 	DebugSnd_ES8712Initted = 0;
296 }
297 
298 /*************************************************************************************
299 
300      es8712Reset -- stop emulation of an ES8712-compatible chip
301 
302 **************************************************************************************/
303 
es8712Reset(INT32 device)304 void es8712Reset(INT32 device)
305 {
306 #if defined FBA_DEBUG
307 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712Reset called without init\n"));
308 #endif
309 
310 	if (device >= MAX_ES8712_CHIPS) return;
311 
312 	chip = &chips[device];
313 
314 	if (chip->playing)
315 	{
316 		/* update the stream, then turn it off */
317 		chip->playing = 0;
318 		chip->repeat = 0;
319 	}
320 }
321 
322 
323 /****************************************************************************
324 
325     es8712_set_bank_base -- set the base of the bank on a given chip
326 
327 *****************************************************************************/
328 
es8712SetBankBase(INT32 device,INT32 base)329 void es8712SetBankBase(INT32 device, INT32 base)
330 {
331 #if defined FBA_DEBUG
332 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712SetBankBase called without init\n"));
333 #endif
334 
335 	if (device >= MAX_ES8712_CHIPS) return;
336 
337 	chip = &chips[device];
338 
339 	chip->bank_offset = base;
340 }
341 
342 
343 /**********************************************************************************************
344 
345     es8712Play -- Begin playing the addressed sample
346 
347 ***********************************************************************************************/
348 
es8712Play(INT32 device)349 void es8712Play(INT32 device)
350 {
351 #if defined FBA_DEBUG
352 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712Play called without init\n"));
353 #endif
354 
355 	if (device >= MAX_ES8712_CHIPS) return;
356 
357 	chip = &chips[device];
358 
359 	if (chip->start < chip->end)
360 	{
361 		if (!chip->playing)
362 		{
363 			chip->playing = 1;
364 			chip->base_offset = chip->start;
365 			chip->sample = 0;
366 			chip->count = 2 * (chip->end - chip->start + 1);
367 			chip->repeat = 0;//1;
368 
369 			/* also reset the ADPCM parameters */
370 			chip->signal = (UINT32)-2;
371 			chip->step = 0;
372 		}
373 	}
374 	/* invalid samples go here */
375 	else
376 	{
377 		if (chip->playing)
378 		{
379 			/* update the stream */
380 			chip->playing = 0;
381 		}
382 	}
383 }
384 
385 
386 /**********************************************************************************************
387 
388      es8712Write -- generic data write function
389 
390 ***********************************************************************************************/
391 
392 /**********************************************************************************************
393  *
394  *  offset  Start       End
395  *          0hmmll  -  0HMMLL
396  *    00    ----ll
397  *    01    --mm--
398  *    02    0h----
399  *    03               ----LL
400  *    04               --MM--
401  *    05               0H----
402  *    06           Go!
403  *
404  * Offsets are written in the order -> 00, 02, 01, 03, 05, 04, 06
405  * Offset 06 is written with the same value as offset 04.
406  *
407 ***********************************************************************************************/
408 
es8712Write(INT32 device,INT32 offset,UINT8 data)409 void es8712Write(INT32 device, INT32 offset, UINT8 data)
410 {
411 #if defined FBA_DEBUG
412 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712Write called without init\n"));
413 #endif
414 
415 	if (device >= MAX_ES8712_CHIPS) return;
416 
417 	chip = &chips[device];
418 
419 	switch (offset)
420 	{
421 		case 00:	chip->start &= 0x000fff00;
422 					chip->start |= ((data & 0xff) <<  0); break;
423 		case 01:	chip->start &= 0x000f00ff;
424 					chip->start |= ((data & 0xff) <<  8); break;
425 		case 02:	chip->start &= 0x0000ffff;
426 					chip->start |= ((data & 0x0f) << 16); break;
427 		case 03:	chip->end   &= 0x000fff00;
428 					chip->end   |= ((data & 0xff) <<  0); break;
429 		case 04:	chip->end   &= 0x000f00ff;
430 					chip->end   |= ((data & 0xff) <<  8); break;
431 		case 05:	chip->end   &= 0x0000ffff;
432 					chip->end   |= ((data & 0x0f) << 16); break;
433 		case 06:
434 				es8712Play(device);
435 				break;
436 		default:	break;
437 	}
438 
439 	chip->start &= 0xfffff;
440 	chip->end &= 0xfffff;
441 }
442 
443 
444 /**********************************************************************************************
445 
446      es8712Scan -- save state function
447 
448 ***********************************************************************************************/
449 
es8712Scan(INT32 nAction,INT32 *)450 void es8712Scan(INT32 nAction, INT32 *)
451 {
452 #if defined FBA_DEBUG
453 	if (!DebugSnd_ES8712Initted) bprintf(PRINT_ERROR, _T("es8712Scan called without init\n"));
454 #endif
455 
456 	if (nAction & ACB_DRIVER_DATA)
457 	{
458 		for (INT32 i = 0; i < MAX_ES8712_CHIPS; i++)
459 		{
460 			chip = &chips[i];
461 
462 			SCAN_VAR(chip->playing);
463 			SCAN_VAR(chip->base_offset);
464 			SCAN_VAR(chip->sample);
465 			SCAN_VAR(chip->count);
466 			SCAN_VAR(chip->signal);
467 			SCAN_VAR(chip->step);
468 			SCAN_VAR(chip->start);
469 			SCAN_VAR(chip->end);
470 			SCAN_VAR(chip->repeat);
471 			SCAN_VAR(chip->bank_offset);
472 		}
473 	}
474 }
475