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