1 #include "burnint.h"
2 #include "burn_ym2608.h"
3 
4 void (*BurnYM2608Update)(INT16* pSoundBuf, INT32 nSegmentEnd);
5 
6 static INT32 (*BurnYM2608StreamCallback)(INT32 nSoundRate);
7 
8 static INT32 nBurnYM2608SoundRate;
9 
10 static INT16* pBuffer;
11 static INT16* pYM2608Buffer[6];
12 
13 static INT32* pAYBuffer;
14 
15 static INT32 nYM2608Position;
16 static INT32 nAY8910Position;
17 
18 static UINT32 nSampleSize;
19 static INT32 nFractionalPosition;
20 
21 static INT32 bYM2608AddSignal;
22 
23 static double YM2608Volumes[3];
24 static INT32 YM2608RouteDirs[3];
25 
26 // ----------------------------------------------------------------------------
27 // Dummy functions
28 
YM2608UpdateDummy(INT16 *,INT32)29 static void YM2608UpdateDummy(INT16*, INT32)
30 {
31 	return;
32 }
33 
YM2608StreamCallbackDummy(INT32)34 static INT32 YM2608StreamCallbackDummy(INT32)
35 {
36 	return 0;
37 }
38 
39 // ----------------------------------------------------------------------------
40 // Execute YM2608 for part of a frame
41 
AY8910Render(INT32 nSegmentLength)42 static void AY8910Render(INT32 nSegmentLength)
43 {
44 #if defined FBNEO_DEBUG
45 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("BurnYM2608 AY8910Render called without init\n"));
46 #endif
47 
48 	if (nAY8910Position >= nSegmentLength || !pBurnSoundOut) {
49 		return;
50 	}
51 
52 	nSegmentLength -= nAY8910Position;
53 
54 	pYM2608Buffer[2] = pBuffer + 2 * 4096 + 4 + nAY8910Position;
55 	pYM2608Buffer[3] = pBuffer + 3 * 4096 + 4 + nAY8910Position;
56 	pYM2608Buffer[4] = pBuffer + 4 * 4096 + 4 + nAY8910Position;
57 
58 	AY8910Update(0, &pYM2608Buffer[2], nSegmentLength);
59 
60 	nAY8910Position += nSegmentLength;
61 }
62 
YM2608Render(INT32 nSegmentLength)63 static void YM2608Render(INT32 nSegmentLength)
64 {
65 #if defined FBNEO_DEBUG
66 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("YM2608Render called without init\n"));
67 #endif
68 
69 	if (nYM2608Position >= nSegmentLength || !pBurnSoundOut) {
70 		return;
71 	}
72 
73 	nSegmentLength -= nYM2608Position;
74 
75 	pYM2608Buffer[0] = pBuffer + 0 * 4096 + 4 + nYM2608Position;
76 	pYM2608Buffer[1] = pBuffer + 1 * 4096 + 4 + nYM2608Position;
77 
78 	YM2608UpdateOne(0, &pYM2608Buffer[0], nSegmentLength);
79 
80 	nYM2608Position += nSegmentLength;
81 }
82 
83 // ----------------------------------------------------------------------------
84 // Update the sound buffer
85 
YM2608UpdateResample(INT16 * pSoundBuf,INT32 nSegmentEnd)86 static void YM2608UpdateResample(INT16* pSoundBuf, INT32 nSegmentEnd)
87 {
88 #if defined FBNEO_DEBUG
89 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("YM2608UpdateResample called without init\n"));
90 #endif
91 
92 	if (!pBurnSoundOut) return;
93 
94 	INT32 nSegmentLength = nSegmentEnd;
95 	INT32 nSamplesNeeded = nSegmentEnd * nBurnYM2608SoundRate / nBurnSoundRate + 1;
96 
97 	if (nSamplesNeeded < nAY8910Position) {
98 		nSamplesNeeded = nAY8910Position;
99 	}
100 	if (nSamplesNeeded < nYM2608Position) {
101 		nSamplesNeeded = nYM2608Position;
102 	}
103 
104 	if (nSegmentLength > nBurnSoundLen) {
105 		nSegmentLength = nBurnSoundLen;
106 	}
107 	nSegmentLength <<= 1;
108 
109 	YM2608Render(nSamplesNeeded);
110 	AY8910Render(nSamplesNeeded);
111 
112 	pYM2608Buffer[0] = pBuffer + 0 * 4096 + 4;
113 	pYM2608Buffer[1] = pBuffer + 1 * 4096 + 4;
114 	pYM2608Buffer[2] = pBuffer + 2 * 4096 + 4;
115 	pYM2608Buffer[3] = pBuffer + 3 * 4096 + 4;
116 	pYM2608Buffer[4] = pBuffer + 4 * 4096 + 4;
117 	pYM2608Buffer[5] = pBuffer + 5 * 4096 + 4;
118 
119 	for (INT32 i = (nFractionalPosition >> 16) - 4; i < nSamplesNeeded; i++) {
120 		pYM2608Buffer[5][i] = (INT32)((pYM2608Buffer[2][i] + pYM2608Buffer[3][i] + pYM2608Buffer[4][i]) * YM2608Volumes[BURN_SND_YM2608_AY8910_ROUTE]);
121 	}
122 
123 	for (INT32 i = (nFractionalPosition & 0xFFFF0000) >> 15; i < nSegmentLength; i += 2, nFractionalPosition += nSampleSize) {
124 		INT32 nLeftSample[4] = {0, 0, 0, 0};
125 		INT32 nRightSample[4] = {0, 0, 0, 0};
126 		INT32 nTotalLeftSample, nTotalRightSample;
127 
128 		if ((YM2608RouteDirs[BURN_SND_YM2608_AY8910_ROUTE] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
129 			nLeftSample[0] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 3];
130 			nLeftSample[1] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 2];
131 			nLeftSample[2] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 1];
132 			nLeftSample[3] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 0];
133 		}
134 		if ((YM2608RouteDirs[BURN_SND_YM2608_AY8910_ROUTE] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
135 			nRightSample[0] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 3];
136 			nRightSample[1] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 2];
137 			nRightSample[2] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 1];
138 			nRightSample[3] += pYM2608Buffer[5][(nFractionalPosition >> 16) - 0];
139 		}
140 
141 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_1] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
142 			nLeftSample[0] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 3] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
143 			nLeftSample[1] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 2] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
144 			nLeftSample[2] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 1] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
145 			nLeftSample[3] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 0] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
146 		}
147 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_1] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
148 			nRightSample[0] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 3] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
149 			nRightSample[1] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 2] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
150 			nRightSample[2] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 1] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
151 			nRightSample[3] += (INT32)(pYM2608Buffer[0][(nFractionalPosition >> 16) - 0] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
152 		}
153 
154 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_2] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
155 			nLeftSample[0] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 3] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
156 			nLeftSample[1] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 2] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
157 			nLeftSample[2] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 1] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
158 			nLeftSample[3] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 0] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
159 		}
160 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_2] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
161 			nRightSample[0] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 3] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
162 			nRightSample[1] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 2] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
163 			nRightSample[2] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 1] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
164 			nRightSample[3] += (INT32)(pYM2608Buffer[1][(nFractionalPosition >> 16) - 0] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
165 		}
166 
167 		nTotalLeftSample = INTERPOLATE4PS_16BIT((nFractionalPosition >> 4) & 0x0fff, nLeftSample[0], nLeftSample[1], nLeftSample[2], nLeftSample[3]);
168 		nTotalRightSample = INTERPOLATE4PS_16BIT((nFractionalPosition >> 4) & 0x0fff, nRightSample[0], nRightSample[1], nRightSample[2], nRightSample[3]);
169 
170 		nTotalLeftSample = BURN_SND_CLIP(nTotalLeftSample);
171 		nTotalRightSample = BURN_SND_CLIP(nTotalRightSample);
172 
173 		if (bYM2608AddSignal) {
174 			pSoundBuf[i + 0] += nTotalLeftSample;
175 			pSoundBuf[i + 1] += nTotalRightSample;
176 		} else {
177 			pSoundBuf[i + 0] = nTotalLeftSample;
178 			pSoundBuf[i + 1] = nTotalRightSample;
179 		}
180 	}
181 
182 	if (nSegmentEnd >= nBurnSoundLen) {
183 		INT32 nExtraSamples = nSamplesNeeded - (nFractionalPosition >> 16);
184 
185 		for (INT32 i = -4; i < nExtraSamples; i++) {
186 			pYM2608Buffer[0][i] = pYM2608Buffer[0][(nFractionalPosition >> 16) + i];
187 			pYM2608Buffer[1][i] = pYM2608Buffer[1][(nFractionalPosition >> 16) + i];
188 			pYM2608Buffer[2][i] = pYM2608Buffer[2][(nFractionalPosition >> 16) + i];
189 			pYM2608Buffer[3][i] = pYM2608Buffer[3][(nFractionalPosition >> 16) + i];
190 			pYM2608Buffer[4][i] = pYM2608Buffer[4][(nFractionalPosition >> 16) + i];
191 		}
192 
193 		nFractionalPosition &= 0xFFFF;
194 
195 		nYM2608Position = nExtraSamples;
196 		nAY8910Position = nExtraSamples;
197 
198 		dTime += 100.0 / nBurnFPS;
199 	}
200 }
201 
YM2608UpdateNormal(INT16 * pSoundBuf,INT32 nSegmentEnd)202 static void YM2608UpdateNormal(INT16* pSoundBuf, INT32 nSegmentEnd)
203 {
204 #if defined FBNEO_DEBUG
205 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("YM2608UpdateNormal called without init\n"));
206 #endif
207 
208 	if (!pBurnSoundOut) return;
209 
210 	INT32 nSegmentLength = nSegmentEnd;
211 
212 	if (nSegmentEnd < nAY8910Position) {
213 		nSegmentEnd = nAY8910Position;
214 	}
215 	if (nSegmentEnd < nYM2608Position) {
216 		nSegmentEnd = nYM2608Position;
217 	}
218 
219 	if (nSegmentLength > nBurnSoundLen) {
220 		nSegmentLength = nBurnSoundLen;
221 	}
222 
223 	YM2608Render(nSegmentEnd);
224 	AY8910Render(nSegmentEnd);
225 
226 	pYM2608Buffer[0] = pBuffer + 4 + 0 * 4096;
227 	pYM2608Buffer[1] = pBuffer + 4 + 1 * 4096;
228 	pYM2608Buffer[2] = pBuffer + 4 + 2 * 4096;
229 	pYM2608Buffer[3] = pBuffer + 4 + 3 * 4096;
230 	pYM2608Buffer[4] = pBuffer + 4 + 4 * 4096;
231 
232 	for (INT32 n = nFractionalPosition; n < nSegmentLength; n++) {
233 		INT32 nAYSample, nLeftSample = 0, nRightSample = 0;
234 
235 		nAYSample  = pYM2608Buffer[2][n];
236 		nAYSample += pYM2608Buffer[3][n];
237 		nAYSample += pYM2608Buffer[4][n];
238 
239 		if ((YM2608RouteDirs[BURN_SND_YM2608_AY8910_ROUTE] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
240 			nLeftSample += (INT32)(nAYSample * YM2608Volumes[BURN_SND_YM2608_AY8910_ROUTE]);
241 		}
242 		if ((YM2608RouteDirs[BURN_SND_YM2608_AY8910_ROUTE] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
243 			nRightSample += (INT32)(nAYSample * YM2608Volumes[BURN_SND_YM2608_AY8910_ROUTE]);
244 		}
245 
246 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_1] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
247 			nLeftSample += (INT32)(pYM2608Buffer[0][n] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
248 		}
249 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_1] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
250 			nRightSample += (INT32)(pYM2608Buffer[0][n] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1]);
251 		}
252 
253 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_2] & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
254 			nLeftSample += (INT32)(pYM2608Buffer[1][n] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
255 		}
256 		if ((YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_2] & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
257 			nRightSample += (INT32)(pYM2608Buffer[1][n] * YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2]);
258 		}
259 
260 		nLeftSample = BURN_SND_CLIP(nLeftSample);
261 		nRightSample = BURN_SND_CLIP(nRightSample);
262 
263 		if (bYM2608AddSignal) {
264 			pSoundBuf[(n << 1) + 0] += nLeftSample;
265 			pSoundBuf[(n << 1) + 1] += nRightSample;
266 		} else {
267 			pSoundBuf[(n << 1) + 0] = nLeftSample;
268 			pSoundBuf[(n << 1) + 1] = nRightSample;
269 		}
270 	}
271 
272 	nFractionalPosition = nSegmentLength;
273 
274 	if (nSegmentEnd >= nBurnSoundLen) {
275 		INT32 nExtraSamples = nSegmentEnd - nBurnSoundLen;
276 
277 		for (INT32 i = 0; i < nExtraSamples; i++) {
278 			pYM2608Buffer[0][i] = pYM2608Buffer[0][nBurnSoundLen + i];
279 			pYM2608Buffer[1][i] = pYM2608Buffer[1][nBurnSoundLen + i];
280 			pYM2608Buffer[2][i] = pYM2608Buffer[2][nBurnSoundLen + i];
281 			pYM2608Buffer[3][i] = pYM2608Buffer[3][nBurnSoundLen + i];
282 			pYM2608Buffer[4][i] = pYM2608Buffer[4][nBurnSoundLen + i];
283 		}
284 
285 		nFractionalPosition = 0;
286 
287 		nYM2608Position = nExtraSamples;
288 		nAY8910Position = nExtraSamples;
289 
290 		dTime += 100.0 / nBurnFPS;
291 	}
292 }
293 
294 // ----------------------------------------------------------------------------
295 // Callbacks for YM2608 core
296 
BurnYM2608UpdateRequest()297 void BurnYM2608UpdateRequest()
298 {
299 #if defined FBNEO_DEBUG
300 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("BurnYM2608UpdateRequest called without init\n"));
301 #endif
302 
303 	YM2608Render(BurnYM2608StreamCallback(nBurnYM2608SoundRate));
304 }
305 
BurnAY8910UpdateRequest()306 static void BurnAY8910UpdateRequest()
307 {
308 #if defined FBNEO_DEBUG
309 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("BurnYM2608 BurnAY8910UpdateRequest called without init\n"));
310 #endif
311 
312 	AY8910Render(BurnYM2608StreamCallback(nBurnYM2608SoundRate));
313 }
314 
315 // ----------------------------------------------------------------------------
316 // Initialisation, etc.
317 
BurnYM2608Reset()318 void BurnYM2608Reset()
319 {
320 #if defined FBNEO_DEBUG
321 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("BurnYM2608Reset called without init\n"));
322 #endif
323 
324 	BurnTimerReset();
325 
326 	YM2608ResetChip(0);
327 }
328 
BurnYM2608Exit()329 void BurnYM2608Exit()
330 {
331 #if defined FBNEO_DEBUG
332 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("BurnYM2608Exit called without init\n"));
333 #endif
334 
335 	if (!DebugSnd_YM2608Initted) return;
336 
337 	YM2608Shutdown();
338 	AY8910Exit(0);
339 
340 	BurnTimerExit();
341 
342 	BurnFree(pBuffer);
343 	BurnFree(pAYBuffer);
344 
345 	bYM2608AddSignal = 0;
346 
347 	DebugSnd_YM2608Initted = 0;
348 }
349 
BurnYM2608Init(INT32 nClockFrequency,UINT8 * YM2608ADPCMROM,INT32 * nYM2608ADPCMSize,UINT8 * YM2608IROM,FM_IRQHANDLER IRQCallback,INT32 bAddSignal)350 INT32 BurnYM2608Init(INT32 nClockFrequency, UINT8* YM2608ADPCMROM, INT32* nYM2608ADPCMSize, UINT8* YM2608IROM, FM_IRQHANDLER IRQCallback, INT32 bAddSignal)
351 {
352 	return BurnYM2608Init(nClockFrequency, YM2608ADPCMROM, nYM2608ADPCMSize, YM2608IROM, IRQCallback, BurnSynchroniseStream, BurnGetTime, bAddSignal);
353 }
354 
BurnYM2608Init(INT32 nClockFrequency,UINT8 * YM2608ADPCMROM,INT32 * nYM2608ADPCMSize,UINT8 * YM2608IROM,FM_IRQHANDLER IRQCallback,INT32 (* StreamCallback)(INT32),double (* GetTimeCallback)(),INT32 bAddSignal)355 INT32 BurnYM2608Init(INT32 nClockFrequency, UINT8* YM2608ADPCMROM, INT32* nYM2608ADPCMSize, UINT8* YM2608IROM, FM_IRQHANDLER IRQCallback, INT32 (*StreamCallback)(INT32), double (*GetTimeCallback)(), INT32 bAddSignal)
356 {
357 	DebugSnd_YM2608Initted = 1;
358 
359 	BurnTimerInit(&YM2608TimerOver, GetTimeCallback);
360 
361 	if (nBurnSoundRate <= 0) {
362 		BurnYM2608StreamCallback = YM2608StreamCallbackDummy;
363 
364 		BurnYM2608Update = YM2608UpdateDummy;
365 
366 		AY8910InitYM(0, nClockFrequency, 11025, NULL, NULL, NULL, NULL, BurnAY8910UpdateRequest);
367 		YM2608Init(1, nClockFrequency, 11025, (void**)(&YM2608ADPCMROM), nYM2608ADPCMSize, YM2608IROM, &BurnOPNTimerCallback, IRQCallback);
368 		return 0;
369 	}
370 
371 	BurnYM2608StreamCallback = StreamCallback;
372 
373 	if (nFMInterpolation == 3) {
374 		// Set YM2608 core samplerate to match the hardware
375 		nBurnYM2608SoundRate = nClockFrequency / 144;
376 		// Bring YM2608 core samplerate within usable range
377 		while (nBurnYM2608SoundRate > nBurnSoundRate * 3) {
378 			nBurnYM2608SoundRate >>= 1;
379 		}
380 
381 		BurnYM2608Update = YM2608UpdateResample;
382 
383 		nSampleSize = (UINT32)nBurnYM2608SoundRate * (1 << 16) / nBurnSoundRate;
384 		nFractionalPosition = 0;
385 	} else {
386 		nBurnYM2608SoundRate = nBurnSoundRate;
387 
388 		BurnYM2608Update = YM2608UpdateNormal;
389 	}
390 
391 	AY8910InitYM(0, nClockFrequency, nBurnYM2608SoundRate, NULL, NULL, NULL, NULL, BurnAY8910UpdateRequest);
392 	YM2608Init(1, nClockFrequency, nBurnYM2608SoundRate, (void**)(&YM2608ADPCMROM), nYM2608ADPCMSize, YM2608IROM, &BurnOPNTimerCallback, IRQCallback);
393 
394 	pBuffer = (INT16*)BurnMalloc(4096 * 6 * sizeof(INT16));
395 	memset(pBuffer, 0, 4096 * 6 * sizeof(INT16));
396 
397 	pAYBuffer = (INT32*)BurnMalloc(4096 * sizeof(INT32));
398 	memset(pAYBuffer, 0, 4096 * sizeof(INT32));
399 
400 	nYM2608Position = 0;
401 	nAY8910Position = 0;
402 
403 	bYM2608AddSignal = bAddSignal;
404 
405 	// default routes
406 	YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_1] = 1.00;
407 	YM2608Volumes[BURN_SND_YM2608_YM2608_ROUTE_2] = 1.00;
408 	YM2608Volumes[BURN_SND_YM2608_AY8910_ROUTE] = 1.00;
409 	YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_1] = BURN_SND_ROUTE_LEFT;
410 	YM2608RouteDirs[BURN_SND_YM2608_YM2608_ROUTE_2] = BURN_SND_ROUTE_RIGHT;
411 	YM2608RouteDirs[BURN_SND_YM2608_AY8910_ROUTE] = BURN_SND_ROUTE_BOTH;
412 
413 	return 0;
414 }
415 
BurnYM2608SetRoute(INT32 nIndex,double nVolume,INT32 nRouteDir)416 void BurnYM2608SetRoute(INT32 nIndex, double nVolume, INT32 nRouteDir)
417 {
418 #if defined FBNEO_DEBUG
419 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("BurnYM2608SetRoute called without init\n"));
420 	if (nIndex < 0 || nIndex > 2) bprintf(PRINT_ERROR, _T("BurnYM2608SetRoute called with invalid index %i\n"), nIndex);
421 #endif
422 
423 	YM2608Volumes[nIndex] = nVolume;
424 	YM2608RouteDirs[nIndex] = nRouteDir;
425 }
426 
BurnYM2608Scan(INT32 nAction,INT32 * pnMin)427 void BurnYM2608Scan(INT32 nAction, INT32* pnMin)
428 {
429 #if defined FBNEO_DEBUG
430 	if (!DebugSnd_YM2608Initted) bprintf(PRINT_ERROR, _T("BurnYM2608Scan called without init\n"));
431 #endif
432 
433 	BurnTimerScan(nAction, pnMin);
434 	AY8910Scan(nAction, pnMin);
435 
436 	if (nAction & ACB_DRIVER_DATA) {
437 		SCAN_VAR(nYM2608Position);
438 		SCAN_VAR(nAY8910Position);
439 	}
440 }
441