summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/skyraid.c
blob: 95dc7cac596fca88f5104dcb398919d6e86d54d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/************************************************************************
 * skyraid Sound System Analog emulation
 * Sept 2009, Derrick Renaud
 ************************************************************************/

#include "driver.h"
#include "includes/skyraid.h"


/* Discrete Sound Input Nodes */
#define SKYRAID_PLANE_SWEEP_EN		NODE_01
#define SKYRAID_MISSILE_EN			NODE_02
#define SKYRAID_EXPLOSION_EN		NODE_03
#define SKYRAID_PLANE_ON_EN			NODE_04
#define SKYRAID_PLANE_ON__IC_E8		SKYRAID_PLANE_ON_EN
#define SKYRAID_ATTRACT_EN			NODE_05

/* Discrete Sound Output Nodes */
#define SKYRAID_NOISE				NODE_10
#define SKYRAID_EXPLOSION_SND		NODE_11
#define SKYRAID_JET_A_SND			NODE_12
#define SKYRAID_JET_B_SND			NODE_13
#define SKYRAID_MSL_A_SND			NODE_14
#define SKYRAID_MSL_B_SND			NODE_15
#define SKYRAID_PLANE_SND			NODE_16

/* Parts List - Resistors */
#define SKYRAID_R12		RES_K(1)
#define SKYRAID_R13		RES_K(10)
#define SKYRAID_R14		RES_K(100)
#define SKYRAID_R16		RES_K(10)
#define SKYRAID_R18		RES_K(10)
#define SKYRAID_R19		RES_K(10)
#define SKYRAID_R20		RES_K(47)
#define SKYRAID_R24		RES_M(10)
#define SKYRAID_R25		RES_M(3.9)
#define SKYRAID_R27		RES_M(1.5)
#define SKYRAID_R28		RES_M(1.5)
#define SKYRAID_R29		RES_M(4.7)
#define SKYRAID_R30		RES_M(1)
#define SKYRAID_R31		RES_M(1)
#define SKYRAID_R32		RES_M(4.7)
#define SKYRAID_R84		RES_K(22)
#define SKYRAID_R85		RES_K(100)
#define SKYRAID_R86		820
#define SKYRAID_R110	RES_K(330)
#define SKYRAID_R118	RES_K(470)
#define SKYRAID_R119	RES_K(10)
#define SKYRAID_R120	RES_K(220)
#define SKYRAID_R121	RES_K(1)
#define SKYRAID_R122	RES_K(150)

/* Parts List - Capacitors */
#define SKYRAID_C44		CAP_U(4.7)
#define SKYRAID_C45		CAP_U(.0047)
#define SKYRAID_C46		CAP_U(.001)
#define SKYRAID_C48		CAP_U(.0047)
#define SKYRAID_C49		CAP_U(.1)
#define SKYRAID_C50		CAP_U(.001)
#define SKYRAID_C51		CAP_U(.01)
#define SKYRAID_C68		CAP_U(10)
#define SKYRAID_C85		CAP_U(.068)
#define SKYRAID_C86		CAP_U(.1)
#define SKYRAID_C93		CAP_U(.1)


static const discrete_lfsr_desc skyraid_lfsr =
{
	DISC_CLK_IS_FREQ,
	16,					/* Bit Length */
	0,					/* Reset Value */
	0,					/* Use Bit 0 as XOR input 0 */
	14,					/* Use Bit 14 as XOR input 1 */
	DISC_LFSR_XNOR,		/* Feedback stage1 is XNOR */
	DISC_LFSR_OR,		/* Feedback stage2 is just stage 1 output OR with external feed */
	DISC_LFSR_REPLACE,	/* Feedback stage3 replaces the shifted register contents */
	0x000001,			/* Everything is shifted into the first bit only */
	DISC_LFSR_FLAG_RESET_TYPE_H,	/* Output is not inverted */
	15					/* Output bit */
};

static const discrete_op_amp_filt_info skyraid_explosion_filter =
{
	SKYRAID_R85, 0, SKYRAID_R86, 0, SKYRAID_R110,	/* r1, r2, r3, r4, rF*/
	SKYRAID_C85, SKYRAID_C86, 0,	/* c1, c2, c3 */
	0, 12, -5,	/* vRef, vP, vN */
};

static const discrete_dac_r1_ladder skyraid_plane_dac =
{
	2, {SKYRAID_R28, SKYRAID_R27},
	0, 0, 0, 0				/* no vBias, rBias, rGnd, cFilter */
};

static const discrete_mixer_desc skyraid_mixer =
{
	DISC_MIXER_IS_RESISTOR,
	{SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31, RES_2_PARALLEL(SKYRAID_R28, SKYRAID_R27)},
	{0, 0, 0, 0, 0, SKYRAID_PLANE_ON__IC_E8},	/* r_nodes */
	{0}, 0, 0, 0, 0, 0, 1		/* no c, rI, rF, cF, cAmp, vRef, gain */
};


/************************************************************************
 *
 * Custom skyraid missle charge
 *
 * input[0]    - In1 (Logic)
 * input[1]    - R1
 * input[2]    - R2
 * input[3]    - R3
 * input[4]    - C
 *
 *              12V            5V
 *               v              v
 *               |              |
 *               Z             ---
 *               Z R1           ^   1N914
 *               Z             / \  Diode
 *               |            -----
 *               |              |
 *               +--------------+
 *               |              |
 *              ---             Z
 *              --- C           Z R2
 *               |              Z
 *               |              |
 *               +--------------+----> Node Output
 *               |
 *               Z
 *               Z R3
 *         O.C.  Z
 *          |\   |
 *   In1 >--| o--+
 *          |/
 *
 ************************************************************************/
#define SKYRAID_MISSLE_CUSTOM_IN1		DISCRETE_INPUT(0)
#define SKYRAID_MISSLE_CUSTOM_R1		DISCRETE_INPUT(1)
#define SKYRAID_MISSLE_CUSTOM_R2		DISCRETE_INPUT(2)
#define SKYRAID_MISSLE_CUSTOM_R3		DISCRETE_INPUT(3)
#define SKYRAID_MISSLE_CUSTOM_C			DISCRETE_INPUT(4)

struct skyraid_missle_custom_charge_context
{
	double v_charge[2];
	double v_cap;
	double exp[2];
};

/* the high charge is clamped by the diode to 0.7V above the 5V line */
#define SKYRAID_MISSLE_CHARGE_PLUS	(5.0 + 0.7)

static DISCRETE_STEP( skyraid_missle_custom_charge )
{
	struct skyraid_missle_custom_charge_context *context = (struct skyraid_missle_custom_charge_context *)node->context;

	int in_1 = (SKYRAID_MISSLE_CUSTOM_IN1 == 0) ? 0 : 1;

	/* charge/discharge cap */
	context->v_cap += (context->v_charge[in_1] - context->v_cap) * context->exp[in_1];

	node->output[0] = SKYRAID_MISSLE_CHARGE_PLUS - context->v_cap;
}

static DISCRETE_RESET( skyraid_missle_custom_charge )
{
	struct skyraid_missle_custom_charge_context *context = (struct skyraid_missle_custom_charge_context *)node->context;

	/* everything is based on the input to the O.C. inverter */

	/* the charging voltage across the cap */
	context->v_charge[0] = 0;
	context->v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS * RES_VOLTAGE_DIVIDER(SKYRAID_MISSLE_CUSTOM_R1 + SKYRAID_MISSLE_CUSTOM_R2, SKYRAID_MISSLE_CUSTOM_R3);
	context->v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS - context->v_charge[1];
	context->v_cap = 0;

	/* precalculate charging exponents */
	/* discharge cap */
	context->exp[0] = RC_CHARGE_EXP(SKYRAID_MISSLE_CUSTOM_R2 * SKYRAID_MISSLE_CUSTOM_C);
	/* charge cap */
	context->exp[1] = RC_CHARGE_EXP(RES_2_PARALLEL(SKYRAID_MISSLE_CUSTOM_R1 + SKYRAID_MISSLE_CUSTOM_R2, SKYRAID_MISSLE_CUSTOM_R3) * SKYRAID_MISSLE_CUSTOM_C);

	/* starts at full voltage until cap starts charging */
	node->output[0] = SKYRAID_MISSLE_CHARGE_PLUS;
}

static const discrete_custom_info skyraid_missle_custom_charge =
{
	DISCRETE_CUSTOM_MODULE( skyraid_missle_custom_charge, struct skyraid_missle_custom_charge_context),
	NULL
};


DISCRETE_SOUND_START( skyraid )
	/************************************************
     * Input register mapping
     ************************************************/
	/* convert the PLANE_SWEEP line to voltage*/
	DISCRETE_INPUTX_LOGIC(SKYRAID_PLANE_SWEEP_EN, DEFAULT_TTL_V_LOGIC_1 * RES_VOLTAGE_DIVIDER(SKYRAID_R25, SKYRAID_R24), 0, 0)
	DISCRETE_INPUT_LOGIC(SKYRAID_MISSILE_EN)
	DISCRETE_INPUT_LOGIC(SKYRAID_EXPLOSION_EN)
	/* convert PLANE_ON into 4066 Ron value of 270 ohms @ 5V */
	DISCRETE_INPUTX_LOGIC(SKYRAID_PLANE_ON__IC_E8, 270, 0, 0)
	DISCRETE_INPUT_LOGIC(SKYRAID_ATTRACT_EN)

	/************************************************
     * Noise Generator, Explosion sound
     ************************************************/
	/* Note: the noise reset is not emulated 100% accurate */
	/* According to the schematics, Attract only clears the lower 8 bits. */
	/* I may modify the noise module in the future to properly emulate this, */
	/* but you will never hear the difference. */
	/* It only wrong for 8 cycles of the 555 while no sound is being generated. */
	DISCRETE_LFSR_NOISE(SKYRAID_NOISE,			/* IC F7, pin 13 */
		1,										/* ENAB */
		SKYRAID_ATTRACT_EN,						/* RESET */
		1.49 / ((SKYRAID_R20 + 2 * SKYRAID_R19) * SKYRAID_C51),		/* CLK - 555 astable source */
		1, 0, 0.5, &skyraid_lfsr)				/* AMPL, FEED, BIAS */

	DISCRETE_LOGIC_NOR(NODE_20, SKYRAID_EXPLOSION_EN, SKYRAID_NOISE)
	DISCRETE_RC_CIRCUIT_1(NODE_21,
		SKYRAID_EXPLOSION_EN, NODE_20,			/* INP0, INP1 */
		RES_2_PARALLEL(SKYRAID_R84, SKYRAID_R85 + SKYRAID_R86), SKYRAID_C68)
	DISCRETE_OP_AMP_FILTER(NODE_22,
		1,										/* ENAB */
		NODE_21, 0,								/* INP0, INP1 */
		DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &skyraid_explosion_filter)	/* TYPE,INFO */
	/* IC E10, pin 14 gain and clipping */
	DISCRETE_GAIN(NODE_23, NODE_22, SKYRAID_R119 / SKYRAID_R121 + 1)
	DISCRETE_CLAMP(SKYRAID_EXPLOSION_SND, NODE_23, -5, 12.0 - 1.5)

	/************************************************
     * Jet, Plane sound
     ************************************************/
	DISCRETE_RCFILTER(NODE_30,				/* IC J6, pin 5 */
		SKYRAID_PLANE_SWEEP_EN,				/* IN0 */
		RES_2_PARALLEL(SKYRAID_R25, SKYRAID_R24), SKYRAID_C49)
	DISCRETE_566(NODE_31,					/* IC J6, pin 3 */
		NODE_30,							/* VMOD */
		SKYRAID_R18, SKYRAID_C48,
		5, -5, 5,							/* VPOS,VNEG,VCHARGE */
		DISC_566_OUT_COUNT_R)
	DISCRETE_LOGIC_SHIFT(NODE_32,			/* IC H7, J7 output */
		SKYRAID_NOISE,						/* IC H7, J7 pins 1 & 2 */
		1, NODE_31, 16,						/* RESET, CLK, SIZE */
		DISC_LOGIC_SHIFT__RESET_L | DISC_LOGIC_SHIFT__LEFT | DISC_CLK_BY_COUNT)
	/* move bits together for ease of use */
	DISCRETE_TRANSFORM4(NODE_33, NODE_32, 1, 1 << 14, 2, "01&02/3&|")
	DISCRETE_DAC_R1(SKYRAID_PLANE_SND,
		NODE_33,							/* DATA */
		DEFAULT_TTL_V_LOGIC_1, &skyraid_plane_dac)
	DISCRETE_BIT_DECODE(SKYRAID_JET_A_SND, NODE_32, 0, DEFAULT_TTL_V_LOGIC_1)	/* IC H7, pin 3 */
	DISCRETE_BIT_DECODE(SKYRAID_JET_B_SND, NODE_32, 15, DEFAULT_TTL_V_LOGIC_1)	/* IC J7, pin 13 */

	/************************************************
     * Missle sound
     ************************************************/
	DISCRETE_CUSTOM5(NODE_40, SKYRAID_MISSILE_EN, SKYRAID_R12, SKYRAID_R14, SKYRAID_R13, SKYRAID_C44, &skyraid_missle_custom_charge)
	DISCRETE_566(NODE_41,					/* IC K6, pin 3 */
		NODE_40,							/* VMOD */
		SKYRAID_R16, SKYRAID_C45,
		5, -5, SKYRAID_MISSLE_CHARGE_PLUS,	/* VPOS,VNEG,VCHARGE */
		DISC_566_OUT_COUNT_R)
	DISCRETE_LOGIC_SHIFT(NODE_42,			/* IC K7, L7 output */
		SKYRAID_NOISE,						/* IC K7, L7 pins 1 & 2 */
		1, NODE_41, 16,						/* RESET, CLK, SIZE */
		DISC_LOGIC_SHIFT__RESET_L | DISC_LOGIC_SHIFT__LEFT | DISC_CLK_BY_COUNT)
	DISCRETE_BIT_DECODE(SKYRAID_MSL_A_SND, NODE_42, 0, DEFAULT_TTL_V_LOGIC_1)	/* IC K7, pin 3 */
	DISCRETE_BIT_DECODE(SKYRAID_MSL_B_SND, NODE_42, 15, DEFAULT_TTL_V_LOGIC_1)	/* IC L7, pin 13 */

	/************************************************
     * Final Mix
     ************************************************/
	DISCRETE_LOGIC_INVERT(NODE_91, SKYRAID_ATTRACT_EN)
	DISCRETE_MIXER6(NODE_92,
		NODE_91,				/* ENAB */
		SKYRAID_EXPLOSION_SND,
		SKYRAID_JET_A_SND,
		SKYRAID_JET_B_SND,
		SKYRAID_MSL_A_SND,
		SKYRAID_MSL_B_SND,
		SKYRAID_PLANE_SND,
		&skyraid_mixer)
	DISCRETE_CRFILTER(NODE_93,
		NODE_92,				/* IN0 */
		SKYRAID_R122 + RES_6_PARALLEL(SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31, RES_2_PARALLEL(SKYRAID_R27, SKYRAID_R28)),
		SKYRAID_C93)
	/* IC E10, pin 1 gain and clipping */
	DISCRETE_GAIN(NODE_94, NODE_93, - SKYRAID_R118 / (SKYRAID_R122 + RES_5_PARALLEL(SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31)))
	DISCRETE_CLAMP(NODE_95, NODE_94, -5, 12.0 - 1.5)
	DISCRETE_OUTPUT(NODE_95, 32700.0/8)
DISCRETE_SOUND_END


WRITE8_DEVICE_HANDLER( skyraid_sound_w )
{
	/* BIT0 => PLANE SWEEP */
	/* BIT1 => MISSILE     */
	/* BIT2 => EXPLOSION   */
	/* BIT3 => START LAMP  */
	/* BIT4 => PLANE ON    */
	/* BIT5 => ATTRACT     */

	discrete_sound_w(device, SKYRAID_PLANE_SWEEP_EN, data & 0x01);
	discrete_sound_w(device, SKYRAID_MISSILE_EN, data & 0x02);
	discrete_sound_w(device, SKYRAID_EXPLOSION_EN, data & 0x04);
	set_led_status(device->machine, 0, !(data & 0x08));
	discrete_sound_w(device, SKYRAID_PLANE_ON_EN, data & 0x10);
	discrete_sound_w(device, SKYRAID_ATTRACT_EN, data & 0x20);
}