1 // Based on MAME driver by Nicola Salmoria
2
3 #include "burnint.h"
4 #include "sn76496.h"
5 #include <stddef.h>
6
7 #define MAX_SN76496_CHIPS 8
8
9 #define MAX_OUTPUT 0x7fff
10
11 #define STEP 0x10000
12
13 struct SN76496
14 {
15 INT32 Register[8]; /* registers */
16 INT32 LastRegister; /* last register written */
17 INT32 Volume[4]; /* volume of voice 0-2 and noise */
18 INT32 RNG; /* noise generator */
19 INT32 NoiseMode; /* active noise mode */
20 INT32 Period[4];
21 INT32 Count[4];
22 INT32 Output[4];
23 INT32 StereoMask; /* the stereo output mask */
24
25 // Init-time stuff
26 INT32 VolTable[16]; /* volume table */
27 INT32 FeedbackMask; /* mask for feedback */
28 INT32 WhitenoiseTaps; /* mask for white noise taps */
29 INT32 WhitenoiseInvert; /* white noise invert flag */
30 INT32 bSignalAdd;
31 double nVolume;
32 INT32 nOutputDir;
33 UINT32 UpdateStep;
34 };
35
36 static INT32 NumChips = 0;
37 static struct SN76496 *Chips[MAX_SN76496_CHIPS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
38
39
40 // for stream-sync
41 static INT32 sn76496_buffered = 0;
42 static INT32 (*pCPUTotalCycles)() = NULL;
43 static UINT32 nDACCPUMHZ = 0;
44 static INT32 nPosition[MAX_SN76496_CHIPS];
45 static INT16 *soundbuf[MAX_SN76496_CHIPS];
46
47 // Streambuffer handling
SyncInternal()48 static INT32 SyncInternal()
49 {
50 if (!sn76496_buffered) return 0;
51 return (INT32)(float)(nBurnSoundLen * (pCPUTotalCycles() / (nDACCPUMHZ / (nBurnFPS / 100.0000))));
52 }
53
UpdateStream(INT32 chip,INT32 samples_len)54 static void UpdateStream(INT32 chip, INT32 samples_len)
55 {
56 if (!sn76496_buffered || !pBurnSoundOut) return;
57 if (samples_len > nBurnSoundLen) samples_len = nBurnSoundLen;
58
59 INT32 nSamplesNeeded = samples_len;
60
61 nSamplesNeeded -= nPosition[chip];
62 if (nSamplesNeeded <= 0) return;
63
64 INT16 *mix = soundbuf[chip] + 5 + (nPosition[chip] * 2); // * 2 (stereo stream)
65 //memset(mix, 0, nSamplesNeeded * sizeof(INT16) * 2);
66 //bprintf(0, _T("sn76496_sync: %d samples frame %d\n"), nSamplesNeeded, nCurrentFrame);
67
68 SN76496UpdateToBuffer(chip, mix, nSamplesNeeded);
69
70 nPosition[chip] += nSamplesNeeded;
71 }
72
SN76496SetBuffered(INT32 (* pCPUCyclesCB)(),INT32 nCpuMHZ)73 void SN76496SetBuffered(INT32 (*pCPUCyclesCB)(), INT32 nCpuMHZ)
74 {
75 bprintf(0, _T("*** Using BUFFERED SN76496-mode.\n"));
76 for (INT32 i = 0; i < NumChips; i++) {
77 nPosition[i] = 0;
78 }
79
80 sn76496_buffered = 1;
81
82 pCPUTotalCycles = pCPUCyclesCB;
83 nDACCPUMHZ = nCpuMHZ;
84 }
85
SN76496Update(INT32 Num,INT16 * pSoundBuf,INT32 Length)86 void SN76496Update(INT32 Num, INT16* pSoundBuf, INT32 Length)
87 {
88 #if defined FBNEO_DEBUG
89 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496Update called without init\n"));
90 if (Num > NumChips) bprintf(PRINT_ERROR, _T("SN76496Update called with invalid chip %x\n"), Num);
91 #endif
92
93 if (Num >= MAX_SN76496_CHIPS) return;
94
95 struct SN76496 *R = Chips[Num];
96
97 if (sn76496_buffered) {
98 if (Length != nBurnSoundLen) {
99 bprintf(0, _T("SN76496Update() in buffered mode must be called once per frame!\n"));
100 return;
101 }
102 } else {
103 nPosition[Num] = 0;
104 }
105
106 INT16 *mix = soundbuf[Num] + 5 + (nPosition[Num] * 2);
107
108 SN76496UpdateToBuffer(Num, mix, Length - nPosition[Num]); // fill to end
109
110 INT16 *pBuf = soundbuf[Num] + 5;
111
112 while (Length > 0) {
113 if (R->bSignalAdd) {
114 pSoundBuf[0] = BURN_SND_CLIP(pSoundBuf[0] + pBuf[0]);
115 pSoundBuf[1] = BURN_SND_CLIP(pSoundBuf[1] + pBuf[1]);
116 } else {
117 pSoundBuf[0] = BURN_SND_CLIP(pBuf[0]);
118 pSoundBuf[1] = BURN_SND_CLIP(pBuf[1]);
119 }
120
121 pBuf += 2;
122 pSoundBuf += 2;
123 Length--;
124 }
125
126 nPosition[Num] = 0;
127 }
128
129 static INT16 dac_lastin_r = 0;
130 static INT16 dac_lastout_r = 0;
131 static INT16 dac_lastin_l = 0;
132 static INT16 dac_lastout_l = 0;
133
dc_blockR(INT16 sam)134 static INT16 dc_blockR(INT16 sam)
135 {
136 INT16 outr = sam - dac_lastin_r + 0.998 * dac_lastout_r;
137 dac_lastin_r = sam;
138 dac_lastout_r = outr;
139
140 return outr;
141 }
142
dc_blockL(INT16 sam)143 static INT16 dc_blockL(INT16 sam)
144 {
145 INT16 outl = sam - dac_lastin_l + 0.998 * dac_lastout_l;
146 dac_lastin_l = sam;
147 dac_lastout_l = outl;
148
149 return outl;
150 }
151
SN76496Update(INT16 * pSoundBuf,INT32 Length)152 void SN76496Update(INT16* pSoundBuf, INT32 Length)
153 {
154 for (INT32 i = 0; i < NumChips; i++) {
155 SN76496Update(i, pSoundBuf, Length);
156 }
157
158 for (INT32 i = 0; i < Length*2; i += 2) {
159 pSoundBuf[i + 0] = dc_blockR(pSoundBuf[i + 0]);
160 pSoundBuf[i + 1] = dc_blockL(pSoundBuf[i + 1]);
161 }
162 }
163
SN76496UpdateToBuffer(INT32 Num,INT16 * pSoundBuf,INT32 Length)164 void SN76496UpdateToBuffer(INT32 Num, INT16* pSoundBuf, INT32 Length)
165 {
166 #if defined FBNEO_DEBUG
167 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496Update called without init\n"));
168 if (Num > NumChips) bprintf(PRINT_ERROR, _T("SN76496Update called with invalid chip %x\n"), Num);
169 #endif
170
171 INT32 i;
172
173 if (Num >= MAX_SN76496_CHIPS) return;
174
175 struct SN76496 *R = Chips[Num];
176
177 while (Length > 0)
178 {
179 INT32 Vol[4];
180 UINT32 Out, Out2 = 0;
181 INT32 Left;
182
183
184 /* vol[] keeps track of how long each square wave stays */
185 /* in the 1 position during the sample period. */
186 Vol[0] = Vol[1] = Vol[2] = Vol[3] = 0;
187
188 for (i = 0;i < 3;i++)
189 {
190 if (R->Output[i]) Vol[i] += R->Count[i];
191 R->Count[i] -= STEP;
192 /* Period[i] is the half period of the square wave. Here, in each */
193 /* loop I add Period[i] twice, so that at the end of the loop the */
194 /* square wave is in the same status (0 or 1) it was at the start. */
195 /* vol[i] is also incremented by Period[i], since the wave has been 1 */
196 /* exactly half of the time, regardless of the initial position. */
197 /* If we exit the loop in the middle, Output[i] has to be inverted */
198 /* and vol[i] incremented only if the exit status of the square */
199 /* wave is 1. */
200 while (R->Count[i] <= 0)
201 {
202 R->Count[i] += R->Period[i];
203 if (R->Count[i] > 0)
204 {
205 R->Output[i] ^= 1;
206 if (R->Output[i]) Vol[i] += R->Period[i];
207 break;
208 }
209 R->Count[i] += R->Period[i];
210 Vol[i] += R->Period[i];
211 }
212 if (R->Output[i]) Vol[i] -= R->Count[i];
213 }
214
215 Left = STEP;
216 do
217 {
218 INT32 NextEvent;
219
220
221 if (R->Count[3] < Left) NextEvent = R->Count[3];
222 else NextEvent = Left;
223
224 if (R->Output[3]) Vol[3] += R->Count[3];
225 R->Count[3] -= NextEvent;
226 if (R->Count[3] <= 0)
227 {
228 if (R->NoiseMode == 1) /* White Noise Mode */
229 {
230 if (((R->RNG & R->WhitenoiseTaps) != R->WhitenoiseTaps) && ((R->RNG & R->WhitenoiseTaps) != 0)) /* crappy xor! */
231 {
232 R->RNG >>= 1;
233 R->RNG |= R->FeedbackMask;
234 }
235 else
236 {
237 R->RNG >>= 1;
238 }
239 R->Output[3] = R->WhitenoiseInvert ? !(R->RNG & 1) : R->RNG & 1;
240 }
241 else /* Periodic noise mode */
242 {
243 if (R->RNG & 1)
244 {
245 R->RNG >>= 1;
246 R->RNG |= R->FeedbackMask;
247 }
248 else
249 {
250 R->RNG >>= 1;
251 }
252 R->Output[3] = R->RNG & 1;
253 }
254 R->Count[3] += R->Period[3];
255 if (R->Output[3]) Vol[3] += R->Period[3];
256 }
257 if (R->Output[3]) Vol[3] -= R->Count[3];
258
259 Left -= NextEvent;
260 } while (Left > 0);
261
262 if (R->StereoMask != 0xFF)
263 {
264 Out = ((R->StereoMask&0x10) ? Vol[0] * R->Volume[0]:0)
265 + ((R->StereoMask&0x20) ? Vol[1] * R->Volume[1]:0)
266 + ((R->StereoMask&0x40) ? Vol[2] * R->Volume[2]:0)
267 + ((R->StereoMask&0x80) ? Vol[3] * R->Volume[3]:0);
268
269 Out2 = ((R->StereoMask&0x1) ? Vol[0] * R->Volume[0]:0)
270 + ((R->StereoMask&0x2) ? Vol[1] * R->Volume[1]:0)
271 + ((R->StereoMask&0x4) ? Vol[2] * R->Volume[2]:0)
272 + ((R->StereoMask&0x8) ? Vol[3] * R->Volume[3]:0);
273 if (Out2 > MAX_OUTPUT * STEP) Out2 = MAX_OUTPUT * STEP;
274
275 Out2 /= STEP;
276 }
277 else
278 {
279 Out = Vol[0] * R->Volume[0] + Vol[1] * R->Volume[1] +
280 Vol[2] * R->Volume[2] + Vol[3] * R->Volume[3];
281 }
282
283 if (Out > MAX_OUTPUT * STEP) Out = MAX_OUTPUT * STEP;
284
285 Out /= STEP;
286
287 INT32 nLeftSample = 0, nRightSample = 0;
288 if ((R->nOutputDir & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
289 nLeftSample += (INT32)(Out * R->nVolume);
290 }
291 if ((R->nOutputDir & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
292 if (R->StereoMask != 0xFF)
293 nRightSample += (INT32)(Out2 * R->nVolume);
294 else
295 nRightSample += (INT32)(Out * R->nVolume);
296 }
297
298 pSoundBuf[0] = BURN_SND_CLIP(nLeftSample);
299 pSoundBuf[1] = BURN_SND_CLIP(nRightSample);
300
301 pSoundBuf += 2;
302 Length--;
303 }
304 }
305
SN76496StereoWrite(INT32 Num,INT32 Data)306 void SN76496StereoWrite(INT32 Num, INT32 Data)
307 {
308 #if defined FBNEO_DEBUG
309 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496StereoWrite called without init\n"));
310 if (Num > NumChips) bprintf(PRINT_ERROR, _T("SN76496StereoWrite called with invalid chip %x\n"), Num);
311 #endif
312
313 if (Num >= MAX_SN76496_CHIPS) return;
314
315 struct SN76496 *R = Chips[Num];
316
317 R->StereoMask = Data;
318 }
319
SN76496Write(INT32 Num,INT32 Data)320 void SN76496Write(INT32 Num, INT32 Data)
321 {
322 #if defined FBNEO_DEBUG
323 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496Write called without init\n"));
324 if (Num > NumChips) bprintf(PRINT_ERROR, _T("SN76496Write called with invalid chip %x\n"), Num);
325 #endif
326
327 INT32 n, r, c;
328
329 if (Num >= MAX_SN76496_CHIPS) return;
330
331 if (sn76496_buffered) UpdateStream(Num, SyncInternal());
332
333 struct SN76496 *R = Chips[Num];
334
335 if (Data & 0x80) {
336 r = (Data & 0x70) >> 4;
337 R->LastRegister = r;
338 R->Register[r] = (R->Register[r] & 0x3f0) | (Data & 0x0f);
339 } else {
340 r = R->LastRegister;
341 }
342
343 c = r / 2;
344
345 switch (r)
346 {
347 case 0: /* tone 0 : frequency */
348 case 2: /* tone 1 : frequency */
349 case 4: /* tone 2 : frequency */
350 if ((Data & 0x80) == 0) R->Register[r] = (R->Register[r] & 0x0f) | ((Data & 0x3f) << 4);
351 R->Period[c] = R->UpdateStep * R->Register[r];
352 if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
353 if (r == 4)
354 {
355 /* update noise shift frequency */
356 if ((R->Register[6] & 0x03) == 0x03)
357 R->Period[3] = 2 * R->Period[2];
358 }
359 break;
360 case 1: /* tone 0 : volume */
361 case 3: /* tone 1 : volume */
362 case 5: /* tone 2 : volume */
363 case 7: /* noise : volume */
364 R->Volume[c] = R->VolTable[Data & 0x0f];
365 if ((Data & 0x80) == 0) R->Register[r] = (R->Register[r] & 0x3f0) | (Data & 0x0f);
366 break;
367 case 6: /* noise : frequency, mode */
368 {
369 if ((Data & 0x80) == 0) R->Register[r] = (R->Register[r] & 0x3f0) | (Data & 0x0f);
370 n = R->Register[6];
371 R->NoiseMode = (n & 4) ? 1 : 0;
372 /* N/512,N/1024,N/2048,Tone #3 output */
373 R->Period[3] = ((n&3) == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+(n&3)));
374 /* Reset noise shifter */
375 R->RNG = R->FeedbackMask; /* this is correct according to the smspower document */
376 //R->RNG = 0xF35; /* this is not, but sounds better in do run run */
377 R->Output[3] = R->RNG & 1;
378 }
379 break;
380 }
381 }
382
SN76496SetGain(struct SN76496 * R,INT32 Gain)383 static void SN76496SetGain(struct SN76496 *R,INT32 Gain)
384 {
385 INT32 i;
386 double Out;
387
388 Gain &= 0xff;
389
390 /* increase max output basing on gain (0.2 dB per step) */
391 Out = MAX_OUTPUT / 4;
392 while (Gain-- > 0)
393 Out *= 1.023292992; /* = (10 ^ (0.2/20)) */
394
395 /* build volume table (2dB per step) */
396 for (i = 0;i < 15;i++)
397 {
398 /* limit volume to avoid clipping */
399 if (Out > MAX_OUTPUT / 4) R->VolTable[i] = MAX_OUTPUT / 4;
400 else R->VolTable[i] = (INT32)Out;
401
402 Out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */
403 }
404 R->VolTable[15] = 0;
405 }
406
SN76496Reset()407 void SN76496Reset()
408 {
409 #if defined FBNEO_DEBUG
410 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496Reset called without init\n"));
411 #endif
412
413 INT32 i;
414
415 for (INT32 Num = 0; Num < NumChips; Num++) {
416 struct SN76496 *R = Chips[Num];
417
418 for (i = 0; i < 4; i++) R->Volume[i] = 0;
419
420 R->LastRegister = 0;
421 for (i = 0; i < 8; i += 2) {
422 R->Register[i + 0] = 0x00;
423 R->Register[i + 1] = 0x0f;
424 }
425
426 for (i = 0; i < 4; i++) {
427 R->Output[i] = 0;
428 R->Period[i] = R->Count[i] = R->UpdateStep;
429 }
430
431 R->FeedbackMask = 0x4000;
432 R->WhitenoiseTaps = 0x03;
433 R->WhitenoiseInvert = 1;
434 R->StereoMask = 0xFF;
435
436 R->RNG = R->FeedbackMask;
437 R->Output[3] = R->RNG & 1;
438 }
439
440 // dc blocking stuff
441 dac_lastin_r = 0;
442 dac_lastout_r = 0;
443 dac_lastin_l = 0;
444 dac_lastout_l = 0;
445 }
446
SN76496Init(struct SN76496 * R,INT32 Clock)447 static void SN76496Init(struct SN76496 *R, INT32 Clock)
448 {
449 R->UpdateStep = (UINT32)(((double)STEP * nBurnSoundRate * 16) / Clock);
450
451 SN76496Reset();
452 }
453
GenericStart(INT32 Num,INT32 Clock,INT32 FeedbackMask,INT32 NoiseTaps,INT32 NoiseInvert,INT32 SignalAdd)454 static void GenericStart(INT32 Num, INT32 Clock, INT32 FeedbackMask, INT32 NoiseTaps, INT32 NoiseInvert, INT32 SignalAdd)
455 {
456 DebugSnd_SN76496Initted = 1;
457
458 if (Num >= MAX_SN76496_CHIPS) return;
459
460 if (sn76496_buffered) {
461 bprintf(0, _T("*** ERROR: SN76496SetBuffered() must be called AFTER all chips have been initted!\n"));
462 }
463
464 NumChips = Num + 1;
465
466 Chips[Num] = (struct SN76496*)BurnMalloc(sizeof(struct SN76496));
467 memset(Chips[Num], 0, sizeof(struct SN76496));
468
469 SN76496Init(Chips[Num], Clock);
470 SN76496SetGain(Chips[Num], 0);
471
472 soundbuf[Num] = (INT16*)BurnMalloc(0x1000);
473
474 Chips[Num]->FeedbackMask = FeedbackMask;
475 Chips[Num]->WhitenoiseTaps = NoiseTaps;
476 Chips[Num]->WhitenoiseInvert = NoiseInvert;
477 Chips[Num]->bSignalAdd = SignalAdd;
478 Chips[Num]->nVolume = 1.00;
479 Chips[Num]->nOutputDir = BURN_SND_ROUTE_BOTH;
480
481 // dc blocking stuff
482 dac_lastin_r = 0;
483 dac_lastout_r = 0;
484 dac_lastin_l = 0;
485 dac_lastout_l = 0;
486 }
487
SN76489Init(INT32 Num,INT32 Clock,INT32 SignalAdd)488 void SN76489Init(INT32 Num, INT32 Clock, INT32 SignalAdd)
489 {
490 return GenericStart(Num, Clock, 0x4000, 0x03, 1, SignalAdd);
491 }
492
SN76489AInit(INT32 Num,INT32 Clock,INT32 SignalAdd)493 void SN76489AInit(INT32 Num, INT32 Clock, INT32 SignalAdd)
494 {
495 return GenericStart(Num, Clock, 0x8000, 0x06, 0, SignalAdd);
496 }
497
SN76494Init(INT32 Num,INT32 Clock,INT32 SignalAdd)498 void SN76494Init(INT32 Num, INT32 Clock, INT32 SignalAdd)
499 {
500 return GenericStart(Num, Clock, 0x8000, 0x06, 0, SignalAdd);
501 }
502
SN76496Init(INT32 Num,INT32 Clock,INT32 SignalAdd)503 void SN76496Init(INT32 Num, INT32 Clock, INT32 SignalAdd)
504 {
505 return GenericStart(Num, Clock, 0x8000, 0x06, 0, SignalAdd);
506 }
507
SN76496SetRoute(INT32 Num,double nVolume,INT32 nRouteDir)508 void SN76496SetRoute(INT32 Num, double nVolume, INT32 nRouteDir)
509 {
510 #if defined FBNEO_DEBUG
511 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496SetRoute called without init\n"));
512 if (Num > NumChips) bprintf(PRINT_ERROR, _T("SN76496SetRoute called with invalid chip %i\n"), Num);
513 #endif
514
515 if (Num >= MAX_SN76496_CHIPS) return;
516
517 struct SN76496 *R = Chips[Num];
518
519 R->nVolume = nVolume;
520 R->nOutputDir = nRouteDir;
521 }
522
SN76496Exit()523 void SN76496Exit()
524 {
525 #if defined FBNEO_DEBUG
526 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496Exit called without init\n"));
527 #endif
528
529 for (INT32 i = 0; i < NumChips; i++) {
530 BurnFree(Chips[i]);
531 BurnFree(soundbuf[i]);
532 Chips[i] = NULL;
533
534 if (sn76496_buffered) {
535 nPosition[i] = 0;
536 }
537 }
538
539 NumChips = 0;
540
541 if (sn76496_buffered) {
542 sn76496_buffered = 0;
543 pCPUTotalCycles = NULL;
544 nDACCPUMHZ = 0;
545 }
546
547 DebugSnd_SN76496Initted = 0;
548 }
549
SN76496Scan(INT32 nAction,INT32 * pnMin)550 void SN76496Scan(INT32 nAction, INT32 *pnMin)
551 {
552 #if defined FBNEO_DEBUG
553 if (!DebugSnd_SN76496Initted) bprintf(PRINT_ERROR, _T("SN76496Scan called without init\n"));
554 #endif
555
556 if (pnMin != NULL) {
557 *pnMin = 0x029719;
558 }
559
560 if (nAction & ACB_DRIVER_DATA) {
561 for (INT32 i = 0; i < NumChips; i++) {
562 ScanVar(Chips[i], STRUCT_SIZE_HELPER(struct SN76496, StereoMask), "SN76496/SN76489 Chip");
563 }
564 }
565 }
566
567 #undef MAX_SN76496_CHIPS
568 #undef MAX_OUTPUT
569 #undef STEP
570