1 /***************************************************************************
5 Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
6 tone /noise generator. Also known as (or at least compatible with) TMS9919.
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.
13 ***************************************************************************/
15 ///// commented out by starshine
18 ///// added by starshine
22 #define MAX_OUTPUT 0x7fff
23 #define AUDIO_CONV(A) (A)
28 /* Formulas for noise generator */
31 /* noise feedback for white noise mode */
32 #define FB_WNOISE 0x12000 /* bit15.d(16bits) = bit0(out) ^ bit2 */
33 //#define FB_WNOISE 0x14000 /* bit15.d(16bits) = bit0(out) ^ bit1 */
34 //#define FB_WNOISE 0x28000 /* bit16.d(17bits) = bit0(out) ^ bit2 (same to AY-3-8910) */
35 //#define FB_WNOISE 0x50000 /* bit17.d(18bits) = bit0(out) ^ bit2 */
37 /* noise feedback for periodic noise mode */
38 /* it is correct maybe (it was in the Megadrive sound manual) */
39 //#define FB_PNOISE 0x10000 /* 16bit rorate */
40 #define FB_PNOISE 0x08000 /* JH 981127 - fixes Do Run Run */
42 /* noise generator start preset (for periodic noise) */
43 #define NG_PRESET 0x0f35
50 unsigned int UpdateStep
;
51 int VolTable
[16]; /* volume table */
52 int Register
[8]; /* registers */
53 int LastRegister
; /* last register written */
54 int Volume
[4]; /* volume of voice 0-2 and noise */
55 unsigned int RNG
; /* noise generator */
56 int NoiseFB
; /* noise feedback mask */
63 static struct SN76496 sn
[MAX_76496
];
67 void SN76496Write(int chip
,int data
)
69 struct SN76496
*R
= &sn
[chip
];
72 /* update the output buffer before changing the registers */
73 ///// commented out by starshine
74 //stream_update(R->Channel,0);
78 int r
= (data
& 0x70) >> 4;
82 R
->Register
[r
] = (R
->Register
[r
] & 0x3f0) | (data
& 0x0f);
85 case 0: /* tone 0 : frequency */
86 case 2: /* tone 1 : frequency */
87 case 4: /* tone 2 : frequency */
88 R
->Period
[c
] = R
->UpdateStep
* R
->Register
[r
];
89 if (R
->Period
[c
] == 0) R
->Period
[c
] = R
->UpdateStep
;
92 /* update noise shift frequency */
93 if ((R
->Register
[6] & 0x03) == 0x03)
94 R
->Period
[3] = 2 * R
->Period
[2];
97 case 1: /* tone 0 : volume */
98 case 3: /* tone 1 : volume */
99 case 5: /* tone 2 : volume */
100 case 7: /* noise : volume */
101 R
->Volume
[c
] = R
->VolTable
[data
& 0x0f];
103 case 6: /* noise : frequency, mode */
105 int n
= R
->Register
[6];
106 R
->NoiseFB
= (n
& 4) ? FB_WNOISE
: FB_PNOISE
;
108 /* N/512,N/1024,N/2048,Tone #3 output */
109 R
->Period
[3] = (n
== 3) ? 2 * R
->Period
[2] : (R
->UpdateStep
<< (5+n
));
111 /* reset noise shifter */
113 R
->Output
[3] = R
->RNG
& 1;
120 int r
= R
->LastRegister
;
125 case 0: /* tone 0 : frequency */
126 case 2: /* tone 1 : frequency */
127 case 4: /* tone 2 : frequency */
128 R
->Register
[r
] = (R
->Register
[r
] & 0x0f) | ((data
& 0x3f) << 4);
129 R
->Period
[c
] = R
->UpdateStep
* R
->Register
[r
];
130 if (R
->Period
[c
] == 0) R
->Period
[c
] = R
->UpdateStep
;
133 /* update noise shift frequency */
134 if ((R
->Register
[6] & 0x03) == 0x03)
135 R
->Period
[3] = 2 * R
->Period
[2];
143 void SN76496_0_w(int offset
,int data
) { SN76496Write(0,data
); }
144 void SN76496_1_w(int offset
,int data
) { SN76496Write(1,data
); }
145 void SN76496_2_w(int offset
,int data
) { SN76496Write(2,data
); }
146 void SN76496_3_w(int offset
,int data
) { SN76496Write(3,data
); }
150 void SN76496Update_8(int chip
,void *buffer
,int length
)
152 #define DATATYPE unsigned char
153 #define DATACONV(A) AUDIO_CONV((A) / (STEP * 256))
154 #include "sn76496u.c"
159 void SN76496Update_16(int chip
,void *buffer
,int length
)
161 #define DATATYPE unsigned short
162 #define DATACONV(A) ((A) / STEP)
163 #include "sn76496u.c"
170 void SN76496_set_clock(int chip
,int clock
)
172 struct SN76496
*R
= &sn
[chip
];
175 /* the base clock for the tone generators is the chip clock divided by 16; */
176 /* for the noise generator, it is clock / 256. */
177 /* Here we calculate the number of steps which happen during one sample */
178 /* at the given sample rate. No. of events = sample rate / (clock/16). */
179 /* STEP is a multiplier used to turn the fraction into a fixed point */
181 R
->UpdateStep
= ((double)STEP
* R
->SampleRate
* 16) / clock
;
186 static void SN76496_set_volume(int chip
,int volume
,int gain
)
188 struct SN76496
*R
= &sn
[chip
];
193 ///// commented out by starshine
194 //stream_set_volume(R->Channel,volume);
198 /* increase max output basing on gain (0.2 dB per step) */
199 out
= MAX_OUTPUT
/ 3;
201 out
*= 1.023292992; /* = (10 ^ (0.2/20)) */
203 /* build volume table (2dB per step) */
204 for (i
= 0;i
< 15;i
++)
206 /* limit volume to avoid clipping */
207 if (out
> MAX_OUTPUT
/ 3) R
->VolTable
[i
] = MAX_OUTPUT
/ 3;
208 else R
->VolTable
[i
] = out
;
210 out
/= 1.258925412; /* = 10 ^ (2/20) = 2dB */
217 int SN76496_init(int chip
,int clock
,int sample_rate
,int sample_bits
)
220 struct SN76496
*R
= &sn
[chip
];
223 ////// commented out by starshine
224 //sprintf(name,"SN76496 #%d",chip);
225 //R->Channel = stream_init(msound,
226 // name,sample_rate,sample_bits,
227 // chip,(sample_bits == 16) ? SN76496Update_16 : SN76496Update_8);
229 if (R
->Channel
== -1)
232 R
->SampleRate
= sample_rate
;
233 SN76496_set_clock(chip
,clock
);
234 SN76496_set_volume(chip
,255,0);
236 for (i
= 0;i
< 4;i
++) R
->Volume
[i
] = 0;
239 for (i
= 0;i
< 8;i
+=2)
242 R
->Register
[i
+ 1] = 0x0f; /* volume = 0 */
245 for (i
= 0;i
< 4;i
++)
248 R
->Period
[i
] = R
->Count
[i
] = R
->UpdateStep
;
251 R
->Output
[3] = R
->RNG
& 1;
258 int SN76496_sh_start()
260 ///// total commenting out by starshine
262 //const struct SN76496interface *intf = msound->sound_interface;
265 //for (chip = 0;chip < intf->num;chip++)
267 // if (SN76496_init(msound,chip,intf->baseclock,Machine->sample_rate,Machine->sample_bits) != 0)
270 // SN76496_set_volume(chip,intf->volume[chip] & 0xff,(intf->volume[chip] >> 8) & 0xff);