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