1 #include "burnint.h"
2 #include "burn_y8950.h"
3 
4 // Timer Related
5 
6 #define MAX_TIMER_VALUE ((1 << 30) - 65536)
7 
8 static double dTimeY8950;									// Time elapsed since the emulated machine was started
9 
10 static INT32 nTimerCount[2], nTimerStart[2];
11 
12 // Callbacks
13 static INT32 (*pTimerOverCallback)(INT32, INT32);
14 static double (*pTimerTimeCallback)();
15 
16 static INT32 nCPUClockspeed = 0;
17 static INT32 (*pCPUTotalCycles)() = NULL;
18 static INT32 (*pCPURun)(INT32) = NULL;
19 static void (*pCPURunEnd)() = NULL;
20 
21 // ---------------------------------------------------------------------------
22 // Running time
23 
BurnTimerTimeCallbackDummy()24 static double BurnTimerTimeCallbackDummy()
25 {
26 	return 0.0;
27 }
28 
BurnTimerGetTimeY8950()29 extern "C" double BurnTimerGetTimeY8950()
30 {
31 	return dTimeY8950 + pTimerTimeCallback();
32 }
33 
34 // ---------------------------------------------------------------------------
35 // Update timers
36 
37 static INT32 nTicksTotal, nTicksDone, nTicksExtra;
38 
BurnTimerUpdateY8950(INT32 nCycles)39 INT32 BurnTimerUpdateY8950(INT32 nCycles)
40 {
41 	INT32 nIRQStatus = 0;
42 
43 	nTicksTotal = MAKE_TIMER_TICKS(nCycles, nCPUClockspeed);
44 
45 	while (nTicksDone < nTicksTotal) {
46 		INT32 nTimer, nCyclesSegment, nTicksSegment;
47 
48 		// Determine which timer fires first
49 		if (nTimerCount[0] <= nTimerCount[1]) {
50 			nTicksSegment = nTimerCount[0];
51 		} else {
52 			nTicksSegment = nTimerCount[1];
53 		}
54 		if (nTicksSegment > nTicksTotal) {
55 			nTicksSegment = nTicksTotal;
56 		}
57 
58 		nCyclesSegment = MAKE_CPU_CYLES(nTicksSegment + nTicksExtra, nCPUClockspeed);
59 
60 		pCPURun(nCyclesSegment - pCPUTotalCycles());
61 
62 		nTicksDone = MAKE_TIMER_TICKS(pCPUTotalCycles() + 1, nCPUClockspeed) - 1;
63 
64 		nTimer = 0;
65 		if (nTicksDone >= nTimerCount[0]) {
66 			if (nTimerStart[0] == MAX_TIMER_VALUE) {
67 				nTimerCount[0] = MAX_TIMER_VALUE;
68 			} else {
69 				nTimerCount[0] += nTimerStart[0];
70 			}
71 			nTimer |= 1;
72 		}
73 		if (nTicksDone >= nTimerCount[1]) {
74 			if (nTimerStart[1] == MAX_TIMER_VALUE) {
75 				nTimerCount[1] = MAX_TIMER_VALUE;
76 			} else {
77 				nTimerCount[1] += nTimerStart[1];
78 			}
79 			nTimer |= 2;
80 		}
81 		if (nTimer & 1) {
82 			nIRQStatus |= pTimerOverCallback(0, 0);
83 		}
84 		if (nTimer & 2) {
85 			nIRQStatus |= pTimerOverCallback(0, 1);
86 		}
87 	}
88 
89 	return nIRQStatus;
90 }
91 
BurnTimerEndFrameY8950(INT32 nCycles)92 void BurnTimerEndFrameY8950(INT32 nCycles)
93 {
94 	INT32 nTicks = MAKE_TIMER_TICKS(nCycles, nCPUClockspeed);
95 
96 	BurnTimerUpdateY8950(nCycles);
97 
98 	if (nTimerCount[0] < MAX_TIMER_VALUE) {
99 		nTimerCount[0] -= nTicks;
100 	}
101 	if (nTimerCount[1] < MAX_TIMER_VALUE) {
102 		nTimerCount[1] -= nTicks;
103 	}
104 
105 	nTicksDone -= nTicks;
106 	if (nTicksDone < 0) {
107 		nTicksDone = 0;
108 	}
109 }
110 
BurnTimerUpdateEndY8950()111 void BurnTimerUpdateEndY8950()
112 {
113 	pCPURunEnd();
114 
115 	nTicksTotal = 0;
116 }
117 
BurnOPLTimerCallbackY8950(INT32 c,double period)118 void BurnOPLTimerCallbackY8950(INT32 c, double period)
119 {
120 	pCPURunEnd();
121 
122 	if (period == 0.0) {
123 		nTimerCount[c] = MAX_TIMER_VALUE;
124 		return;
125 	}
126 
127 	nTimerCount[c]  = (INT32)(period * (double)TIMER_TICKS_PER_SECOND);
128 	nTimerCount[c] += MAKE_TIMER_TICKS(pCPUTotalCycles(), nCPUClockspeed);
129 }
130 
BurnTimerScanY8950(INT32 nAction,INT32 * pnMin)131 void BurnTimerScanY8950(INT32 nAction, INT32* pnMin)
132 {
133 	if (pnMin && *pnMin < 0x029521) {
134 		*pnMin = 0x029521;
135 	}
136 
137 	if (nAction & ACB_DRIVER_DATA) {
138 		SCAN_VAR(nTimerCount);
139 		SCAN_VAR(nTimerStart);
140 		SCAN_VAR(dTimeY8950);
141 
142 		SCAN_VAR(nTicksDone);
143 	}
144 }
145 
BurnTimerExitY8950()146 void BurnTimerExitY8950()
147 {
148 	nCPUClockspeed = 0;
149 	pCPUTotalCycles = NULL;
150 	pCPURun = NULL;
151 	pCPURunEnd = NULL;
152 
153 	return;
154 }
155 
BurnTimerResetY8950()156 void BurnTimerResetY8950()
157 {
158 	nTimerCount[0] = nTimerCount[1] = MAX_TIMER_VALUE;
159 	nTimerStart[0] = nTimerStart[1] = MAX_TIMER_VALUE;
160 
161 	dTimeY8950 = 0.0;
162 
163 	nTicksDone = 0;
164 }
165 
BurnTimerInitY8950(INT32 (* pOverCallback)(INT32,INT32),double (* pTimeCallback)())166 INT32 BurnTimerInitY8950(INT32 (*pOverCallback)(INT32, INT32), double (*pTimeCallback)())
167 {
168 	BurnTimerExitY8950();
169 
170 	pTimerOverCallback = pOverCallback;
171 	pTimerTimeCallback = pTimeCallback ? pTimeCallback : BurnTimerTimeCallbackDummy;
172 
173 	BurnTimerResetY8950();
174 
175 	return 0;
176 }
177 
178 
BurnTimerAttachY8950(cpu_core_config * ptr,INT32 nClockspeed)179 INT32 BurnTimerAttachY8950(cpu_core_config *ptr, INT32 nClockspeed)
180 {
181 	nCPUClockspeed = nClockspeed;
182 	pCPUTotalCycles = ptr->totalcycles;
183 	pCPURun = ptr->run;
184 	pCPURunEnd = ptr->runend;
185 
186 	nTicksExtra = MAKE_TIMER_TICKS(1, nCPUClockspeed) - 1;
187 
188 //	bprintf(PRINT_NORMAL, _T("--- timer cpu speed %iHz, one cycle = %i ticks.\n"), nClockspeed, MAKE_TIMER_TICKS(1, BurnTimerCPUClockspeed));
189 
190 	return 0;
191 }
192 
193 // Sound Related
194 
195 #define MAX_Y8950	2
196 
197 void (*BurnY8950Update)(INT16* pSoundBuf, INT32 nSegmentEnd);
198 
199 static INT32 (*BurnY8950StreamCallback)(INT32 nSoundRate);
200 
201 static INT32 nBurnY8950SoundRate;
202 
203 static INT16* pBuffer;
204 static INT16* pY8950Buffer[MAX_Y8950];
205 
206 static INT32 nY8950Position;
207 
208 static UINT32 nSampleSize;
209 static INT32 nFractionalPosition;
210 
211 static INT32 nNumChips = 0;
212 
213 static INT32 bY8950AddSignal;
214 
215 static double Y8950Volumes[1 * MAX_Y8950];
216 static INT32 Y8950RouteDirs[1 * MAX_Y8950];
217 
218 // ----------------------------------------------------------------------------
219 // Dummy functions
220 
Y8950UpdateDummy(INT16 *,INT32)221 static void Y8950UpdateDummy(INT16* , INT32)
222 {
223 	return;
224 }
225 
Y8950StreamCallbackDummy(INT32)226 static int Y8950StreamCallbackDummy(INT32)
227 {
228 	return 0;
229 }
230 
231 // ----------------------------------------------------------------------------
232 // Execute Y8950 for part of a frame
233 
Y8950Render(INT32 nSegmentLength)234 static void Y8950Render(INT32 nSegmentLength)
235 {
236 #if defined FBA_DEBUG
237 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("Y8950Render called without init\n"));
238 #endif
239 
240 	if (nY8950Position >= nSegmentLength) {
241 		return;
242 	}
243 
244 	nSegmentLength -= nY8950Position;
245 
246 	Y8950UpdateOne(0, pBuffer + 0 * 4096 + 4 + nY8950Position, nSegmentLength);
247 
248 	if (nNumChips > 1) {
249 		Y8950UpdateOne(1, pBuffer + 1 * 4096 + 4 + nY8950Position, nSegmentLength);
250 	}
251 
252 	nY8950Position += nSegmentLength;
253 }
254 
255 // ----------------------------------------------------------------------------
256 // Update the sound buffer
257 
Y8950UpdateResample(INT16 * pSoundBuf,INT32 nSegmentEnd)258 static void Y8950UpdateResample(INT16* pSoundBuf, INT32 nSegmentEnd)
259 {
260 #if defined FBA_DEBUG
261 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("Y8950UpdateResample called without init\n"));
262 #endif
263 
264 	INT32 nSegmentLength = nSegmentEnd;
265 	INT32 nSamplesNeeded = nSegmentEnd * nBurnY8950SoundRate / nBurnSoundRate + 1;
266 
267 
268 	if (nSamplesNeeded < nY8950Position) {
269 		nSamplesNeeded = nY8950Position;
270 	}
271 
272 	if (nSegmentLength > nBurnSoundLen) {
273 		nSegmentLength = nBurnSoundLen;
274 	}
275 	nSegmentLength <<= 1;
276 
277 	Y8950Render(nSamplesNeeded);
278 
279 	pY8950Buffer[0] = pBuffer + 0 * 4096 + 4;
280 
281 	if (nNumChips > 1) {
282 		pY8950Buffer[1] = pBuffer + 1 * 4096 + 4;
283 	}
284 
285 	for (INT32 i = (nFractionalPosition & 0xFFFF0000) >> 15; i < nSegmentLength; i += 2, nFractionalPosition += nSampleSize) {
286 		INT32 nLeftSample[4] = {0, 0, 0, 0};
287 		INT32 nRightSample[4] = {0, 0, 0, 0};
288 		INT32 nTotalLeftSample, nTotalRightSample;
289 
290 		if ((Y8950RouteDirs[BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
291 			nLeftSample[0] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 3] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
292 			nLeftSample[1] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 2] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
293 			nLeftSample[2] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 1] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
294 			nLeftSample[3] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 0] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
295 		}
296 		if ((Y8950RouteDirs[BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
297 			nRightSample[0] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 3] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
298 			nRightSample[1] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 2] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
299 			nRightSample[2] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 1] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
300 			nRightSample[3] += (INT32)(pY8950Buffer[0][(nFractionalPosition >> 16) - 0] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
301 		}
302 
303 		if (nNumChips > 1) {
304 			if ((Y8950RouteDirs[1 + BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
305 				nLeftSample[0] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 3] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
306 				nLeftSample[1] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 2] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
307 				nLeftSample[2] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 1] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
308 				nLeftSample[3] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 0] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
309 			}
310 			if ((Y8950RouteDirs[1 + BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
311 				nRightSample[0] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 3] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
312 				nRightSample[1] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 2] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
313 				nRightSample[2] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 1] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
314 				nRightSample[3] += (INT32)(pY8950Buffer[1][(nFractionalPosition >> 16) - 0] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
315 			}
316 		}
317 
318 		nTotalLeftSample = INTERPOLATE4PS_16BIT((nFractionalPosition >> 4) & 0x0fff, nLeftSample[0], nLeftSample[1], nLeftSample[2], nLeftSample[3]);
319 		nTotalRightSample = INTERPOLATE4PS_16BIT((nFractionalPosition >> 4) & 0x0fff, nRightSample[0], nRightSample[1], nRightSample[2], nRightSample[3]);
320 
321 		nTotalLeftSample = BURN_SND_CLIP(nTotalLeftSample);
322 		nTotalRightSample = BURN_SND_CLIP(nTotalRightSample);
323 
324 		if (bY8950AddSignal) {
325 			pSoundBuf[i + 0] += nTotalLeftSample;
326 			pSoundBuf[i + 1] += nTotalRightSample;
327 		} else {
328 			pSoundBuf[i + 0] = nTotalLeftSample;
329 			pSoundBuf[i + 1] = nTotalRightSample;
330 		}
331 	}
332 
333 	if (nSegmentEnd >= nBurnSoundLen) {
334 		INT32 nExtraSamples = nSamplesNeeded - (nFractionalPosition >> 16);
335 
336 		for (INT32 i = -4; i < nExtraSamples; i++) {
337 			pY8950Buffer[0][i] = pY8950Buffer[0][(nFractionalPosition >> 16) + i];
338 
339 			if (nNumChips > 1) {
340 				pY8950Buffer[1][i] = pY8950Buffer[1][(nFractionalPosition >> 16) + i];
341 			}
342 		}
343 
344 		nFractionalPosition &= 0xFFFF;
345 
346 		nY8950Position = nExtraSamples;
347 	}
348 }
349 
Y8950UpdateNormal(INT16 * pSoundBuf,INT32 nSegmentEnd)350 static void Y8950UpdateNormal(INT16* pSoundBuf, INT32 nSegmentEnd)
351 {
352 #if defined FBA_DEBUG
353 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("Y8950UpdateNormal called without init\n"));
354 #endif
355 
356 	INT32 nSegmentLength = nSegmentEnd;
357 
358 	if (nSegmentEnd < nY8950Position) {
359 		nSegmentEnd = nY8950Position;
360 	}
361 
362 	if (nSegmentLength > nBurnSoundLen) {
363 		nSegmentLength = nBurnSoundLen;
364 	}
365 
366 	Y8950Render(nSegmentEnd);
367 
368 	pY8950Buffer[0] = pBuffer + 4 + 0 * 4096;
369 
370 	if (nNumChips > 1) {
371 		pY8950Buffer[1] = pBuffer + 4 + 1 * 4096;
372 	}
373 
374 	for (INT32 n = nFractionalPosition; n < nSegmentLength; n++) {
375 		INT32 nLeftSample = 0, nRightSample = 0;
376 
377 		if ((Y8950RouteDirs[BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
378 			nLeftSample += (INT32)(pY8950Buffer[0][n] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
379 		}
380 		if ((Y8950RouteDirs[BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
381 			nRightSample += (INT32)(pY8950Buffer[0][n] * Y8950Volumes[BURN_SND_Y8950_ROUTE]);
382 		}
383 
384 		if (nNumChips > 1) {
385 			if ((Y8950RouteDirs[1 + BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
386 				nLeftSample += (INT32)(pY8950Buffer[1][n] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
387 			}
388 			if ((Y8950RouteDirs[1 + BURN_SND_Y8950_ROUTE] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
389 				nRightSample += (INT32)(pY8950Buffer[1][n] * Y8950Volumes[1 + BURN_SND_Y8950_ROUTE]);
390 			}
391 		}
392 
393 		nLeftSample = BURN_SND_CLIP(nLeftSample);
394 		nRightSample = BURN_SND_CLIP(nRightSample);
395 
396 		if (bY8950AddSignal) {
397 			pSoundBuf[(n << 1) + 0] += nLeftSample;
398 			pSoundBuf[(n << 1) + 1] += nRightSample;
399 		} else {
400 			pSoundBuf[(n << 1) + 0] = nLeftSample;
401 			pSoundBuf[(n << 1) + 1] = nRightSample;
402 		}
403 	}
404 
405 	nFractionalPosition = nSegmentLength;
406 
407 	if (nSegmentEnd >= nBurnSoundLen) {
408 		INT32 nExtraSamples = nSegmentEnd - nBurnSoundLen;
409 
410 		for (INT32 i = 0; i < nExtraSamples; i++) {
411 			pY8950Buffer[i] = pY8950Buffer[nBurnSoundLen + i];
412 		}
413 
414 		nFractionalPosition = 0;
415 
416 		nY8950Position = nExtraSamples;
417 
418 	}
419 }
420 
421 // ----------------------------------------------------------------------------
422 // Callbacks for Y8950 core
423 
BurnY8950UpdateRequest(INT32,INT32)424 void BurnY8950UpdateRequest(INT32, INT32)
425 {
426 #if defined FBA_DEBUG
427 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("BurnY8950UpdateRequest called without init\n"));
428 #endif
429 
430 	Y8950Render(BurnY8950StreamCallback(nBurnY8950SoundRate));
431 }
432 
433 // ----------------------------------------------------------------------------
434 // Initialisation, etc.
435 
BurnY8950Reset()436 void BurnY8950Reset()
437 {
438 #if defined FBA_DEBUG
439 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("BurnY8950Reset called without init\n"));
440 #endif
441 
442 	BurnTimerResetY8950();
443 
444 	for (INT32 i = 0; i < nNumChips; i++) {
445 		Y8950ResetChip(i);
446 	}
447 }
448 
BurnY8950Exit()449 void BurnY8950Exit()
450 {
451 #if defined FBA_DEBUG
452 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("BurnY8950Exit called without init\n"));
453 #endif
454 
455 	// Crash prevention.
456 	if (!DebugSnd_Y8950Initted) return;
457 
458 	Y8950Shutdown();
459 
460 	BurnTimerExitY8950();
461 
462 	BurnFree(pBuffer);
463 
464 	nNumChips = 0;
465 	bY8950AddSignal = 0;
466 
467 	DebugSnd_Y8950Initted = 0;
468 }
469 
BurnY8950Init(INT32 num,INT32 nClockFrequency,UINT8 * Y8950ADPCM0ROM,INT32 nY8950ADPCM0Size,UINT8 * Y8950ADPCM1ROM,INT32 nY8950ADPCM1Size,OPL_IRQHANDLER IRQCallback,INT32 (* StreamCallback)(INT32),INT32 bAddSignal)470 INT32 BurnY8950Init(INT32 num, INT32 nClockFrequency, UINT8* Y8950ADPCM0ROM, INT32 nY8950ADPCM0Size, UINT8* Y8950ADPCM1ROM, INT32 nY8950ADPCM1Size, OPL_IRQHANDLER IRQCallback, INT32 (*StreamCallback)(INT32), INT32 bAddSignal)
471 {
472 	BurnTimerInitY8950(&Y8950TimerOver, NULL);
473 
474 	if (nBurnSoundRate <= 0) {
475 		BurnY8950StreamCallback = Y8950StreamCallbackDummy;
476 
477 		BurnY8950Update = Y8950UpdateDummy;
478 
479 		Y8950Init(num, nClockFrequency, 11025);
480 		return 0;
481 	}
482 
483 	BurnY8950StreamCallback = StreamCallback;
484 
485 	if (nFMInterpolation == 3) {
486 		// Set Y8950 core samplerate to match the hardware
487 		nBurnY8950SoundRate = nClockFrequency / 72;
488 		// Bring Y8950 core samplerate within usable range
489 		while (nBurnY8950SoundRate > nBurnSoundRate * 3) {
490 			nBurnY8950SoundRate >>= 1;
491 		}
492 
493 		BurnY8950Update = Y8950UpdateResample;
494 
495 		nSampleSize = (UINT32)nBurnY8950SoundRate * (1 << 16) / nBurnSoundRate;
496 		nFractionalPosition = 0;
497 	} else {
498 		nBurnY8950SoundRate = nBurnSoundRate;
499 
500 		BurnY8950Update = Y8950UpdateNormal;
501 	}
502 
503 	Y8950Init(num, nClockFrequency, nBurnY8950SoundRate);
504 	Y8950SetIRQHandler(0, IRQCallback, 0);
505 	Y8950SetTimerHandler(0, &BurnOPLTimerCallbackY8950, 0);
506 	Y8950SetUpdateHandler(0, &BurnY8950UpdateRequest, 0);
507 	Y8950SetDeltaTMemory(0, Y8950ADPCM0ROM, nY8950ADPCM0Size);
508 	if (num > 1) {
509 //		Y8950SetIRQHandler(1, IRQCallback, 0); // ??
510 		Y8950SetTimerHandler(1, &BurnOPLTimerCallbackY8950, 0);
511 		Y8950SetUpdateHandler(1, &BurnY8950UpdateRequest, 0);
512 		Y8950SetDeltaTMemory(1, Y8950ADPCM1ROM, nY8950ADPCM1Size);
513 	}
514 
515 	pBuffer = (INT16*)BurnMalloc(4096 * num * sizeof(INT16));
516 	memset(pBuffer, 0, 4096 * num * sizeof(INT16));
517 
518 	nY8950Position = 0;
519 
520 	nFractionalPosition = 0;
521 
522 	nNumChips = num;
523 	bY8950AddSignal = bAddSignal;
524 
525 	// default routes
526 	Y8950Volumes[BURN_SND_Y8950_ROUTE] = 1.00;
527 	Y8950RouteDirs[BURN_SND_Y8950_ROUTE] = BURN_SND_ROUTE_BOTH;
528 	if (nNumChips > 1) {
529 		Y8950Volumes[1 + BURN_SND_Y8950_ROUTE] = 1.00;
530 		Y8950RouteDirs[1 + BURN_SND_Y8950_ROUTE] = BURN_SND_ROUTE_BOTH;
531 	}
532 
533 	DebugSnd_Y8950Initted = 1;
534 
535 	return 0;
536 }
537 
BurnY8950SetRoute(INT32 nChip,INT32 nIndex,double nVolume,INT32 nRouteDir)538 void BurnY8950SetRoute(INT32 nChip, INT32 nIndex, double nVolume, INT32 nRouteDir)
539 {
540 #if defined FBA_DEBUG
541 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("BurnY8950SetRoute called without init\n"));
542 	if (nIndex < 0 || nIndex > 1) bprintf(PRINT_ERROR, _T("BurnY8950SetRoute called with invalid index %i\n"), nIndex);
543 	if (nChip >= nNumChips) bprintf(PRINT_ERROR, _T("BurnY8950SetRoute called with invalid chip %i\n"), nChip);
544 #endif
545 
546 	if (nChip == 0) {
547 		Y8950Volumes[nIndex] = nVolume;
548 		Y8950RouteDirs[nIndex] = nRouteDir;
549 	}
550 
551 	if (nChip == 1) {
552 		Y8950Volumes[1 + nIndex] = nVolume;
553 		Y8950RouteDirs[1 + nIndex] = nRouteDir;
554 	}
555 }
556 
BurnY8950Scan(INT32 nAction,INT32 * pnMin)557 void BurnY8950Scan(INT32 nAction, INT32* pnMin)
558 {
559 	#if defined FBA_DEBUG
560 	if (!DebugSnd_Y8950Initted) bprintf(PRINT_ERROR, _T("BurnY8950Scan called without init\n"));
561 #endif
562 
563 	BurnTimerScanY8950(nAction, pnMin);
564 	FMOPLScan(FM_OPL_SAVESTATE_Y8950, 0, nAction, pnMin);
565 
566 	if (nAction & ACB_DRIVER_DATA) {
567 		SCAN_VAR(nY8950Position);
568 	}
569 }
570 
571 #undef MAX_Y8950
572