summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/madalien.cpp
blob: 59990445d3e1ca49aa1393bef3365b185a25026b (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
// license:BSD-3-Clause
// copyright-holders:Derrick Renaud
/************************************************************************
 * madalien Sound System Analog emulation
 * Aug 2008, Derrick Renaud
 ************************************************************************/

#include "emu.h"
#include "includes/madalien.h"
#include "sound/discrete.h"


/* Discrete Sound Input Nodes */
/* see also "madalien.h" */
#define MADALIEN_8910_PORTA_1       NODE_03
#define MADALIEN_8910_PORTA_2       NODE_04
#define MADALIEN_8910_PORTA_3       NODE_05
#define MADALIEN_8910_PORTA_4       NODE_06
#define MADALIEN_8910_PORTA_5       NODE_07
#define MADALIEN_8910_PORTA_6       NODE_08
#define MADALIEN_8910_PORTA_8       NODE_09

#define MADALIEN_8910_PORTB_1       NODE_10
#define MADALIEN_8910_PORTB_23      NODE_11
#define MADALIEN_8910_PORTB_45      NODE_12
#define MADALIEN_8910_PORTB_6       NODE_13
#define MADALIEN_8910_PORTB_7       NODE_14

#define MADALIEN_8910_PSG_A         NODE_15
#define MADALIEN_8910_PSG_B         NODE_16
#define MADALIEN_8910_PSG_C         NODE_17


static const discrete_op_amp_filt_info madalien_psg_a_filter =
{
	RES_K(1)+ 270, 0, RES_K(10), 0, RES_K(100), CAP_U(.1), CAP_U(.1), 0, 0, 5, -5
};

static const discrete_op_amp_filt_info madalien_psg_c_filter =
{
	RES_K(1)+ 270, 0, RES_K(10), 0, RES_K(100), CAP_U(.068), CAP_U(.068), 0, 0, 5, -5
};

static const discrete_mixer_desc madalien_psg_mix =
{
	DISC_MIXER_IS_RESISTOR,
	{RES_K(10), RES_K(10), RES_K(10)},
	{0}, {0}, 0, 0, 0, 0, 0, 1
};

static const discrete_555_desc madalien_555_1f =
{
	// the 555 will clock a 74161, which counts on rising edges
	DISC_555_TRIGGER_IS_LOGIC | DISC_555_OUT_DC | DISC_555_OUT_COUNT_R_X,
	5.0-.5,     // B+ voltage of 555 - diode drop
	DEFAULT_555_VALUES
};

static const discrete_555_desc madalien_555_1c =
{
	// the 555 will clock a 74161, which counts on rising edges
	DISC_555_TRIGGER_IS_LOGIC | DISC_555_OUT_DC | DISC_555_OUT_COUNT_R_X,
	5,      // B+ voltage of 555
	DEFAULT_555_VALUES
};

static const discrete_555_desc madalien_555_1l =
{
	DISC_555_TRIGGER_IS_LOGIC | DISC_555_OUT_DC | DISC_555_OUT_CAP,
	5,      // B+ voltage of 555
	DEFAULT_555_VALUES
};

static const discrete_comp_adder_table madalien_555_1f_r_select =
{
	DISC_COMP_P_RESISTOR, 0, 2,
	{RES_K(22+1), RES_K(15+1)}
};

static const discrete_comp_adder_table madalien_effect_1b_vol_r =
{
	DISC_COMP_P_RESISTOR, 0, 2,
	{270, RES_K(22) + 270}
};

static const discrete_dac_r1_ladder madalien_effect1a_dac =
{
	4,
	{RES_K(22), RES_K(22), 0, RES_K(22)},
	0, 0, 0, 0
};

static const discrete_dac_r1_ladder madalien_effect1b_dac =
{
	2,
	{RES_K(22), RES_K(22)},
	0, 0, 0, 0
};

static const discrete_dac_r1_ladder madalien_effect2_dac =
{
	4,
	{0, RES_K(33), RES_K(22), RES_K(33)},
	0, 0, 0, 0
};

// resistor effect of 555 internal resistors at pin 5
static const discrete_mixer_desc madalien_555_1c_cv =
{
	DISC_MIXER_IS_RESISTOR,
	{RES_K(1.5), RES_K(5)},
	{0}, {0}, 0, RES_K(10), 0, 0, 0, 1
};

static const discrete_mixer_desc madalien_final_mix =
{
	DISC_MIXER_IS_RESISTOR,
	{RES_K(10), RES_K(10)/3, RES_K(10), RES_K(10),
		RES_K(22) + RES_K(22)/3,
		RES_K(22) + RES_K(22) + RES_K(22)/2,
		RES_K(33) + 1.0 / (1.0/RES_K(33) + 1.0/RES_K(22) + 1.0/RES_K(33))},
	{MADALIEN_8910_PORTA_1, 0, MADALIEN_8910_PORTA_5, MADALIEN_8910_PORTA_8, MADALIEN_8910_PORTB_1, NODE_59, 0},
	{0}, 0,
	RES_K(100),
	0, CAP_U(1), 0,
	32768.0/DEFAULT_TTL_V_LOGIC_1   // final gain
};

DISCRETE_SOUND_START( madalien )
	/************************************************
	 * Input register mapping
	 ************************************************/
	DISCRETE_INPUT_DATA(MADALIEN_8910_PORTA)
	DISCRETE_INPUT_DATA(MADALIEN_8910_PORTB)

	/************************************************
	 * Convert to individual bits
	 ************************************************/
	// Port A is used to turn filtering on/off.
	// 1 - player shot, siren, music
	// turn bit into 4066 Ron value of 270 ohms @ 5V
	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTA_1, MADALIEN_8910_PORTA, 0x01, 270, "01&2*")
	// 2 - player explosion
	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_2, MADALIEN_8910_PORTA, 0x02, "01&")
	// 3 - rub wall
	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_3, MADALIEN_8910_PORTA, 0x04, "01&")
	// 4 - is it even triggered?
	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_4, MADALIEN_8910_PORTA, 0x08, "01&")
	// 5 - siren, music (out of phase copy of 1 for echo effect)
	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTA_5, MADALIEN_8910_PORTA, 0x10, 270, "01&2*")
	// 6 - enemy explosions
	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_6, MADALIEN_8910_PORTA, 0x20, "01&")
	// 8 - enemy spin, beep
	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTA_8, MADALIEN_8910_PORTA, 0x80, 270, "01&2*")

	//Port B controls motor sounds
	// 1,2,3 - Player motor volume
	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_1,  MADALIEN_8910_PORTB, 0x01, 270, "01&2*")
	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_23, MADALIEN_8910_PORTB, 0x06, 2, "01&2/")
	// 4,5 - Player motor speed
	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_45, MADALIEN_8910_PORTB, 0x18, 8, "01&2/")
	// 6 - Enemy motor enable
	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTB_6,  MADALIEN_8910_PORTB, 0x20, "01&")
	// 7 - Enemy motor speed
	// convert bit 7 to voltage level
	// 2 diodes reduce voltage by 1V.
	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_7, MADALIEN_8910_PORTB, 0x40, (DEFAULT_TTL_V_LOGIC_1 - 1) / 0x40, "01&2*")

	/************************************************
	 * PSG input streams
	 ************************************************/
	// AY-3-8910 PSG have a 1Vpp level
	DISCRETE_INPUTX_STREAM(MADALIEN_8910_PSG_A, 0, 2.0/32768, .250)
	DISCRETE_INPUTX_STREAM(MADALIEN_8910_PSG_B, 1, 2.0/32768, .250)
	DISCRETE_INPUTX_STREAM(MADALIEN_8910_PSG_C, 2, 2.0/32768, .250)

	/************************************************
	 * AY-3-8910 filtering
	 ************************************************/
	// top op-amp
	DISCRETE_ONOFF(NODE_20, MADALIEN_8910_PORTA_2, MADALIEN_8910_PSG_A)
	DISCRETE_OP_AMP_FILTER(NODE_21, 1, NODE_20, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &madalien_psg_a_filter)

	// middle op-amp
	// pin 3
	DISCRETE_MULTIPLY(NODE_30, MADALIEN_8910_PSG_B, RES_K(3.3)/(RES_K(3.3)+RES_K(3.3)))
	DISCRETE_ONOFF(NODE_31, MADALIEN_8910_PORTA_4, NODE_30)
	// pin 2
	DISCRETE_TRANSFORM3(NODE_32, MADALIEN_8910_PSG_A, NODE_30, -RES_K(10)/RES_K(3.3), "01-2*1+")
	// pin 1
	DISCRETE_SWITCH(NODE_33, 1, MADALIEN_8910_PORTA_3, NODE_31, NODE_32)
	DISCRETE_CLAMP(NODE_34, NODE_33, -5, 5.0-1.5)

	// bottom op-amp
	DISCRETE_ONOFF(NODE_40, MADALIEN_8910_PORTA_6, MADALIEN_8910_PSG_B)
	DISCRETE_OP_AMP_FILTER(NODE_41, 1, NODE_40, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &madalien_psg_c_filter)

	DISCRETE_MIXER3(NODE_48, 1, NODE_21, NODE_33, NODE_41, &madalien_psg_mix)

	/************************************************
	 * Player motor
	 ************************************************/
	DISCRETE_555_ASTABLE(NODE_50,   // cap is buffered by op-amp 2D.
		1,                          // always enabled
		RES_K(4.7),
		RES_K(22),
		CAP_U(2.2),
		&madalien_555_1l)
	// The speed frequencies seem strange but the components have been GuruVerified
	// There is not much change in selected frequency.  99Hz, 110.6Hz, 124Hz
	DISCRETE_COMP_ADDER(NODE_51, MADALIEN_8910_PORTB_45, &madalien_555_1f_r_select)
	DISCRETE_555_ASTABLE_CV(NODE_52,    // IC 1F pin 3 out
		MADALIEN_8910_PORTB_45,         // enabled by gate O2 pin 13
		NODE_51,
		RES_K(10),                      // per actual board
		CAP_U(.22),
		NODE_50,                        // IC 1F pin 5 in
		&madalien_555_1f)
	// convert reset to active high for module use
	DISCRETE_LOGIC_INVERT(NODE_53, MADALIEN_8910_PORTB_45)
	DISCRETE_COUNTER(NODE_54, 1,
		NODE_53,                        // pin 7 in
		NODE_52,                        // pin 1 in
		0, 15, 1, 0, DISC_CLK_BY_COUNT) // 4-bit binary up counter
	DISCRETE_DAC_R1(NODE_55, NODE_54, DEFAULT_TTL_V_LOGIC_1, &madalien_effect1a_dac)
	DISCRETE_DAC_R1(NODE_56, NODE_54, DEFAULT_TTL_V_LOGIC_1, &madalien_effect1b_dac)
	DISCRETE_RCFILTER(NODE_57, NODE_56, RES_K(22)/2 + RES_K(22), CAP_U(.033))
	DISCRETE_COMP_ADDER(NODE_59, MADALIEN_8910_PORTB_23, &madalien_effect_1b_vol_r)

	/************************************************
	 * Enemy motor
	 ************************************************/
	DISCRETE_CRFILTER(NODE_60, MADALIEN_8910_PORTB_7, RES_K(100), CAP_U(4.7))
	// 2 diodes clamp it positive.
	DISCRETE_CLAMP(NODE_62, NODE_60, 0, 12)
	// the 0.047uF cap to ground just removes real world spikes.
	// it does not have to be simulated.
	DISCRETE_MIXER2(NODE_64, 1, NODE_62, 5, &madalien_555_1c_cv)
	DISCRETE_555_ASTABLE_CV(NODE_65,    // IC 1C pin 3 out
		MADALIEN_8910_PORTB_6,
		RES_K(47),
		RES_K(22),
		CAP_U(.033),
		NODE_64,                        // IC 1C pin 5 in
		&madalien_555_1c)
	// convert reset to active high for module use
	DISCRETE_LOGIC_INVERT(NODE_66, MADALIEN_8910_PORTB_6)
	DISCRETE_COUNTER(NODE_67, 1,
		NODE_66,                        // pin 7 in
		NODE_65,                        // pin 1 in
		0, 15, 1, 0, DISC_CLK_BY_COUNT) // 4-bit binary up counter
	DISCRETE_DAC_R1(NODE_68, NODE_67, DEFAULT_TTL_V_LOGIC_1, &madalien_effect2_dac)

	/************************************************
	 * Mixer
	 ************************************************/
	DISCRETE_MIXER7(NODE_90, 1, MADALIEN_8910_PSG_A, NODE_48, MADALIEN_8910_PSG_B, MADALIEN_8910_PSG_C, NODE_56, NODE_57, NODE_68, &madalien_final_mix)

	DISCRETE_OUTPUT(NODE_90, 1.1)

DISCRETE_SOUND_END