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

#include "emu.h"
#include "includes/sprint8.h"

#include "speaker.h"


/* Discrete Sound Input Nodes */
#define SPRINT8_CRASH_EN            NODE_01
#define SPRINT8_SCREECH_EN          NODE_02
#define SPRINT8_ATTRACT_EN          NODE_03
#define SPRINT8_MOTOR1_EN           NODE_04
#define SPRINT8_MOTOR2_EN           NODE_05
#define SPRINT8_MOTOR3_EN           NODE_06
#define SPRINT8_MOTOR4_EN           NODE_07
#define SPRINT8_MOTOR5_EN           NODE_08
#define SPRINT8_MOTOR6_EN           NODE_09
#define SPRINT8_MOTOR7_EN           NODE_10
#define SPRINT8_MOTOR8_EN           NODE_11

/* Discrete Sound Output Nodes */
#define SPRINT8_NOISE               NODE_12
#define SPRINT8_MOTOR1_SND          NODE_13
#define SPRINT8_MOTOR2_SND          NODE_14
#define SPRINT8_MOTOR3_SND          NODE_15
#define SPRINT8_MOTOR4_SND          NODE_16
#define SPRINT8_MOTOR5_SND          NODE_17
#define SPRINT8_MOTOR6_SND          NODE_18
#define SPRINT8_MOTOR7_SND          NODE_19
#define SPRINT8_MOTOR8_SND          NODE_20
#define SPRINT8_CRASH_SCREECH_SND   NODE_21
#define SPRINT8_AUDIO_1_2           NODE_22
#define SPRINT8_AUDIO_3_7           NODE_23
#define SPRINT8_AUDIO_5_6           NODE_24
#define SPRINT8_AUDIO_4_8           NODE_25

/* Adjusters */
#define SPRINT8_R132_POT            NODE_29


/* Parts List - Resistors */
#define SPRINT8_R1      RES_K(47)
#define SPRINT8_R3      RES_K(47)
#define SPRINT8_R4      RES_K(47)
#define SPRINT8_R19     RES_K(1)
#define SPRINT8_R20     RES_K(1)
#define SPRINT8_R27     RES_K(18)
#define SPRINT8_R28     820
#define SPRINT8_R29     RES_K(330)
#define SPRINT8_R39     RES_K(120)
#define SPRINT8_R40     RES_K(22)
#define SPRINT8_R41     RES_K(150)
#define SPRINT8_R89     RES_K(22)
#define SPRINT8_R91     RES_K(47)
#define SPRINT8_R93     RES_K(2.2)
#define SPRINT8_R96     RES_K(47)
#define SPRINT8_R97     RES_K(2.2)
#define SPRINT8_R99     RES_K(27)
#define SPRINT8_R100    RES_K(1)
#define SPRINT8_R101    RES_K(2.2)
#define SPRINT8_R132    RES_K(100)
#define SPRINT8_R145    RES_K(3.3)
#define SPRINT8_R146    RES_K(7.5)
#define SPRINT8_R147    100
#define SPRINT8_R148    RES_K(1)
#define SPRINT8_R149    RES_K(22)

/* Parts List - Capacitors */
#define SPRINT8_C8      CAP_U(.01)
#define SPRINT8_C17     CAP_U(.001)
#define SPRINT8_C18     CAP_U(.047)
#define SPRINT8_C19     CAP_U(.047)
#define SPRINT8_C26     CAP_U(100)
#define SPRINT8_C27     CAP_U(.22)
#define SPRINT8_C28     CAP_U(.1)
#define SPRINT8_C59     CAP_U(.1)
#define SPRINT8_C63     CAP_U(.1)
#define SPRINT8_C64     CAP_U(.1)
#define SPRINT8_C89     CAP_U(.1)
#define SPRINT8_C90     CAP_U(.1)

#define SPRINT8_HSYNC   15750.0     /* not checked */
#define SPRINT8_1V  SPRINT8_HSYNC/2
#define SPRINT8_2V  SPRINT8_1V/2


static const discrete_lfsr_desc sprint8_lfsr =
{
	DISC_CLK_IS_FREQ,
	16,                 /* Bit Length */
	0,                  /* Reset Value */
	10,                 /* Use Bit 10 as XOR input 0 */
	15,                 /* Use Bit 15 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_L,    /* Output is not inverted */
	12                  /* Output bit */
};

static const discrete_555_desc sprint8_crash_555a_desc =
{
	DISC_555_OUT_ENERGY,
	5, DEFAULT_555_VALUES
};

static const discrete_integrate_info sprint8_crash_integrate =
{
	DISC_INTEGRATE_OP_AMP_1,
	SPRINT8_R99, SPRINT8_R97, SPRINT8_R96, SPRINT8_C59,     /*r1, r2, r3, c, */
	5, 5,                           /* v1, vP*/
	0, 0, 0                         /* no functions */
};

static const discrete_555_desc sprint8_motor_555a_desc =
{
	DISC_555_OUT_COUNT_F_X,
	5, DEFAULT_555_VALUES
};

static const discrete_555_desc sprint8_motor_555m_desc =
{
	DISC_555_OUT_ENERGY | DISC_555_TRIGGER_IS_COUNT,
	5, DEFAULT_555_VALUES
};

static const discrete_op_amp_filt_info sprint8_motor_filter =
{
	SPRINT8_R27, 0, SPRINT8_R28 + RES_2_PARALLEL(SPRINT8_R19, SPRINT8_R20), 0, SPRINT8_R29, /* r1, r2, r3, r4, rF, */
	SPRINT8_C18, SPRINT8_C19, 0,                                    /* c1, c2, c3, */
	5.0 * RES_VOLTAGE_DIVIDER(SPRINT8_R19, SPRINT8_R20), 5, 0       /* vRef, vP, vN */
};

static const discrete_mixer_desc sprint8_crash_screech_mixer =
{
	DISC_MIXER_IS_RESISTOR,
	{SPRINT8_R149, SPRINT8_R91},
	{0, NODE_80},                       /* R93 switched in/out of circuit */
	{0}, 0, 0, SPRINT8_C64, 0, 0, 1     /* c, rI, rF, cF, cAmp, vRef, gain */
};

static const discrete_mixer_desc sprint8_mixer =
{
	DISC_MIXER_IS_RESISTOR,
	{SPRINT8_R1 + SPRINT8_R100, SPRINT8_R3, SPRINT8_R4},
	{0}, {0}, 0, 0, 0, SPRINT8_C8, 0, 1     /* r_nodes, c, rI, rF, cF, cAmp, vRef, gain */
};


/************************************************
 * Car Motor
 ************************************************/
/* The first (astable) 555 generates a quick falling pulse that triggers the second (monostable) 555.
 * This pulse is passed through C17 and pulled up with R40.  This pulse is too fast to emulate so
 * we will just tell the monostable it was triggered once and ignore C17/R40.
 */
#define SPRINT8_MOTOR_CIRCUIT(_car)                                                             \
DISCRETE_RCFILTER(NODE_RELATIVE(NODE_30, _car - 1), NODE_RELATIVE(SPRINT8_MOTOR1_EN, _car - 1), SPRINT8_R89, SPRINT8_C26)   \
DISCRETE_ADDER2(NODE_RELATIVE(NODE_40, _car - 1), 1, NODE_RELATIVE(NODE_30, _car - 1), 0.7) /* add Q21 shift */                 \
DISCRETE_555_ASTABLE_CV(NODE_RELATIVE(NODE_50, _car - 1), 1, SPRINT8_R39, 0, SPRINT8_C27, NODE_RELATIVE(NODE_40, _car - 1), &sprint8_motor_555a_desc) \
DISCRETE_555_MSTABLE(NODE_RELATIVE(NODE_60, _car - 1), 1, NODE_RELATIVE(NODE_50, _car - 1), SPRINT8_R41, SPRINT8_C28, &sprint8_motor_555m_desc)       \
DISCRETE_OP_AMP_FILTER(NODE_RELATIVE(SPRINT8_MOTOR1_SND, _car - 1), 1, NODE_RELATIVE(NODE_60, _car - 1), 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &sprint8_motor_filter)


DISCRETE_SOUND_START( sprint8_discrete )
	/************************************************
	 * Input register mapping
	 ************************************************/
	DISCRETE_INPUT_LOGIC(SPRINT8_CRASH_EN)
	DISCRETE_INPUT_NOT  (SPRINT8_SCREECH_EN)
	DISCRETE_INPUT_NOT  (SPRINT8_ATTRACT_EN)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR1_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR2_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR3_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR4_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR5_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR6_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR7_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)
	DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR8_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0)

	DISCRETE_TASK_START(0)
	DISCRETE_ADJUSTMENT(SPRINT8_R132_POT, 0, SPRINT8_R132, DISC_LINADJ, "R132")

	/************************************************
	 * Noise Generator, Crash, Screech
	 ************************************************/
	/* Address line A2 is used to XOR the feedback bits.
	 * This can not easily be implemented, so I just set the
	 * feedback as XNOR. */
	DISCRETE_LFSR_NOISE(SPRINT8_NOISE,          /* IC F7, pin 13 */
		1,                                      /* ENAB */
		SPRINT8_ATTRACT_EN,                     /* RESET */
		SPRINT8_2V, 1, 0, 0.5, &sprint8_lfsr)   /* CLK,AMPL,FEED,BIAS,LFSRTB */

	DISCRETE_TASK_END()

	DISCRETE_TASK_START(1)
	DISCRETE_GAIN(NODE_70, SPRINT8_NOISE, DEFAULT_TTL_V_LOGIC_1 * RES_VOLTAGE_DIVIDER(SPRINT8_R148, SPRINT8_R147))
	DISCRETE_CRFILTER_VREF(NODE_71,
		NODE_70,                                /* IN0 */
		RES_2_PARALLEL(SPRINT8_R148, SPRINT8_R147) + RES_2_PARALLEL(RES_K(5), RES_K(10)),
		SPRINT8_C90,
		5.0 * RES_VOLTAGE_DIVIDER(RES_K(5), RES_K(10)))     /* ref to 555 CV pin */
	DISCRETE_555_ASTABLE_CV(NODE_72,
		SPRINT8_SCREECH_EN,                     /* RESET */
		SPRINT8_R145, SPRINT8_R146, SPRINT8_C89,
		NODE_71,                                /* CTRLV */
		&sprint8_crash_555a_desc)
	DISCRETE_INTEGRATE(NODE_73, SPRINT8_CRASH_EN, 0, &sprint8_crash_integrate)

	DISCRETE_SWITCH(NODE_80,
		1,                                      /* ENAB */
		SPRINT8_NOISE,                          /* SWITCH */
		SPRINT8_R93, 1)                         /* INP0,INP1*/
	DISCRETE_SWITCH(NODE_74,                    /* effect of Q20 */
		1,                                      /* ENAB */
		SPRINT8_NOISE,                          /* SWITCH */
		NODE_73, 0)                             /* INP0,INP1*/
	DISCRETE_MIXER2(NODE_75,
		1,                                      /* ENAB */
		NODE_72,
		NODE_74,
		&sprint8_crash_screech_mixer)

	DISCRETE_CRFILTER_VREF(NODE_76,
		NODE_75,                                /* IN0 */
		SPRINT8_R93 + SPRINT8_R91, SPRINT8_C63,
		5)                                      /* VREF */
	/* IC E5, pin 14 gain.  Does not simulate minor DC offset caused by R93. */
	DISCRETE_TRANSFORM5(NODE_77, NODE_76, 5, SPRINT8_R132_POT, SPRINT8_R101, 1, "01-23/4+*1+")
	DISCRETE_CLAMP(SPRINT8_CRASH_SCREECH_SND, NODE_77, 0, 15.0 - 1.5)
	DISCRETE_TASK_END()

	/************************************************
	 * Car Motor
	 ************************************************/
	DISCRETE_TASK_START(1)
	SPRINT8_MOTOR_CIRCUIT(1)
	SPRINT8_MOTOR_CIRCUIT(2)
	DISCRETE_TASK_END()

	DISCRETE_TASK_START(1)
	SPRINT8_MOTOR_CIRCUIT(3)
	SPRINT8_MOTOR_CIRCUIT(7)
	DISCRETE_TASK_END()

	DISCRETE_TASK_START(1)
	SPRINT8_MOTOR_CIRCUIT(5)
	SPRINT8_MOTOR_CIRCUIT(6)
	DISCRETE_TASK_END()

	DISCRETE_TASK_START(1)
	SPRINT8_MOTOR_CIRCUIT(4)
	SPRINT8_MOTOR_CIRCUIT(8)
	DISCRETE_TASK_END()

	/************************************************
	 * Final Mix
	 ************************************************/
	DISCRETE_TASK_START(2)
	DISCRETE_MIXER3(SPRINT8_AUDIO_1_2,
		SPRINT8_ATTRACT_EN,             /* ENAB */
		SPRINT8_CRASH_SCREECH_SND,
		SPRINT8_MOTOR1_SND,
		SPRINT8_MOTOR2_SND,
		&sprint8_mixer)
	DISCRETE_MIXER3(SPRINT8_AUDIO_3_7,
		SPRINT8_ATTRACT_EN,             /* ENAB */
		SPRINT8_CRASH_SCREECH_SND,
		SPRINT8_MOTOR3_SND,
		SPRINT8_MOTOR7_SND,
		&sprint8_mixer)
	DISCRETE_MIXER3(SPRINT8_AUDIO_5_6,
		SPRINT8_ATTRACT_EN,             /* ENAB */
		SPRINT8_CRASH_SCREECH_SND,
		SPRINT8_MOTOR5_SND,
		SPRINT8_MOTOR6_SND,
		&sprint8_mixer)
	DISCRETE_MIXER3(SPRINT8_AUDIO_4_8,
		SPRINT8_ATTRACT_EN,             /* ENAB */
		SPRINT8_CRASH_SCREECH_SND,
		SPRINT8_MOTOR4_SND,
		SPRINT8_MOTOR8_SND,
		&sprint8_mixer)
	DISCRETE_OUTPUT(SPRINT8_AUDIO_1_2, 65500.0/8)
	DISCRETE_OUTPUT(SPRINT8_AUDIO_3_7, 65500.0/8)
	DISCRETE_OUTPUT(SPRINT8_AUDIO_5_6, 65500.0/8)
	DISCRETE_OUTPUT(SPRINT8_AUDIO_4_8, 65500.0/8)
	DISCRETE_TASK_END()
DISCRETE_SOUND_END

MACHINE_CONFIG_START(sprint8_state::sprint8_audio)
	/* sound hardware */
	/* the proper way is to hook up 4 speakers, but they are not really
	 * F/R/L/R speakers.  Though you can pretend the 1-2 mix is the front. */
	SPEAKER(config, "speaker_1_2", 0.0, 0.0, 1.0);      // front
	SPEAKER(config, "speaker_3_7", -0.2, 0.0, 1.0);     // left
	SPEAKER(config, "speaker_5_6",  0.0, 0.0, -0.5);    // back
	SPEAKER(config, "speaker_4_8", 0.2, 0.0, 1.0);      // right

	MCFG_DEVICE_ADD("discrete", DISCRETE, sprint8_discrete)
	MCFG_SOUND_ROUTE(0, "speaker_1_2", 1.0)
	/* volumes on other channels defaulted to off, */
	/* user can turn them up if needed. */
	/* The game does not sound good with all channels mixed to stereo. */
	MCFG_SOUND_ROUTE(1, "speaker_3_7", 0.0)
	MCFG_SOUND_ROUTE(2, "speaker_5_6", 0.0)
	MCFG_SOUND_ROUTE(3, "speaker_4_8", 0.0)

	MCFG_DEVICE_ADD("latch", F9334, 0)
	MCFG_ADDRESSABLE_LATCH_Q0_OUT_CB(WRITELINE(*this, sprint8_state, int_reset_w))
	MCFG_ADDRESSABLE_LATCH_Q1_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_CRASH_EN>))
	MCFG_ADDRESSABLE_LATCH_Q2_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_SCREECH_EN>))
	MCFG_ADDRESSABLE_LATCH_Q5_OUT_CB(WRITELINE(*this, sprint8_state, team_w))
	MCFG_ADDRESSABLE_LATCH_Q6_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_ATTRACT_EN>))

	MCFG_DEVICE_ADD("motor", F9334, 0)
	MCFG_ADDRESSABLE_LATCH_Q0_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR1_EN>))
	MCFG_ADDRESSABLE_LATCH_Q1_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR2_EN>))
	MCFG_ADDRESSABLE_LATCH_Q2_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR3_EN>))
	MCFG_ADDRESSABLE_LATCH_Q3_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR4_EN>))
	MCFG_ADDRESSABLE_LATCH_Q4_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR5_EN>))
	MCFG_ADDRESSABLE_LATCH_Q5_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR6_EN>))
	MCFG_ADDRESSABLE_LATCH_Q6_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR7_EN>))
	MCFG_ADDRESSABLE_LATCH_Q7_OUT_CB(WRITELINE("discrete", discrete_device, write_line<SPRINT8_MOTOR8_EN>))
MACHINE_CONFIG_END