|
|
1.1 root 1: /* This code comes from MAME 0.53 and according to changes log was written
2: by Nicola Salmoria. The MAME license says:
3:
4: VI. Reuse of Source Code
5: --------------------------
6: This chapter might not apply to specific portions of MAME (e.g. CPU
7: emulators) which bear different copyright notices.
8: The source code cannot be used in a commercial product without the written
9: authorization of the authors. Use in non-commercial products is allowed, and
10: indeed encouraged. If you use portions of the MAME source code in your
11: program, however, you must make the full source code freely available as
12: well.
13: Usage of the _information_ contained in the source code is free for any use.
14: However, given the amount of time and energy it took to collect this
15: information, if you find new information we would appreciate if you made it
16: freely available as well.
17:
18: */
19:
20: /***************************************************************************
21:
22: sn76496.c
23:
24: Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
25: tone /noise generator. Also known as (or at least compatible with) TMS9919.
26:
27: Noise emulation is not accurate due to lack of documentation. The noise
28: generator uses a shift register with a XOR-feedback network, but the exact
29: layout is unknown. It can be set for either period or white noise; again,
30: the details are unknown.
31:
32: ***************************************************************************/
33:
34: /* get uint16 definition */
35: #include "generator.h"
36:
37: #include "sn76496.h"
38:
39: #define MAX_OUTPUT 0x7fff
40: #define STEP 0x10000
41:
42: /* Formulas for noise generator */
43: /* bit0 = output */
44:
45: /* noise feedback for white noise mode */
46: #define FB_WNOISE 0x12000 /* bit15.d(16bits) = bit0(out) ^ bit2 */
47: //#define FB_WNOISE 0x14000 /* bit15.d(16bits) = bit0(out) ^ bit1 */
48: //#define FB_WNOISE 0x28000 /* bit16.d(17bits) = bit0(out) ^ bit2 (same to AY-3-8910) */
49: //#define FB_WNOISE 0x50000 /* bit17.d(18bits) = bit0(out) ^ bit2 */
50:
51: /* noise feedback for periodic noise mode */
52: /* it is correct maybe (it was in the Megadrive sound manual) */
53: //#define FB_PNOISE 0x10000 /* 16bit rorate */
54: #define FB_PNOISE 0x08000 /* JH 981127 - fixes Do Run Run */
55:
56: /* noise generator start preset (for periodic noise) */
57: #define NG_PRESET 0x0f35
58:
59: struct SN76496 sn[MAX_76496];
60:
61: void SN76496Write(int chip, int data)
62: {
63: struct SN76496 *R = &sn[chip];
64:
65: /* should update buffer before getting here */
66:
67: if (data & 0x80) {
68: int r = (data & 0x70) >> 4;
69: int c = r / 2;
70:
71: R->LastRegister = r;
72: R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
73: switch (r) {
74: case 0: /* tone 0 : frequency */
75: case 2: /* tone 1 : frequency */
76: case 4: /* tone 2 : frequency */
77: R->Period[c] = R->UpdateStep * R->Register[r];
78: if (R->Period[c] == 0)
79: R->Period[c] = R->UpdateStep;
80: if (r == 4) {
81: /* update noise shift frequency */
82: if ((R->Register[6] & 0x03) == 0x03)
83: R->Period[3] = 2 * R->Period[2];
84: }
85: break;
86: case 1: /* tone 0 : volume */
87: case 3: /* tone 1 : volume */
88: case 5: /* tone 2 : volume */
89: case 7: /* noise : volume */
90: R->Volume[c] = R->VolTable[data & 0x0f];
91: break;
92: case 6: /* noise : frequency, mode */
93: {
94: int n = R->Register[6];
95: R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
96: n &= 3;
97: /* N/512,N/1024,N/2048,Tone #3 output */
98: R->Period[3] =
99: (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5 + n));
100:
101: /* reset noise shifter */
102: R->RNG = NG_PRESET;
103: R->Output[3] = R->RNG & 1;
104: }
105: break;
106: }
107: } else {
108: int r = R->LastRegister;
109: int c = r / 2;
110:
111: switch (r) {
112: case 0: /* tone 0 : frequency */
113: case 2: /* tone 1 : frequency */
114: case 4: /* tone 2 : frequency */
115: R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
116: R->Period[c] = R->UpdateStep * R->Register[r];
117: if (R->Period[c] == 0)
118: R->Period[c] = R->UpdateStep;
119: if (r == 4) {
120: /* update noise shift frequency */
121: if ((R->Register[6] & 0x03) == 0x03)
122: R->Period[3] = 2 * R->Period[2];
123: }
124: break;
125: }
126: }
127: }
128:
129: void SN76496Update(int chip, uint16 *buffer, int length)
130: {
131: int i;
132: struct SN76496 *R = &sn[chip];
133:
134: /* If the volume is 0, increase the counter */
135: for (i = 0; i < 4; i++) {
136: if (R->Volume[i] == 0) {
137: /* note that I do count += length, NOT count = length + 1. You might
138: think it's the same since the volume is 0, but doing the latter
139: could cause interferencies when the program is rapidly modulating
140: the volume. */
141: if (R->Count[i] <= length * STEP)
142: R->Count[i] += length * STEP;
143: }
144: }
145:
146: while (length > 0) {
147: int vol[4];
148: unsigned int out;
149: int left;
150:
151: /* vol[] keeps track of how long each square wave stays */
152: /* in the 1 position during the sample period. */
153: vol[0] = vol[1] = vol[2] = vol[3] = 0;
154:
155: for (i = 0; i < 3; i++) {
156: if (R->Output[i])
157: vol[i] += R->Count[i];
158: R->Count[i] -= STEP;
159: /* Period[i] is the half period of the square wave. Here, in each */
160: /* loop I add Period[i] twice, so that at the end of the loop the */
161: /* square wave is in the same status (0 or 1) it was at the start. */
162: /* vol[i] is also incremented by Period[i], since the wave has been 1 */
163: /* exactly half of the time, regardless of the initial position. */
164: /* If we exit the loop in the middle, Output[i] has to be inverted */
165: /* and vol[i] incremented only if the exit status of the square */
166: /* wave is 1. */
167: while (R->Count[i] <= 0) {
168: R->Count[i] += R->Period[i];
169: if (R->Count[i] > 0) {
170: R->Output[i] ^= 1;
171: if (R->Output[i])
172: vol[i] += R->Period[i];
173: break;
174: }
175: R->Count[i] += R->Period[i];
176: vol[i] += R->Period[i];
177: }
178: if (R->Output[i])
179: vol[i] -= R->Count[i];
180: }
181:
182: left = STEP;
183: do {
184: int nextevent;
185:
186: if (R->Count[3] < left)
187: nextevent = R->Count[3];
188: else
189: nextevent = left;
190: if (R->Output[3])
191: vol[3] += R->Count[3];
192: R->Count[3] -= nextevent;
193: if (R->Count[3] <= 0) {
194: if (R->RNG & 1)
195: R->RNG ^= R->NoiseFB;
196: R->RNG >>= 1;
197: R->Output[3] = R->RNG & 1;
198: R->Count[3] += R->Period[3];
199: if (R->Output[3])
200: vol[3] += R->Period[3];
201: }
202: if (R->Output[3])
203: vol[3] -= R->Count[3];
204: left -= nextevent;
205: } while (left > 0);
206:
207: out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
208: vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
209: if (out > MAX_OUTPUT * STEP)
210: out = MAX_OUTPUT * STEP;
211: *(buffer++) = out / STEP;
212: length--;
213: }
214: }
215:
216: static void SN76496_set_clock(int chip, int clock)
217: {
218: struct SN76496 *R = &sn[chip];
219:
220: /* the base clock for the tone generators is the chip clock divided by 16; */
221: /* for the noise generator, it is clock / 256. */
222: /* Here we calculate the number of steps which happen during one sample */
223: /* at the given sample rate. No. of events = sample rate / (clock/16). */
224: /* STEP is a multiplier used to turn the fraction into a fixed point */
225: /* number. */
226: R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock;
227: }
228:
229: static void SN76496_set_gain(int chip, int gain)
230: {
231: struct SN76496 *R = &sn[chip];
232: int i;
233: double out;
234:
235: gain &= 0xff;
236: /* increase max output basing on gain (0.2 dB per step) */
237: out = MAX_OUTPUT / 3;
238: while (gain-- > 0)
239: out *= 1.023292992; /* = (10 ^ (0.2/20)) */
240: /* build volume table (2dB per step) */
241: for (i = 0; i < 15; i++) {
242: /* limit volume to avoid clipping */
243: if (out > MAX_OUTPUT / 3)
244: R->VolTable[i] = MAX_OUTPUT / 3;
245: else
246: R->VolTable[i] = out;
247: out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */
248: }
249: R->VolTable[15] = 0;
250: }
251:
252: int SN76496Init(int chip, int clock, int gain, int sample_rate)
253: {
254: int i;
255: struct SN76496 *R = &sn[chip];
256: char name[40];
257:
258: R->SampleRate = sample_rate;
259: SN76496_set_clock(chip, clock);
260:
261: for (i = 0; i < 4; i++)
262: R->Volume[i] = 0;
263:
264: R->LastRegister = 0;
265: for (i = 0; i < 8; i += 2) {
266: R->Register[i] = 0;
267: R->Register[i + 1] = 0x0f; /* volume = 0 */
268: }
269:
270: for (i = 0; i < 4; i++) {
271: R->Output[i] = 0;
272: R->Period[i] = R->Count[i] = R->UpdateStep;
273: }
274: R->RNG = NG_PRESET;
275: R->Output[3] = R->RNG & 1;
276: SN76496_set_gain(chip, gain & 0xff);
277:
278: return 0;
279: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.