summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/asteroid.cpp
blob: 6c8b04000701970f664bb4d2b720dbef13790a42 (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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
// license:BSD-3-Clause
// copyright-holders:K.Wilkins
/*****************************************************************************
 *
 * Asteroids Analog Sound system interface
 *
 *****************************************************************************/

#include "emu.h"
#include "includes/asteroid.h"
#include "machine/74259.h"
#include "speaker.h"

/************************************************************************/
/* Asteroids Sound System Analog emulation by K.Wilkins Nov 2000        */
/* Questions/Suggestions to mame@esplexo.co.uk                          */
/************************************************************************/

static const discrete_lfsr_desc asteroid_lfsr =
{
	DISC_CLK_IS_FREQ,
	16,         /* Bit Length */
	0,          /* Reset Value */
	6,          /* Use Bit 6 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 */
	0,          /* Output is already inverted by XNOR */
	16          /* Output bit is feedback bit */
};

static const discrete_dac_r1_ladder asteroid_thump_dac1 =
{
	4,          // size of ladder
	{RES_K(220), RES_K(100), RES_K(47), RES_K(22)}, //R44-R47
	4.3,        // 5v - diode junction
	RES_K(6.8), // R49
	RES_K(47),  // R44
	CAP_U(0.01) // C27
};

static const discrete_555_cc_desc asteroid_thump_555cc =
{
	DISC_555_OUT_SQW | DISC_555_OUT_AC | DISCRETE_555_CC_TO_CAP,
	5,      // B+ voltage of 555
	DEFAULT_555_VALUES,
	0.8     // VBE 2N3906 (Si)
};

#define ASTEROID_SAUCER_SND_EN      NODE_01
#define ASTEROID_SAUCER_FIRE_EN     NODE_02
#define ASTEROID_SAUCER_SEL         NODE_03
#define ASTEROID_THRUST_EN          NODE_04
#define ASTEROID_SHIP_FIRE_EN       NODE_05
#define ASTEROID_LIFE_EN            NODE_06
#define ASTEROID_NOISE_RESET        NODE_07

#define ASTEROID_THUMP_EN           NODE_08
#define ASTEROID_THUMP_DATA         NODE_09
#define ASTEROID_EXPLODE_DATA       NODE_10
#define ASTEROID_EXPLODE_PITCH      NODE_11

#define ASTEROID_NOISE              NODE_20
#define ASTEROID_THUMP_SND          NODE_21
#define ASTEROID_SAUCER_SND         NODE_22
#define ASTEROID_LIFE_SND           NODE_23
#define ASTEROID_SAUCER_FIRE_SND    NODE_24
#define ASTEROID_SHIP_FIRE_SND      NODE_25
#define ASTEROID_EXPLODE_SND        NODE_26
#define ASTEROID_THRUST_SND         NODE_27

static DISCRETE_SOUND_START(asteroid)
	/************************************************/
	/* Asteroid Effects Relataive Gain Table        */
	/*                                              */
	/* Effect       V-ampIn   Gain ratio  Relative  */
	/* Thump         5        1/47          131.6   */
	/* Saucer        2.4      1/39           76.1   */
	/* Life          3.8      1/47          100.0   */
	/* Saucer Fire   5-0.6    1/(100+10)     49.5   */
	/* Ship Fire     5-0.6    1/(100+2.7)    53.0   */
	/* Explode       3.8      1/4.7        1000.0   */
	/* Thrust        3.8      1/4.7         600.0   */
	/*  NOTE: Thrust gain has to be tweaked, due to */
	/*        the filter stage.                     */
	/************************************************/

	/*                        NODE                 GAIN        OFFSET  INIT */
	DISCRETE_INPUT_LOGIC (ASTEROID_SAUCER_SND_EN)
	DISCRETE_INPUT_LOGIC (ASTEROID_SAUCER_FIRE_EN)
	DISCRETE_INPUT_LOGIC (ASTEROID_SAUCER_SEL)
	DISCRETE_INPUT_LOGIC (ASTEROID_THRUST_EN)
	DISCRETE_INPUT_LOGIC (ASTEROID_SHIP_FIRE_EN)
	DISCRETE_INPUT_LOGIC (ASTEROID_LIFE_EN)
	DISCRETE_INPUT_PULSE (ASTEROID_NOISE_RESET, 1)

	DISCRETE_INPUT_LOGIC (ASTEROID_THUMP_EN)
	DISCRETE_INPUT_DATA  (ASTEROID_THUMP_DATA)

	DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_DATA, 1000.0/15.0,   0.0,   0)
	DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_PITCH, 1,            0,     12)

	/************************************************/
	/* Thump circuit is based on a VCO with the     */
	/* VCO control fed from the 4 low order bits    */
	/* from /THUMP bit 4 controls the osc enable.   */
	/* A resistor ladder network is used to convert */
	/* the 4 bit value to an analog value.          */
	/*                                              */
	/* The VCO is implemented with a 555 timer and  */
	/* an RC filter to perform smoothing on the     */
	/* output                                       */
	/************************************************/
	DISCRETE_DAC_R1(NODE_30, ASTEROID_THUMP_DATA, 3.5, &asteroid_thump_dac1) // CMOS
	DISCRETE_555_CC(NODE_31, ASTEROID_THUMP_EN, NODE_30, RES_K(22), CAP_U(0.22), 0, 0, RES_K(18), &asteroid_thump_555cc)
	DISCRETE_RCFILTER(NODE_32, NODE_31, RES_K(3.3), CAP_U(0.1))
	DISCRETE_GAIN(ASTEROID_THUMP_SND, NODE_32, 30)

	/************************************************/
	/* The SAUCER sound is based on two VCOs, a     */
	/* slow VCO feed the input to a higher freq VCO */
	/* with the SAUCERSEL switch being used to move */
	/* the frequency ranges of both VCOs            */
	/*                                              */
	/* The slow VCO is implemented with a 555 timer */
	/* and a 566 is used for the higher VCO.        */
	/*                                              */
	/* The sound can be tweaked with the gain and   */
	/* adder constants in the 2 lines below         */
	/************************************************/
	// SAUCER_SEL = 1 - larger saucer
	DISCRETE_MULTADD(NODE_40, ASTEROID_SAUCER_SEL, -2.5, 8.25)  // Saucer Warble rate (5.75 or 8.25Hz)
	DISCRETE_TRIANGLEWAVE(NODE_41, 1, NODE_40, 920.0, 920.0/2, 0)   // (amount of warble)

	DISCRETE_TRANSFORM4(NODE_42, ASTEROID_SAUCER_SEL, -250, NODE_41, 750, "01*2+3+")    // Large saucer is 250hz lower

	DISCRETE_TRIANGLEWAVE(NODE_43, ASTEROID_SAUCER_SND_EN, NODE_42, 76.1, 0, 0)
	DISCRETE_RCFILTER(ASTEROID_SAUCER_SND, NODE_43, 1, 1.0e-5)

	/************************************************/
	/* The Ship Fire sound is produced by a 555     */
	/* based VCO where the frequency rapidly decays */
	/* with time.                                   */
	/************************************************/
	DISCRETE_RAMP(NODE_50, ASTEROID_SHIP_FIRE_EN, ASTEROID_SHIP_FIRE_EN, (820.0-110.0)/0.28, 820.0, 110.0, 0)   /* Decay - Freq */
	DISCRETE_RCDISC(NODE_51, ASTEROID_SHIP_FIRE_EN, 53.0-7.0, 2700.0*3, 1e-5)   /* Decay - Amplitude */
	DISCRETE_ADDER2(NODE_52, 1, NODE_51, 7.0)   /* Amplitude */
	DISCRETE_TRANSFORM3(NODE_53, 4500, NODE_50, 67, "01/2+")    /* Duty */
	DISCRETE_SQUAREWAVE(NODE_54, ASTEROID_SHIP_FIRE_EN, NODE_50, NODE_52, NODE_53, 0, 0)
	DISCRETE_RCFILTER(ASTEROID_SHIP_FIRE_SND, NODE_54, 1, 1.0e-5)

	/************************************************/
	/* The Saucer Fire sound is produced by a 555   */
	/* based VCO where the frequency rapidly decays */
	/* with time.                                   */
	/************************************************/
	DISCRETE_RAMP(NODE_60, ASTEROID_SAUCER_FIRE_EN, ASTEROID_SAUCER_FIRE_EN, (830.0-630.0)/0.28, 830.0, 630.0, 0)   /* Decay - Freq */
	DISCRETE_RCDISC(NODE_61, ASTEROID_SAUCER_FIRE_EN, 49.5-7.0, 10000.0*3, 1e-5)    /* Decay - Amplitude */
	DISCRETE_ADDER2(NODE_62, 1, NODE_61, 7.0)   /* Amplitude */
	DISCRETE_TRANSFORM3(NODE_63, 4500, NODE_60, 67, "01/2+")    /* Duty */
	DISCRETE_SQUAREWAVE(NODE_64, ASTEROID_SAUCER_FIRE_EN, NODE_60, NODE_62, NODE_63, 0, 0)
	DISCRETE_RCFILTER(ASTEROID_SAUCER_FIRE_SND, NODE_64, 2, 1.0e-5)

	/************************************************/
	/* Thrust noise is a gated noise source         */
	/* fed into a filter network                    */
	/* It is an RC lowpass, followed by a           */
	/* Sallen-Key bandpass, followed by an active   */
	/* lowpass.                                     */
	/************************************************/
	DISCRETE_LFSR_NOISE(ASTEROID_NOISE, ASTEROID_NOISE_RESET, ASTEROID_NOISE_RESET, 12000.0, 1.0, 0, 0, &asteroid_lfsr)

	DISCRETE_GAIN(NODE_70, ASTEROID_NOISE, 600.0*7.6)
	DISCRETE_RCFILTER(NODE_71, NODE_70, 2200, 1e-6)
	DISCRETE_MULTIPLY(NODE_72, NODE_71, ASTEROID_THRUST_EN)
	/* TBD - replace this line with a Sallen-Key Bandpass macro */
	DISCRETE_FILTER2(NODE_73, 1, NODE_72, 89.5, (1.0 / 7.6), DISC_FILTER_BANDPASS)
	/* TBD - replace this line with a Active Lowpass macro */
	DISCRETE_FILTER1(ASTEROID_THRUST_SND, 1, NODE_73, 160, DISC_FILTER_LOWPASS)

	/************************************************/
	/* Explosion generation circuit, pitch and vol  */
	/* are variable.                                */
	/* The pitch divides using an overflow counter. */
	/* Meaning the duty cycle varies.  The on time  */
	/* is always the same (one 12Khz cycle).  But   */
	/* the off time varies.  /12 = 11 off cycles    */
	/* Then it is ANDed with the 12kHz to make a    */
	/* shorter pulse.  There is no real reason to   */
	/* do this, as the D-Latch already triggers on  */
	/* the rising edge.  So we won't add the extra  */
	/* nodes.                                       */
	/************************************************/
	DISCRETE_DIVIDE(NODE_80, 1, 12000, ASTEROID_EXPLODE_PITCH)      /* Frequency */
	DISCRETE_DIVIDE(NODE_81, 1, 100, ASTEROID_EXPLODE_PITCH)        /* Duty */
	DISCRETE_SQUAREWFIX(NODE_82, 1, NODE_80, 1.0, NODE_81, 1.0/2, 0)    /* Pitch clock */
	DISCRETE_SAMPLHOLD(NODE_83, ASTEROID_NOISE, NODE_82, DISC_SAMPHOLD_REDGE)
	DISCRETE_MULTIPLY(NODE_84, NODE_83, ASTEROID_EXPLODE_DATA)
	DISCRETE_RCFILTER(ASTEROID_EXPLODE_SND, NODE_84, 3042, 1e-6)

	/************************************************/
	/* Life enable is just 3KHz tone from the clock */
	/* generation cct according to schematics       */
	/************************************************/
	DISCRETE_SQUAREWFIX(ASTEROID_LIFE_SND, ASTEROID_LIFE_EN, 3000, 100.0, 50.0, 0, 0)

	/************************************************/
	/* Combine all 7 sound sources with a double    */
	/* adder circuit                                */
	/************************************************/
	DISCRETE_ADDER4(NODE_90, 1, ASTEROID_THUMP_SND, ASTEROID_SAUCER_SND, ASTEROID_SHIP_FIRE_SND, ASTEROID_SAUCER_FIRE_SND)
	DISCRETE_ADDER4(NODE_91, 1, ASTEROID_THRUST_SND, ASTEROID_EXPLODE_SND, ASTEROID_LIFE_SND, NODE_90)

	DISCRETE_OUTPUT(NODE_91, 65534.0 / (131.6+76.1+49.5+53.0+1000.0+600.0))     // Take the output from the mixer
DISCRETE_SOUND_END


static DISCRETE_SOUND_START(astdelux)
	/************************************************/
	/* Asteroid delux sound hardware is mostly done */
	/* in the Pokey chip except for the thrust and  */
	/* explosion sounds that are a direct lift of   */
	/* the asteroids hardware hence is a clone of   */
	/* the circuit above apart from gain scaling.   */
	/*                                              */
	/* Note that the thrust enable signal is invert */
	/************************************************/
	/*                         NODE                GAIN        OFFSET  INIT */
	DISCRETE_INPUT_LOGIC (ASTEROID_THRUST_EN)
	DISCRETE_INPUT_PULSE (ASTEROID_NOISE_RESET, 1)

	DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_DATA, 1000.0/15.0,   0.0,   0)
	DISCRETE_INPUTX_DATA (ASTEROID_EXPLODE_PITCH, 1,            0,     12)

	/************************************************/
	/* Thrust noise is a gated noise source         */
	/* fed into a filter network                    */
	/* It is an RC lowpass, followed by a           */
	/* Sallen-Key bandpass, followed by an active   */
	/* lowpass.                                     */
	/************************************************/
	DISCRETE_LFSR_NOISE(ASTEROID_NOISE, ASTEROID_NOISE_RESET, ASTEROID_NOISE_RESET, 12000.0, 1.0, 0, 0, &asteroid_lfsr)

	DISCRETE_GAIN(NODE_70, ASTEROID_NOISE, 1000.0*7.6)
	DISCRETE_RCFILTER(NODE_71, NODE_70, 2200, 1e-6)
	DISCRETE_MULTIPLY(NODE_72, NODE_71, ASTEROID_THRUST_EN)
	/* TBD - replace this line with a Sallen-Key Bandpass macro */
	DISCRETE_FILTER2(NODE_73, 1, NODE_72, 89.5, (1.0 / 7.6), DISC_FILTER_BANDPASS)
	/* TBD - replace this line with a Active Lowpass macro */
	DISCRETE_FILTER1(ASTEROID_THRUST_SND, 1, NODE_73, 160, DISC_FILTER_LOWPASS)

	/************************************************/
	/* Explosion generation circuit, pitch and vol  */
	/* are variable.                                */
	/* The pitch divides using an overflow counter. */
	/* Meaning the duty cycle varies.  The on time  */
	/* is always the same (one 12Khz cycle).  But   */
	/* the off time varies.  /12 = 11 off cycles    */
	/* Then it is ANDed with the 12kHz to make a    */
	/* shorter pulse.  There is no real reason to   */
	/* do this, as the D-Latch already triggers on  */
	/* the rising edge.  So we won't add the extra  */
	/* nodes.                                       */
	/************************************************/
	DISCRETE_DIVIDE(NODE_80, 1, 12000, ASTEROID_EXPLODE_PITCH)      /* Frequency */
	DISCRETE_DIVIDE(NODE_81, 1, 100, ASTEROID_EXPLODE_PITCH)        /* Duty */
	DISCRETE_SQUAREWFIX(NODE_82, 1, NODE_80, 1.0, NODE_81, 1.0/2, 0)    /* Pitch clock */
	DISCRETE_SAMPLHOLD(NODE_83, ASTEROID_NOISE, NODE_82, DISC_SAMPHOLD_REDGE)
	DISCRETE_MULTIPLY(NODE_84, NODE_83, ASTEROID_EXPLODE_DATA)
	DISCRETE_RCFILTER(ASTEROID_EXPLODE_SND, NODE_84, 3042, 1e-6)

	/************************************************/
	/* Combine all 7 sound sources with a double    */
	/* adder circuit                                */
	/************************************************/
	DISCRETE_ADDER2(NODE_90, 1, ASTEROID_THRUST_SND, ASTEROID_EXPLODE_SND)

	DISCRETE_OUTPUT(NODE_90, 65534.0/(1000+600))    // Take the output from the mixer
DISCRETE_SOUND_END


WRITE8_MEMBER(asteroid_state::asteroid_explode_w)
{
	m_discrete->write(space,ASTEROID_EXPLODE_DATA,(data&0x3c)>>2);                // Volume
	/* We will modify the pitch data to send the divider value. */
	switch ((data&0xc0))
	{
		case 0x00:
			data = 12;
			break;
		case 0x40:
			data = 6;
			break;
		case 0x80:
			data = 3;
			break;
		case 0xc0:
			data = 5;
			break;
	}
	m_discrete->write(space, ASTEROID_EXPLODE_PITCH, data);
}

WRITE8_MEMBER(asteroid_state::asteroid_thump_w)
{
	m_discrete->write(space, ASTEROID_THUMP_EN,   data & 0x10);
	m_discrete->write(space, ASTEROID_THUMP_DATA, data & 0x0f);
}

WRITE8_MEMBER(asteroid_state::asteroid_noise_reset_w)
{
	m_discrete->write(space, ASTEROID_NOISE_RESET, 0);
}


MACHINE_CONFIG_START(asteroid_state::asteroid_sound)
	MCFG_SPEAKER_STANDARD_MONO("mono")

	MCFG_SOUND_ADD("discrete", DISCRETE, 0)
	MCFG_DISCRETE_INTF(asteroid)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.4)

	MCFG_DEVICE_ADD("audiolatch", LS259, 0) // M10
	MCFG_ADDRESSABLE_LATCH_Q0_OUT_CB(DEVWRITELINE("discrete", discrete_device, write_line<ASTEROID_SAUCER_SND_EN>))
	MCFG_ADDRESSABLE_LATCH_Q1_OUT_CB(DEVWRITELINE("discrete", discrete_device, write_line<ASTEROID_SAUCER_FIRE_EN>))
	MCFG_ADDRESSABLE_LATCH_Q2_OUT_CB(DEVWRITELINE("discrete", discrete_device, write_line<ASTEROID_SAUCER_SEL>))
	MCFG_ADDRESSABLE_LATCH_Q3_OUT_CB(DEVWRITELINE("discrete", discrete_device, write_line<ASTEROID_THRUST_EN>))
	MCFG_ADDRESSABLE_LATCH_Q4_OUT_CB(DEVWRITELINE("discrete", discrete_device, write_line<ASTEROID_SHIP_FIRE_EN>))
	MCFG_ADDRESSABLE_LATCH_Q5_OUT_CB(DEVWRITELINE("discrete", discrete_device, write_line<ASTEROID_LIFE_EN>))
MACHINE_CONFIG_END


MACHINE_CONFIG_START(asteroid_state::astdelux_sound)
	MCFG_SPEAKER_STANDARD_MONO("mono")

	MCFG_SOUND_ADD("discrete", DISCRETE, 0)
	MCFG_DISCRETE_INTF(astdelux)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)

	MCFG_DEVICE_ADD("audiolatch", LS259, 0) // M10
	MCFG_ADDRESSABLE_LATCH_Q3_OUT_CB(DEVWRITELINE("discrete", discrete_device, write_line<ASTEROID_THRUST_EN>))
MACHINE_CONFIG_END