summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/skyraid.cpp
blob: d18e0a75cbf48a6f2ea52c23efbb07c1ed3131eb (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
// license:BSD-3-Clause
// copyright-holders:Derrick Renaud
/************************************************************************
 * skyraid Sound System Analog emulation
 * Sept 2009, Derrick Renaud
 ************************************************************************/

#include "emu.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)

DISCRETE_CLASS_STEP_RESET(skyraid_missle_custom_charge, 2,
		double m_v_charge[2];
		double m_v_cap;
		double m_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)

DISCRETE_STEP( skyraid_missle_custom_charge )
{
	int in_1 = (SKYRAID_MISSLE_CUSTOM_IN1 == 0) ? 0 : 1;

	/* charge/discharge cap */
	m_v_cap += (m_v_charge[in_1] - m_v_cap) * m_exp[in_1];

	set_output(0,  SKYRAID_MISSLE_CHARGE_PLUS - m_v_cap);
}

DISCRETE_RESET( skyraid_missle_custom_charge )
{
	/* everything is based on the input to the O.C. inverter */

	/* the charging voltage across the cap */
	m_v_charge[0] = 0;
	m_v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS * RES_VOLTAGE_DIVIDER(SKYRAID_MISSLE_CUSTOM_R1 + SKYRAID_MISSLE_CUSTOM_R2, SKYRAID_MISSLE_CUSTOM_R3);
	m_v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS - m_v_charge[1];
	m_v_cap = 0;

	/* precalculate charging exponents */
	/* discharge cap */
	m_exp[0] = RC_CHARGE_EXP(SKYRAID_MISSLE_CUSTOM_R2 * SKYRAID_MISSLE_CUSTOM_C);
	/* charge cap */
	m_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 */
	set_output(0,  SKYRAID_MISSLE_CHARGE_PLUS);
}



DISCRETE_SOUND_START( skyraid_discrete )
	/************************************************
	 * 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_missle_custom_charge, SKYRAID_MISSILE_EN, SKYRAID_R12, SKYRAID_R14, SKYRAID_R13, SKYRAID_C44, nullptr)
	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_MEMBER(skyraid_state::skyraid_sound_w)
{
	/* BIT0 => PLANE SWEEP */
	/* BIT1 => MISSILE     */
	/* BIT2 => EXPLOSION   */
	/* BIT3 => START LAMP  */
	/* BIT4 => PLANE ON    */
	/* BIT5 => ATTRACT     */

	m_discrete->write(SKYRAID_PLANE_SWEEP_EN, data & 0x01);
	m_discrete->write(SKYRAID_MISSILE_EN, data & 0x02);
	m_discrete->write(SKYRAID_EXPLOSION_EN, data & 0x04);
	m_led = !BIT(data, 3);
	m_discrete->write(SKYRAID_PLANE_ON_EN, data & 0x10);
	m_discrete->write(SKYRAID_ATTRACT_EN, data & 0x20);
}