1 // license:BSD-3-Clause 2 // copyright-holders:Derrick Renaud 3 /************************************************************************ 4 * sprint8 Sound System Analog emulation 5 * Sept 2009, Derrick Renaud 6 ************************************************************************/ 7 8 #include "emu.h" 9 #include "includes/sprint8.h" 10 11 #include "speaker.h" 12 13 14 /* Discrete Sound Input Nodes */ 15 #define SPRINT8_CRASH_EN NODE_01 16 #define SPRINT8_SCREECH_EN NODE_02 17 #define SPRINT8_ATTRACT_EN NODE_03 18 #define SPRINT8_MOTOR1_EN NODE_04 19 #define SPRINT8_MOTOR2_EN NODE_05 20 #define SPRINT8_MOTOR3_EN NODE_06 21 #define SPRINT8_MOTOR4_EN NODE_07 22 #define SPRINT8_MOTOR5_EN NODE_08 23 #define SPRINT8_MOTOR6_EN NODE_09 24 #define SPRINT8_MOTOR7_EN NODE_10 25 #define SPRINT8_MOTOR8_EN NODE_11 26 27 /* Discrete Sound Output Nodes */ 28 #define SPRINT8_NOISE NODE_12 29 #define SPRINT8_MOTOR1_SND NODE_13 30 #define SPRINT8_MOTOR2_SND NODE_14 31 #define SPRINT8_MOTOR3_SND NODE_15 32 #define SPRINT8_MOTOR4_SND NODE_16 33 #define SPRINT8_MOTOR5_SND NODE_17 34 #define SPRINT8_MOTOR6_SND NODE_18 35 #define SPRINT8_MOTOR7_SND NODE_19 36 #define SPRINT8_MOTOR8_SND NODE_20 37 #define SPRINT8_CRASH_SCREECH_SND NODE_21 38 #define SPRINT8_AUDIO_1_2 NODE_22 39 #define SPRINT8_AUDIO_3_7 NODE_23 40 #define SPRINT8_AUDIO_5_6 NODE_24 41 #define SPRINT8_AUDIO_4_8 NODE_25 42 43 /* Adjusters */ 44 #define SPRINT8_R132_POT NODE_29 45 46 47 /* Parts List - Resistors */ 48 #define SPRINT8_R1 RES_K(47) 49 #define SPRINT8_R3 RES_K(47) 50 #define SPRINT8_R4 RES_K(47) 51 #define SPRINT8_R19 RES_K(1) 52 #define SPRINT8_R20 RES_K(1) 53 #define SPRINT8_R27 RES_K(18) 54 #define SPRINT8_R28 820 55 #define SPRINT8_R29 RES_K(330) 56 #define SPRINT8_R39 RES_K(120) 57 #define SPRINT8_R40 RES_K(22) 58 #define SPRINT8_R41 RES_K(150) 59 #define SPRINT8_R89 RES_K(22) 60 #define SPRINT8_R91 RES_K(47) 61 #define SPRINT8_R93 RES_K(2.2) 62 #define SPRINT8_R96 RES_K(47) 63 #define SPRINT8_R97 RES_K(2.2) 64 #define SPRINT8_R99 RES_K(27) 65 #define SPRINT8_R100 RES_K(1) 66 #define SPRINT8_R101 RES_K(2.2) 67 #define SPRINT8_R132 RES_K(100) 68 #define SPRINT8_R145 RES_K(3.3) 69 #define SPRINT8_R146 RES_K(7.5) 70 #define SPRINT8_R147 100 71 #define SPRINT8_R148 RES_K(1) 72 #define SPRINT8_R149 RES_K(22) 73 74 /* Parts List - Capacitors */ 75 #define SPRINT8_C8 CAP_U(.01) 76 #define SPRINT8_C17 CAP_U(.001) 77 #define SPRINT8_C18 CAP_U(.047) 78 #define SPRINT8_C19 CAP_U(.047) 79 #define SPRINT8_C26 CAP_U(100) 80 #define SPRINT8_C27 CAP_U(.22) 81 #define SPRINT8_C28 CAP_U(.1) 82 #define SPRINT8_C59 CAP_U(.1) 83 #define SPRINT8_C63 CAP_U(.1) 84 #define SPRINT8_C64 CAP_U(.1) 85 #define SPRINT8_C89 CAP_U(.1) 86 #define SPRINT8_C90 CAP_U(.1) 87 88 #define SPRINT8_HSYNC 15750.0 /* not checked */ 89 #define SPRINT8_1V SPRINT8_HSYNC/2 90 #define SPRINT8_2V SPRINT8_1V/2 91 92 93 static const discrete_lfsr_desc sprint8_lfsr = 94 { 95 DISC_CLK_IS_FREQ, 96 16, /* Bit Length */ 97 0, /* Reset Value */ 98 10, /* Use Bit 10 as XOR input 0 */ 99 15, /* Use Bit 15 as XOR input 1 */ 100 DISC_LFSR_XNOR, /* Feedback stage1 is XNOR */ 101 DISC_LFSR_OR, /* Feedback stage2 is just stage 1 output OR with external feed */ 102 DISC_LFSR_REPLACE, /* Feedback stage3 replaces the shifted register contents */ 103 0x000001, /* Everything is shifted into the first bit only */ 104 DISC_LFSR_FLAG_RESET_TYPE_L, /* Output is not inverted */ 105 12 /* Output bit */ 106 }; 107 108 static const discrete_555_desc sprint8_crash_555a_desc = 109 { 110 DISC_555_OUT_ENERGY, 111 5, DEFAULT_555_VALUES 112 }; 113 114 static const discrete_integrate_info sprint8_crash_integrate = 115 { 116 DISC_INTEGRATE_OP_AMP_1, 117 SPRINT8_R99, SPRINT8_R97, SPRINT8_R96, SPRINT8_C59, /*r1, r2, r3, c, */ 118 5, 5, /* v1, vP*/ 119 0, 0, 0 /* no functions */ 120 }; 121 122 static const discrete_555_desc sprint8_motor_555a_desc = 123 { 124 DISC_555_OUT_COUNT_F_X, 125 5, DEFAULT_555_VALUES 126 }; 127 128 static const discrete_555_desc sprint8_motor_555m_desc = 129 { 130 DISC_555_OUT_ENERGY | DISC_555_TRIGGER_IS_COUNT, 131 5, DEFAULT_555_VALUES 132 }; 133 134 static const discrete_op_amp_filt_info sprint8_motor_filter = 135 { 136 SPRINT8_R27, 0, SPRINT8_R28 + RES_2_PARALLEL(SPRINT8_R19, SPRINT8_R20), 0, SPRINT8_R29, /* r1, r2, r3, r4, rF, */ 137 SPRINT8_C18, SPRINT8_C19, 0, /* c1, c2, c3, */ 138 5.0 * RES_VOLTAGE_DIVIDER(SPRINT8_R19, SPRINT8_R20), 5, 0 /* vRef, vP, vN */ 139 }; 140 141 static const discrete_mixer_desc sprint8_crash_screech_mixer = 142 { 143 DISC_MIXER_IS_RESISTOR, 144 {SPRINT8_R149, SPRINT8_R91}, 145 {0, NODE_80}, /* R93 switched in/out of circuit */ 146 {0}, 0, 0, SPRINT8_C64, 0, 0, 1 /* c, rI, rF, cF, cAmp, vRef, gain */ 147 }; 148 149 static const discrete_mixer_desc sprint8_mixer = 150 { 151 DISC_MIXER_IS_RESISTOR, 152 {SPRINT8_R1 + SPRINT8_R100, SPRINT8_R3, SPRINT8_R4}, 153 {0}, {0}, 0, 0, 0, SPRINT8_C8, 0, 1 /* r_nodes, c, rI, rF, cF, cAmp, vRef, gain */ 154 }; 155 156 157 /************************************************ 158 * Car Motor 159 ************************************************/ 160 /* The first (astable) 555 generates a quick falling pulse that triggers the second (monostable) 555. 161 * This pulse is passed through C17 and pulled up with R40. This pulse is too fast to emulate so 162 * we will just tell the monostable it was triggered once and ignore C17/R40. 163 */ 164 #define SPRINT8_MOTOR_CIRCUIT(_car) \ 165 DISCRETE_RCFILTER(NODE_RELATIVE(NODE_30, _car - 1), NODE_RELATIVE(SPRINT8_MOTOR1_EN, _car - 1), SPRINT8_R89, SPRINT8_C26) \ 166 DISCRETE_ADDER2(NODE_RELATIVE(NODE_40, _car - 1), 1, NODE_RELATIVE(NODE_30, _car - 1), 0.7) /* add Q21 shift */ \ 167 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) \ 168 DISCRETE_555_MSTABLE(NODE_RELATIVE(NODE_60, _car - 1), 1, NODE_RELATIVE(NODE_50, _car - 1), SPRINT8_R41, SPRINT8_C28, &sprint8_motor_555m_desc) \ 169 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) 170 171 172 DISCRETE_SOUND_START( sprint8_discrete ) 173 /************************************************ 174 * Input register mapping 175 ************************************************/ DISCRETE_INPUT_LOGIC(SPRINT8_CRASH_EN)176 DISCRETE_INPUT_LOGIC(SPRINT8_CRASH_EN) 177 DISCRETE_INPUT_NOT (SPRINT8_SCREECH_EN) 178 DISCRETE_INPUT_NOT (SPRINT8_ATTRACT_EN) 179 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR1_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 180 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR2_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 181 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR3_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 182 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR4_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 183 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR5_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 184 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR6_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 185 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR7_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 186 DISCRETE_INPUTX_LOGIC(SPRINT8_MOTOR8_EN, DEFAULT_TTL_V_LOGIC_1, 0, 0) 187 188 DISCRETE_TASK_START(0) 189 DISCRETE_ADJUSTMENT(SPRINT8_R132_POT, 0, SPRINT8_R132, DISC_LINADJ, "R132") 190 191 /************************************************ 192 * Noise Generator, Crash, Screech 193 ************************************************/ 194 /* Address line A2 is used to XOR the feedback bits. 195 * This can not easily be implemented, so I just set the 196 * feedback as XNOR. */ 197 DISCRETE_LFSR_NOISE(SPRINT8_NOISE, /* IC F7, pin 13 */ 198 1, /* ENAB */ 199 SPRINT8_ATTRACT_EN, /* RESET */ 200 SPRINT8_2V, 1, 0, 0.5, &sprint8_lfsr) /* CLK,AMPL,FEED,BIAS,LFSRTB */ 201 202 DISCRETE_TASK_END() 203 204 DISCRETE_TASK_START(1) 205 DISCRETE_GAIN(NODE_70, SPRINT8_NOISE, DEFAULT_TTL_V_LOGIC_1 * RES_VOLTAGE_DIVIDER(SPRINT8_R148, SPRINT8_R147)) 206 DISCRETE_CRFILTER_VREF(NODE_71, 207 NODE_70, /* IN0 */ 208 RES_2_PARALLEL(SPRINT8_R148, SPRINT8_R147) + RES_2_PARALLEL(RES_K(5), RES_K(10)), 209 SPRINT8_C90, 210 5.0 * RES_VOLTAGE_DIVIDER(RES_K(5), RES_K(10))) /* ref to 555 CV pin */ 211 DISCRETE_555_ASTABLE_CV(NODE_72, 212 SPRINT8_SCREECH_EN, /* RESET */ 213 SPRINT8_R145, SPRINT8_R146, SPRINT8_C89, 214 NODE_71, /* CTRLV */ 215 &sprint8_crash_555a_desc) 216 DISCRETE_INTEGRATE(NODE_73, SPRINT8_CRASH_EN, 0, &sprint8_crash_integrate) 217 218 DISCRETE_SWITCH(NODE_80, 219 1, /* ENAB */ 220 SPRINT8_NOISE, /* SWITCH */ 221 SPRINT8_R93, 1) /* INP0,INP1*/ 222 DISCRETE_SWITCH(NODE_74, /* effect of Q20 */ 223 1, /* ENAB */ 224 SPRINT8_NOISE, /* SWITCH */ 225 NODE_73, 0) /* INP0,INP1*/ 226 DISCRETE_MIXER2(NODE_75, 227 1, /* ENAB */ 228 NODE_72, 229 NODE_74, 230 &sprint8_crash_screech_mixer) 231 232 DISCRETE_CRFILTER_VREF(NODE_76, 233 NODE_75, /* IN0 */ 234 SPRINT8_R93 + SPRINT8_R91, SPRINT8_C63, 235 5) /* VREF */ 236 /* IC E5, pin 14 gain. Does not simulate minor DC offset caused by R93. */ 237 DISCRETE_TRANSFORM5(NODE_77, NODE_76, 5, SPRINT8_R132_POT, SPRINT8_R101, 1, "01-23/4+*1+") 238 DISCRETE_CLAMP(SPRINT8_CRASH_SCREECH_SND, NODE_77, 0, 15.0 - 1.5) 239 DISCRETE_TASK_END() 240 241 /************************************************ 242 * Car Motor 243 ************************************************/ 244 DISCRETE_TASK_START(1) 245 SPRINT8_MOTOR_CIRCUIT(1) 246 SPRINT8_MOTOR_CIRCUIT(2) 247 DISCRETE_TASK_END() 248 249 DISCRETE_TASK_START(1) 250 SPRINT8_MOTOR_CIRCUIT(3) 251 SPRINT8_MOTOR_CIRCUIT(7) 252 DISCRETE_TASK_END() 253 254 DISCRETE_TASK_START(1) 255 SPRINT8_MOTOR_CIRCUIT(5) 256 SPRINT8_MOTOR_CIRCUIT(6) 257 DISCRETE_TASK_END() 258 259 DISCRETE_TASK_START(1) 260 SPRINT8_MOTOR_CIRCUIT(4) 261 SPRINT8_MOTOR_CIRCUIT(8) 262 DISCRETE_TASK_END() 263 264 /************************************************ 265 * Final Mix 266 ************************************************/ 267 DISCRETE_TASK_START(2) 268 DISCRETE_MIXER3(SPRINT8_AUDIO_1_2, 269 SPRINT8_ATTRACT_EN, /* ENAB */ 270 SPRINT8_CRASH_SCREECH_SND, 271 SPRINT8_MOTOR1_SND, 272 SPRINT8_MOTOR2_SND, 273 &sprint8_mixer) 274 DISCRETE_MIXER3(SPRINT8_AUDIO_3_7, 275 SPRINT8_ATTRACT_EN, /* ENAB */ 276 SPRINT8_CRASH_SCREECH_SND, 277 SPRINT8_MOTOR3_SND, 278 SPRINT8_MOTOR7_SND, 279 &sprint8_mixer) 280 DISCRETE_MIXER3(SPRINT8_AUDIO_5_6, 281 SPRINT8_ATTRACT_EN, /* ENAB */ 282 SPRINT8_CRASH_SCREECH_SND, 283 SPRINT8_MOTOR5_SND, 284 SPRINT8_MOTOR6_SND, 285 &sprint8_mixer) 286 DISCRETE_MIXER3(SPRINT8_AUDIO_4_8, 287 SPRINT8_ATTRACT_EN, /* ENAB */ 288 SPRINT8_CRASH_SCREECH_SND, 289 SPRINT8_MOTOR4_SND, 290 SPRINT8_MOTOR8_SND, 291 &sprint8_mixer) 292 DISCRETE_OUTPUT(SPRINT8_AUDIO_1_2, 65500.0/8) 293 DISCRETE_OUTPUT(SPRINT8_AUDIO_3_7, 65500.0/8) 294 DISCRETE_OUTPUT(SPRINT8_AUDIO_5_6, 65500.0/8) 295 DISCRETE_OUTPUT(SPRINT8_AUDIO_4_8, 65500.0/8) 296 DISCRETE_TASK_END() 297 DISCRETE_SOUND_END 298 299 void sprint8_state::sprint8_audio(machine_config &config) 300 { 301 /* sound hardware */ 302 /* the proper way is to hook up 4 speakers, but they are not really 303 * F/R/L/R speakers. Though you can pretend the 1-2 mix is the front. */ 304 SPEAKER(config, "speaker_1_2", 0.0, 0.0, 1.0); // front 305 SPEAKER(config, "speaker_3_7", -0.2, 0.0, 1.0); // left 306 SPEAKER(config, "speaker_5_6", 0.0, 0.0, -0.5); // back 307 SPEAKER(config, "speaker_4_8", 0.2, 0.0, 1.0); // right 308 309 DISCRETE(config, m_discrete, sprint8_discrete); 310 m_discrete->add_route(0, "speaker_1_2", 1.0); 311 /* volumes on other channels defaulted to off, */ 312 /* user can turn them up if needed. */ 313 /* The game does not sound good with all channels mixed to stereo. */ 314 m_discrete->add_route(1, "speaker_3_7", 0.0); 315 m_discrete->add_route(2, "speaker_5_6", 0.0); 316 m_discrete->add_route(3, "speaker_4_8", 0.0); 317 318 f9334_device &latch(F9334(config, "latch")); 319 latch.q_out_cb<0>().set(FUNC(sprint8_state::int_reset_w)); 320 latch.q_out_cb<1>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_CRASH_EN>)); 321 latch.q_out_cb<2>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_SCREECH_EN>)); 322 latch.q_out_cb<5>().set(FUNC(sprint8_state::team_w)); 323 latch.q_out_cb<6>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_ATTRACT_EN>)); 324 325 f9334_device &motor(F9334(config, "motor")); 326 motor.q_out_cb<0>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR1_EN>)); 327 motor.q_out_cb<1>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR2_EN>)); 328 motor.q_out_cb<2>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR3_EN>)); 329 motor.q_out_cb<3>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR4_EN>)); 330 motor.q_out_cb<4>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR5_EN>)); 331 motor.q_out_cb<5>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR6_EN>)); 332 motor.q_out_cb<6>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR7_EN>)); 333 motor.q_out_cb<7>().set(m_discrete, FUNC(discrete_device::write_line<SPRINT8_MOTOR8_EN>)); 334 } 335 ; 336