1 /***************************************************************************
2 
3   sn76496.c
4 
5   Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
6   tone /noise generator. Also known as (or at least compatible with) TMS9919.
7 
8   Noise emulation is not accurate due to lack of documentation. The noise
9   generator uses a shift register with a XOR-feedback network, but the exact
10   layout is unknown. It can be set for either period or white noise; again,
11   the details are unknown.
12 
13 ***************************************************************************/
14 
15 #include "driver.h"
16 
17 
18 #define MAX_OUTPUT 0x7fff
19 
20 #define STEP 0x10000
21 
22 
23 /* Formulas for noise generator */
24 /* bit0 = output */
25 
26 /* noise feedback for white noise mode */
27 #define FB_WNOISE 0x12000	/* bit15.d(16bits) = bit0(out) ^ bit2 */
28 //#define FB_WNOISE 0x14000	/* bit15.d(16bits) = bit0(out) ^ bit1 */
29 //#define FB_WNOISE 0x28000	/* bit16.d(17bits) = bit0(out) ^ bit2 (same to AY-3-8910) */
30 //#define FB_WNOISE 0x50000	/* bit17.d(18bits) = bit0(out) ^ bit2 */
31 
32 /* noise feedback for periodic noise mode */
33 /* it is correct maybe (it was in the Megadrive sound manual) */
34 //#define FB_PNOISE 0x10000	/* 16bit rorate */
35 #define FB_PNOISE 0x08000   /* JH 981127 - fixes Do Run Run */
36 
37 /* noise generator start preset (for periodic noise) */
38 #define NG_PRESET 0x0f35
39 
40 
41 struct SN76496
42 {
43 	int Channel;
44 	int SampleRate;
45 	unsigned int UpdateStep;
46 	int VolTable[16];	/* volume table         */
47 	int Register[8];	/* registers */
48 	int LastRegister;	/* last register written */
49 	int Volume[4];		/* volume of voice 0-2 and noise */
50 	unsigned int RNG;		/* noise generator      */
51 	int NoiseFB;		/* noise feedback mask */
52 	int Period[4];
53 	int Count[4];
54 	int Output[4];
55 };
56 
57 
58 static struct SN76496 sn[MAX_76496];
59 
60 
61 
SN76496Write(int chip,int data)62 static void SN76496Write(int chip,int data)
63 {
64 	struct SN76496 *R = &sn[chip];
65 
66 
67 	/* update the output buffer before changing the registers */
68 	stream_update(R->Channel,0);
69 
70 	if (data & 0x80)
71 	{
72 		int r = (data & 0x70) >> 4;
73 		int c = r/2;
74 
75 		R->LastRegister = r;
76 		R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
77 		switch (r)
78 		{
79 			case 0:	/* tone 0 : frequency */
80 			case 2:	/* tone 1 : frequency */
81 			case 4:	/* tone 2 : frequency */
82 				R->Period[c] = R->UpdateStep * R->Register[r];
83 				if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
84 				if (r == 4)
85 				{
86 					/* update noise shift frequency */
87 					if ((R->Register[6] & 0x03) == 0x03)
88 						R->Period[3] = 2 * R->Period[2];
89 				}
90 				break;
91 			case 1:	/* tone 0 : volume */
92 			case 3:	/* tone 1 : volume */
93 			case 5:	/* tone 2 : volume */
94 			case 7:	/* noise  : volume */
95 				R->Volume[c] = R->VolTable[data & 0x0f];
96 				break;
97 			case 6:	/* noise  : frequency, mode */
98 				{
99 					int n = R->Register[6];
100 					R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
101 					n &= 3;
102 					/* N/512,N/1024,N/2048,Tone #3 output */
103 					R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+n));
104 
105 					/* reset noise shifter */
106 					R->RNG = NG_PRESET;
107 					R->Output[3] = R->RNG & 1;
108 				}
109 				break;
110 		}
111 	}
112 	else
113 	{
114 		int r = R->LastRegister;
115 		int c = r/2;
116 
117 		switch (r)
118 		{
119 			case 0:	/* tone 0 : frequency */
120 			case 2:	/* tone 1 : frequency */
121 			case 4:	/* tone 2 : frequency */
122 				R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
123 				R->Period[c] = R->UpdateStep * R->Register[r];
124 				if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
125 				if (r == 4)
126 				{
127 					/* update noise shift frequency */
128 					if ((R->Register[6] & 0x03) == 0x03)
129 						R->Period[3] = 2 * R->Period[2];
130 				}
131 				break;
132 		}
133 	}
134 }
135 
136 
WRITE_HANDLER(SN76496_0_w)137 WRITE_HANDLER( SN76496_0_w ) {	SN76496Write(0,data); }
WRITE_HANDLER(SN76496_1_w)138 WRITE_HANDLER( SN76496_1_w ) {	SN76496Write(1,data); }
WRITE_HANDLER(SN76496_2_w)139 WRITE_HANDLER( SN76496_2_w ) {	SN76496Write(2,data); }
WRITE_HANDLER(SN76496_3_w)140 WRITE_HANDLER( SN76496_3_w ) {	SN76496Write(3,data); }
141 
142 
143 
SN76496Update(int chip,INT16 * buffer,int length)144 static void SN76496Update(int chip,INT16 *buffer,int length)
145 {
146 	int i;
147 	struct SN76496 *R = &sn[chip];
148 
149 
150 	/* If the volume is 0, increase the counter */
151 	for (i = 0;i < 4;i++)
152 	{
153 		if (R->Volume[i] == 0)
154 		{
155 			/* note that I do count += length, NOT count = length + 1. You might think */
156 			/* it's the same since the volume is 0, but doing the latter could cause */
157 			/* interferencies when the program is rapidly modulating the volume. */
158 			if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP;
159 		}
160 	}
161 
162 	while (length > 0)
163 	{
164 		int vol[4];
165 		unsigned int out;
166 		int left;
167 
168 
169 		/* vol[] keeps track of how long each square wave stays */
170 		/* in the 1 position during the sample period. */
171 		vol[0] = vol[1] = vol[2] = vol[3] = 0;
172 
173 		for (i = 0;i < 3;i++)
174 		{
175 			if (R->Output[i]) vol[i] += R->Count[i];
176 			R->Count[i] -= STEP;
177 			/* Period[i] is the half period of the square wave. Here, in each */
178 			/* loop I add Period[i] twice, so that at the end of the loop the */
179 			/* square wave is in the same status (0 or 1) it was at the start. */
180 			/* vol[i] is also incremented by Period[i], since the wave has been 1 */
181 			/* exactly half of the time, regardless of the initial position. */
182 			/* If we exit the loop in the middle, Output[i] has to be inverted */
183 			/* and vol[i] incremented only if the exit status of the square */
184 			/* wave is 1. */
185 			while (R->Count[i] <= 0)
186 			{
187 				R->Count[i] += R->Period[i];
188 				if (R->Count[i] > 0)
189 				{
190 					R->Output[i] ^= 1;
191 					if (R->Output[i]) vol[i] += R->Period[i];
192 					break;
193 				}
194 				R->Count[i] += R->Period[i];
195 				vol[i] += R->Period[i];
196 			}
197 			if (R->Output[i]) vol[i] -= R->Count[i];
198 		}
199 
200 		left = STEP;
201 		do
202 		{
203 			int nextevent;
204 
205 
206 			if (R->Count[3] < left) nextevent = R->Count[3];
207 			else nextevent = left;
208 
209 			if (R->Output[3]) vol[3] += R->Count[3];
210 			R->Count[3] -= nextevent;
211 			if (R->Count[3] <= 0)
212 			{
213 				if (R->RNG & 1) R->RNG ^= R->NoiseFB;
214 				R->RNG >>= 1;
215 				R->Output[3] = R->RNG & 1;
216 				R->Count[3] += R->Period[3];
217 				if (R->Output[3]) vol[3] += R->Period[3];
218 			}
219 			if (R->Output[3]) vol[3] -= R->Count[3];
220 
221 			left -= nextevent;
222 		} while (left > 0);
223 
224 		out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
225 				vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
226 
227 		if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;
228 
229 		*(buffer++) = out / STEP;
230 
231 		length--;
232 	}
233 }
234 
235 
236 
SN76496_set_clock(int chip,int clock)237 static void SN76496_set_clock(int chip,int clock)
238 {
239 	struct SN76496 *R = &sn[chip];
240 
241 
242 	/* the base clock for the tone generators is the chip clock divided by 16; */
243 	/* for the noise generator, it is clock / 256. */
244 	/* Here we calculate the number of steps which happen during one sample */
245 	/* at the given sample rate. No. of events = sample rate / (clock/16). */
246 	/* STEP is a multiplier used to turn the fraction into a fixed point */
247 	/* number. */
248 	R->UpdateStep = ((float)STEP * R->SampleRate * 16) / clock;
249 }
250 
251 
252 
SN76496_set_gain(int chip,int gain)253 static void SN76496_set_gain(int chip,int gain)
254 {
255 	struct SN76496 *R = &sn[chip];
256 	int i;
257 	float out;
258 
259 
260 	gain &= 0xff;
261 
262 	/* increase max output basing on gain (0.2 dB per step) */
263 	out = MAX_OUTPUT / 3;
264 	while (gain-- > 0)
265 		out *= 1.023292992;	/* = (10 ^ (0.2/20)) */
266 
267 	/* build volume table (2dB per step) */
268 	for (i = 0;i < 15;i++)
269 	{
270 		/* limit volume to avoid clipping */
271 		if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3;
272 		else R->VolTable[i] = out;
273 
274 		out /= 1.258925412;	/* = 10 ^ (2/20) = 2dB */
275 	}
276 	R->VolTable[15] = 0;
277 }
278 
279 
280 
SN76496_init(const struct MachineSound * msound,int chip,int clock,int volume,int sample_rate)281 static int SN76496_init(const struct MachineSound *msound,int chip,int clock,int volume,int sample_rate)
282 {
283 	int i;
284 	struct SN76496 *R = &sn[chip];
285 	char name[40];
286 
287 
288 	sprintf(name,"SN76496 #%d",chip);
289 	R->Channel = stream_init(name,volume,sample_rate,chip,SN76496Update);
290 
291 	if (R->Channel == -1)
292 		return 1;
293 
294 	R->SampleRate = sample_rate;
295 	SN76496_set_clock(chip,clock);
296 
297 	for (i = 0;i < 4;i++) R->Volume[i] = 0;
298 
299 	R->LastRegister = 0;
300 	for (i = 0;i < 8;i+=2)
301 	{
302 		R->Register[i] = 0;
303 		R->Register[i + 1] = 0x0f;	/* volume = 0 */
304 	}
305 
306 	for (i = 0;i < 4;i++)
307 	{
308 		R->Output[i] = 0;
309 		R->Period[i] = R->Count[i] = R->UpdateStep;
310 	}
311 	R->RNG = NG_PRESET;
312 	R->Output[3] = R->RNG & 1;
313 
314 	return 0;
315 }
316 
317 
318 
SN76496_sh_start(const struct MachineSound * msound)319 int SN76496_sh_start(const struct MachineSound *msound)
320 {
321 	int chip;
322 	const struct SN76496interface *intf = (const struct SN76496interface *)msound->sound_interface;
323 
324 
325 	for (chip = 0;chip < intf->num;chip++)
326 	{
327 		if (SN76496_init(msound,chip,intf->baseclock[chip],intf->volume[chip] & 0xff,Machine->sample_rate) != 0)
328 			return 1;
329 
330 		SN76496_set_gain(chip,(intf->volume[chip] >> 8) & 0xff);
331 	}
332 	return 0;
333 }
334