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