TORCS  1.3.10
The Open Racing Car Simulator
Loading...
Searching...
No Matches
CarSoundData.cpp
Go to the documentation of this file.
1// -*- Mode: c++ -*-
2/***************************************************************************
3 file : CarSoundData.cpp
4 created : Tue Apr 5 19:57:35 CEST 2005
5 copyright : (C) 2005-2024 Christos Dimitrakakis, Bernhard Wymann
6 email : berniw@bluewin.ch
7
8***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19#include "SoundInterface.h"
20#include "CarSoundData.h"
21
23{
24 eng_pri.id = id;
25 eng_pri.a = 1.0f;
26 engine.a = 0.0f;
27 engine.f = 1.0f;
28 engine.lp = 1.0f;
29 smooth_accel = 0.0f;
30 base_frequency = 0.0f;
31 drag_collision.a = 0.0f;
32 drag_collision.f = 0.0f;
33 drag_collision.lp = 0.0f;
34 pre_axle = 0.0f;
35 axle.a = 0.0f;
36 axle.f = 0.0f;
37 axle.lp = 0.0f;
38 turbo.a = 0.0f;
39 turbo.f = 0.0f;
40 turbo.lp = 0.0f;
41 engine_backfire.a=0.0f;
42 engine_backfire.f=0.0f;
43 engine_backfire.lp=0.0f;
44 prev_gear = 0;
45 gear_changing = false;
46 bottom_crash = false;
47 bang = false;
48 crash = false;
49 turbo_on = false;
50 turbo_ilag = 0.05f;
51 turbo_rpm = 0.0f;
52 this->sound_interface = sound_interface;
53 for (int i=0; i<4; i++) {
54 for (int j=0; j<3; j++) {
55 wheel[i].p[j] = 0.0f;
56 wheel[i].u[j] = 0.0f;
57 }
58 wheel[i].skid.a = 0.0f;
59 wheel[i].skid.f = 1.0f;
60 wheel[i].skid.lp = 0.0f;
61 }
62 sgVec3 zeroes = {0.0f, 0.0f, 0.0f};
63 setCarPosition(zeroes);
64 setCarSpeed(zeroes);
65 setListenerPosition(zeroes);
66 engine_sound = NULL;
67
68 attenuation = 0.0f;
69 grass_skid.a=0.0f;
70 grass_skid.f=0.0f;
71 grass_skid.lp=0.0f;
72 curb.a = 0.0f;
73 curb.f = 0.0f;
74 curb.lp =0.0f;
75 grass.a=0.0f;
76 grass.f=0.0f;
77 grass.lp=0.0f;
78 road.a=0.0f;
79 road.f=0.0f;
80 road.lp=0.0f;
81 skid_metal.a=0.0f;
82 skid_metal.f=0.0f;
83 skid_metal.lp=0.0f;
84}
86{
87 this->engine_sound = engine_sound;
88 base_frequency = rpm_scale;
89}
90
91void CarSoundData::setTurboParameters (bool turbo_on, float turbo_rpm, float turbo_lag)
92{
93 this->turbo_on = turbo_on;
94 this->turbo_rpm = turbo_rpm;
95 if (turbo_lag > 0.0f) {
96 this->turbo_ilag = exp(-3.0f*turbo_lag);
97 } else {
98 fprintf (stderr, "warning: turbo lag %f <= 0\n", turbo_lag);
99 }
100}
102{
103 assert (car->index == eng_pri.id);
104 speed[0] = car->pub.DynGCg.vel.x;
105 speed[1] = car->pub.DynGCg.vel.y;
106 speed[2] = car->pub.DynGCg.vel.z;
107 position[0] = car->pub.DynGCg.pos.x;
108 position[1] = car->pub.DynGCg.pos.y;
109 position[2] = car->pub.DynGCg.pos.z;
113 calculateTyreSound (car);
116}
117
120{
121 if (car->_state & RM_CAR_STATE_NO_SIMU) {
122 attenuation = 0.0f;
123 return;
124 }
125 float d = 0.0;
126 for (int i=0; i<3; i++) {
127 float delta = (listener_position[i] - position[i]);
128 d += delta*delta;
129 }
130 attenuation = 1.0f / (1.0f + sqrt(d));
132}
133
136{
137 float mpitch = base_frequency * (float)(car->_enginerpm) / 600.0;
138 engine.f = mpitch;
139 engine.a = 1.0f;
140 if (car->_state & RM_CAR_STATE_NO_SIMU) {
141 engine.a = 0.0f;
142 engine.lp = 1.0;
143 turbo.a = 0.0f;
144 turbo.f = 1.0f;
145 return;
146 }
147 //assert(car->index == eng_pri.id);
148
149 float gear_ratio = car->_gearRatio[car->_gear + car->_gearOffset];
150 axle.a = 0.2f*(tanh(100.0f*(fabs(pre_axle - mpitch))));
151 axle.f = (pre_axle + mpitch)*0.05f*fabs(gear_ratio);
152 pre_axle = (pre_axle + mpitch)*.5;
153
154 if (turbo_on) {
155 float turbo_target = 0.1f;
156 float turbo_target_vol = 0.0f;
157 if (car->_enginerpm > turbo_rpm) {
158 turbo_target = 0.1f + 0.9f * smooth_accel;
159 turbo_target_vol = 0.1f * smooth_accel;
160 }
161
162 turbo.a += 0.1f * (turbo_target_vol - turbo.a) * (0.1f + smooth_accel);
163 float turbo_target_pitch = turbo_target * car->_enginerpm / 600.0f;
164 turbo.f += turbo_ilag * (turbo_target_pitch - turbo.f) * (smooth_accel);
165 turbo.f -= turbo.f * 0.01f * (1.0-smooth_accel);//.99f;
166 } else {
167 turbo.a = 0.0;
168 }
169 smooth_accel = smooth_accel*0.5f + 0.5*(car->ctrl.accelCmd*.99f+0.01f);
170
171 // engine filter proportional to revcor2.
172 // when accel = 0, lp \in [0.0, 0.25]
173 // when accel = 1, lp \in [0.25, 1.0]
174 // interpolate linearly for values in between.
175 float rev_cor = car->_enginerpm/car->_enginerpmRedLine;
176 float rev_cor2 = rev_cor * rev_cor;
177 engine.lp = (0.75f*rev_cor2 + 0.25f)*smooth_accel
178 + (1.0f-smooth_accel)*0.25f*rev_cor2;
179
180 // TODO: filter for exhaust and car body resonance?
181
182}
183
184
187{
188 if (car->_state & RM_CAR_STATE_NO_SIMU) {
189 engine_backfire.a = 0.0f;
190 engine_backfire.f = 1.0f;
191 return;
192 }
193 if ((car->priv.smoke>0.0)&&(engine_backfire.a<0.5)) {
194 engine_backfire.a += .25f*car->priv.smoke;
195 }
196 engine_backfire.f = ((float)(car->_enginerpm) / 600.0);
197 engine_backfire.a *= (.9*.5+.5*exp(-engine_backfire.f));
198}
199
201{
202 // Initialize sound parameters
203 grass_skid.a = grass.a = 0.0f;
204 grass.f = curb.f = 1.0f;
205 curb.a = 0.0f;
206 road.a = road.f = 0.0f;
207
208 // Initialize wheel sounds
209 int wheelIndex;
210 for (wheelIndex = 0; wheelIndex < 4; wheelIndex++) {
211 wheel[wheelIndex].skid.a = 0.0f;
212 wheel[wheelIndex].skid.f = 1.0f;
213 }
214
215 // Early exit if the car simulation is not active
216 if (car->_state & RM_CAR_STATE_NO_SIMU) {
217 return;
218 }
219
220 // Check if any wheel is spinning significantly
221 bool wheelSpinning = false;
222 for (wheelIndex = 0; wheelIndex < 4; wheelIndex++) {
223 if (car->_wheelSpinVel(wheelIndex) > 0.1f) {
224 wheelSpinning = true;
225 break;
226 }
227 }
228
229 // Early exit if the car is stationary and wheels are not spinning
230 if ((car->pub.speed < 0.3f) && !wheelSpinning) {
231 return;
232 }
233
234 for (wheelIndex = 0; wheelIndex<4; wheelIndex++) {
235 // I do not skip here for car->_reaction[i] <= 0, because the road sample currently also includes airflow noise
236 tdble tmpvol = car->pub.speed*0.01f;
237 tdble roughnessFreq = calculateRoughnessFreqency(car->priv.wheel[wheelIndex].seg);
238 tdble ride = 0.001f * car->_reaction[wheelIndex];
239
240 // Get information about tire overlapping another surface (e.g. at road edge to the curb).
241 tdble otherSurfaceContribution = 0.0f;
242 tdble otherRoughnessFreq = 1.0f;
243 bool onOtherSurface = car->priv.otherSurfaceContribution[wheelIndex] > 0.0f && car->priv.otherSurfaceSeg[wheelIndex] != NULL;
244
245 if (onOtherSurface) {
246 otherSurfaceContribution = car->priv.otherSurfaceContribution[wheelIndex];
247 otherRoughnessFreq = calculateRoughnessFreqency(car->priv.otherSurfaceSeg[wheelIndex]);
248 }
249
250 // Curb handling, implicit assumption that there are never two curbs directly side by side. This
251 // is currently guaranteed.
252
253 // Check curb sound contribution, skip calculation if there is no load on the wheel (no sound)
254 // The Curb effect is an "addon" effect, it does not exclude the road or dirt effects, e.g. you
255 // can have the tires skid on the curbs and have wind noise.
256 handleCurbContribution(&car->priv, onOtherSurface, otherSurfaceContribution, roughnessFreq,
257 otherRoughnessFreq, tmpvol, ride, wheelIndex, car->_reaction[wheelIndex]);
258
259 // Handling of dirt and normal surfaces, here we can have an overlapping tire spanning either
260 // two surfaces of the same type or a different type.
261 bool mainSurfaceIsOffroad = isOffRoadSurface(car->priv.wheel[wheelIndex].seg);
262 bool onOtherDifferentSurface =
263 onOtherSurface && (mainSurfaceIsOffroad != isOffRoadSurface(car->priv.otherSurfaceSeg[wheelIndex]));
264
265 tdble roadContribution = 0.0f;
266 tdble dirtContribution = 0.0f;
267
268 if (onOtherDifferentSurface) {
269 // Mixed cases, two different surfaces
270 if (mainSurfaceIsOffroad) {
271 dirtContribution = 1.0f - otherSurfaceContribution;
272 roadContribution = otherSurfaceContribution;
273 } else {
274 roadContribution = 1.0f - otherSurfaceContribution;
275 dirtContribution = otherSurfaceContribution;
276 }
277 } else {
278 // Both surfaces of the same type
279 if (mainSurfaceIsOffroad) {
280 dirtContribution = 1.0f;
281 } else {
282 roadContribution = 1.0f;
283 }
284 }
285
286 // Normal road handling
287 if (roadContribution > 0.0f) {
288 handleRoadContribution(mainSurfaceIsOffroad, roadContribution, roughnessFreq,
289 otherRoughnessFreq, tmpvol, ride, wheelIndex, car->_skid[wheelIndex],
290 car->_wheelSlipAccel(wheelIndex), car->_reaction[wheelIndex]);
291 }
292
293 // Dirt handling
294 if (dirtContribution > 0.0f) {
295 tdble dirtRoughnessFreq = 0.0f;
296 tdble dirtRoughness = 0.0f;
297
298 getDirtRoughnessParams(car, wheelIndex, mainSurfaceIsOffroad, roughnessFreq, otherRoughnessFreq, dirtRoughnessFreq, dirtRoughness);
299 handleDirtContribution(dirtContribution, dirtRoughnessFreq, dirtRoughness, car->_skid[wheelIndex], tmpvol, ride);
300 }
301 }
302
303 for (wheelIndex = 0; wheelIndex<4; wheelIndex++) {
304 tdble az = car->_yaw;
305 tdble Sinz = sin(az);
306 tdble Cosz = cos(az);
307
308 tdble x = car->priv.wheel[wheelIndex].relPos.x;
309 tdble y = car->priv.wheel[wheelIndex].relPos.y;
310
311 tdble dx = x * Cosz - y * Sinz;
312 tdble dy = x * Sinz + y * Cosz;
313
314 tdble dux_initial = -car->_yaw_rate * y;
315 tdble duy_initial = car->_yaw_rate * x;
316
317 tdble dux = dux_initial * Cosz - duy_initial * Sinz;
318 tdble duy = dux_initial * Sinz + duy_initial * Cosz;
319
320 wheel[wheelIndex].u[0] = car->pub.DynGCg.vel.x + dux;
321 wheel[wheelIndex].u[1] = car->pub.DynGCg.vel.y + duy;
322 wheel[wheelIndex].u[2] = car->pub.DynGCg.vel.z;
323 wheel[wheelIndex].p[0] = car->pub.DynGCg.pos.x + dx;
324 wheel[wheelIndex].p[1] = car->pub.DynGCg.pos.y + dy;
325 wheel[wheelIndex].p[2] = car->pub.DynGCg.pos.z;
326 }
327}
328
330 const char* const materialName = seg->surface->material;
331 return materialName &&
332 (strstr(materialName, TRK_VAL_SAND)
333 || strstr(materialName, TRK_VAL_DIRT)
334 || strstr(materialName, TRK_VAL_GRASS)
335 || strstr(materialName, "gravel")
336 || strstr(materialName, "mud")
337 );
338}
339
340
342{
343 tdble roughnessFreq = 2.0f*EX_PI*seg->surface->kRoughWaveLen;
344 if (roughnessFreq>2.0f) {
345 roughnessFreq = 2.0f + tanh(roughnessFreq-2.0f);
346 }
347 return roughnessFreq;
348}
349
350
352 tCarElt* car,
353 int wheelIndex,
354 bool mainSurfaceIsOffroad,
355 tdble roughnessFreq,
356 tdble otherRoughnessFreq,
357 tdble& dirtRoughnessFreq,
358 tdble& dirtRoughness
359) {
360 if (mainSurfaceIsOffroad) {
361 dirtRoughnessFreq = roughnessFreq;
362 dirtRoughness = car->priv.wheel[wheelIndex].seg->surface->kRoughness;
363 } else {
364 dirtRoughnessFreq = otherRoughnessFreq;
365 dirtRoughness = car->priv.otherSurfaceSeg[wheelIndex]->surface->kRoughness;
366 }
367}
368
369
371 tdble dirtContribution,
372 tdble dirtRoughnessFreq,
373 tdble dirtRoughness,
374 tdble wheelSkid,
375 tdble tmpvol,
376 tdble ride
377) {
378 if (dirtContribution > 0.0f) {
379 tdble dirtpitch = tmpvol * (0.5f + 0.5f*dirtRoughnessFreq);
380 tdble dirtvol = (0.5f + 0.2f*tanh(0.5f*dirtRoughness))*tmpvol*ride*dirtContribution;
381
382 if (grass.a < dirtvol) {
383 grass.a = dirtvol;
384 grass.f = dirtpitch;
385 }
386
387 tdble grassvol = wheelSkid*dirtContribution;
388 if (grass_skid.a < grassvol) {
389 grass_skid.a = static_cast<float>(grassvol);
390 grass_skid.f = 1.0f;
391 }
392 }
393}
394
395
397 bool mainSurfaceIsOffroad,
398 tdble roadContribution,
399 tdble roughnessFreq,
400 tdble otherRoughnessFreq,
401 tdble tmpvol,
402 tdble ride,
403 int wheelIndex,
404 tdble wheelSkid,
405 tdble wheelSlipAccel,
406 tdble wheelReaction
407) {
408 if (roadContribution > 0.0f) {
409 tdble roadRoughnessFreq;
410 if (!mainSurfaceIsOffroad) {
411 roadRoughnessFreq = roughnessFreq;
412 } else {
413 roadRoughnessFreq = otherRoughnessFreq;
414 }
415
416 tdble roadpitch = tmpvol*(0.75f+0.25f*roadRoughnessFreq);
417 tdble wind_noise = 1.0f;
418 tdble road_noise = 0.25f;
419 tdble roadvol = tmpvol*(wind_noise + ride*road_noise)*roadContribution;
420 if (road.a < roadvol) {
421 road.a = roadvol;
422 road.f = roadpitch;
423 }
424
425 if (wheelSkid > 0.05f) {
426 wheel[wheelIndex].skid.a = (float)(wheelSkid-0.05f)*roadContribution;
427 float wsa = tanh((wheelSlipAccel+10.0f)*0.01f);
428 wheel[wheelIndex].skid.f = (0.3f - 0.3f*wsa + 0.3f*roadRoughnessFreq)/(1.0f+0.5f*tanh(wheelReaction*0.0001f));
429 }
430 }
431}
432
433
435 tPrivCar* car,
436 bool onOtherSurface,
437 tdble otherSurfaceContribution,
438 tdble curbRoughnessFreq,
439 tdble otherRoughnessFreq,
440 tdble tmpvol,
441 tdble ride,
442 int wheelIndex,
443 tdble wheelReaction
444) {
445 if (wheelReaction > 0.0f) {
446 tdble curbContribution = 0.0f;
447 if (car->wheel[wheelIndex].seg->style == TR_CURB) {
448 curbContribution = 1.0f - otherSurfaceContribution;
449 } else if (onOtherSurface && car->otherSurfaceSeg[wheelIndex]->style == TR_CURB) {
450 curbContribution = otherSurfaceContribution;
451 curbRoughnessFreq = otherRoughnessFreq;
452 }
453
454 if (curbContribution > 0.0f) {
455 // Constants by trial and error, there is no deeper reasoning behind it
456 float curbpitch = tmpvol*(0.75f+0.25f*curbRoughnessFreq);
457 float curbvol = tmpvol*(5.0f + ride/3.0f)*curbContribution;
458 // There is only one effect for the car, take the loudest wheel
459 if (curb.a < curbvol) {
460 curb.a = curbvol;
461 curb.f = curbpitch;
462 }
463 }
464 }
465}
466
467
469 if (car->_gear != prev_gear) {
470 prev_gear = car->_gear;
471 gear_changing = true;
472 } else {
473 gear_changing = false;
474 }
475
476}
477
479{
480 skid_metal.a = 0.0f;
481 skid_metal.f = 1.0f;
482 bottom_crash = false;
483 bang = false;
484 crash = false;
485 if (car->_state & RM_CAR_STATE_NO_SIMU) {
486 return;
487 }
488
489
490
491 int collision = car->priv.collision;
492 if (collision) {
493 if (collision & 1) {
494 skid_metal.a = car->pub.speed*0.01;
495 skid_metal.f = .5+0.5*skid_metal.a;
497 } else {
498 skid_metal.a = 0;
499 }
500
501 if ((collision & 16 )) {
502 bottom_crash = true;
503 }
504
505 if ((collision & 8 )) {
506 bang = true;
507 }
508
509 if (((collision & 1) ==0) ||
510 ((collision & 2)
511 &&(skid_metal.a >drag_collision.a))) {
512 crash = true;
513 }
514 car->priv.collision = 0;
515 }
516
518 if (drag_collision.a>1.0f) {
519 drag_collision.a = 1.0f;
520 }
523}
static Vector y[4]
Definition Convex.cpp:56
#define RM_CAR_STATE_NO_SIMU
Do not simulate the car.
Definition car.h:217
struct CarElt tCarElt
Car structure (tCarElt).
float smooth_accel
smoothed acceleration input
bool turbo_on
use turbo sound
QSoundChar grass_skid
void calculateGearChangeSound(tCarElt *car)
QSoundChar engine_backfire
QSoundChar grass
QSoundChar turbo
SoundPri eng_pri
void calculateCollisionSound(tCarElt *car)
void calculateAttenuation(tCarElt *car)
Use inverse distance to calculate attenuation of sounds originating from this car....
float pre_axle
axle related
void setCarSpeed(sgVec3 u)
QSoundChar skid_metal
float turbo_ilag
how fast turbo catches up with engine
float attenuation
global distance attenuation
SoundInterface * sound_interface
float base_frequency
engine base frequency for ~ 6000 rpm
void setListenerPosition(sgVec3 p)
void calculateEngineSound(tCarElt *car)
Calculate characteristics of the engine sound.
void setEngineSound(TorcsSound *engine_sound, float rpm_scale)
void setTurboParameters(bool turbo_on, float turbo_rpm, float turbo_lag)
QSoundChar curb
QSoundChar engine
void handleDirtContribution(tdble dirtContribution, tdble dirtRoughnessFreq, tdble dirtRoughness, tdble wheelSkid, tdble tmpvol, tdble ride)
CarSoundData(int id, SoundInterface *sound_interface)
bool isOffRoadSurface(const tTrackSeg *const seg)
void getDirtRoughnessParams(tCarElt *car, int wheelIndex, bool mainSurfaceIsOffroad, tdble roughnessFreq, tdble otherRoughnessFreq, tdble &dirtRoughnessFreq, tdble &dirtRoughness)
float turbo_rpm
when turbo comes in
TorcsSound * engine_sound
tdble calculateRoughnessFreqency(const tTrackSeg *const seg)
void calculateTyreSound(tCarElt *car)
QSoundChar drag_collision
void handleCurbContribution(tPrivCar *car, bool onOtherSurface, tdble otherSurfaceContribution, tdble curbRoughnessFreq, tdble otherRoughnessFreq, tdble tmpvol, tdble ride, int wheelIndex, tdble wheelReaction)
sgVec3 position
WheelSoundData wheel[4]
QSoundChar axle
void handleRoadContribution(bool mainSurfaceIsOffroad, tdble roadContribution, tdble roughnessFreq, tdble otherRoughnessFreq, tdble tmpvol, tdble ride, int wheelIndex, tdble wheelSkid, tdble wheelSlipAccel, tdble wheelReaction)
void update(tCarElt *car)
sgVec3 listener_position
void setCarPosition(sgVec3 p)
void calculateBackfireSound(tCarElt *car)
Calculate the frequency and amplitude of a looped backfiring sound.
QSoundChar road
Sound interface.
A generic TORCS sound.
Definition TorcsSound.h:53
float tdble
Floating point type used in TORCS.
Definition tgf.h:47
struct trackSeg tTrackSeg
Track segment (tTrackSeg) The segments can be straights (type TR_STR): (the track goes from the right...
#define EX_PI
tPrivCar priv
private
Definition car.h:463
tPublicCar pub
public
Definition car.h:461
tCarCtrl ctrl
private
Definition car.h:464
int index
car index
Definition car.h:459
tdble accelCmd
Accelerator command [0.0, 1.0].
Definition car.h:348
tPosd vel
velocity
Definition tgf.h:144
tPosd pos
position
Definition tgf.h:143
tdble y
y coordinate
Definition tgf.h:131
tdble x
x coordinate
Definition tgf.h:130
tdble z
z coordinate
Definition tgf.h:132
Data known only by the driver.
Definition car.h:287
tWheelState wheel[4]
Definition car.h:292
int collision
Collision value for graphics and sound, clearing is managed by consumers.
Definition car.h:308
tdble otherSurfaceContribution[4]
Definition car.h:319
tTrackSeg * otherSurfaceSeg[4]
Definition car.h:320
float smoke
Definition car.h:310
tDynPt DynGCg
GC data (world axis)
Definition car.h:193
tdble speed
Definition car.h:194
tTrackSeg * seg
Track segment where the wheel is.
Definition car.h:256
tPosd relPos
position relative to GC
Definition car.h:252
tTrackSurface * surface
Segment surface.
Definition track.h:409
int style
Border and barrier segments style:
Definition track.h:319
const char * material
Type of material used.
Definition track.h:262
tdble kRoughWaveLen
Wave length in m of the surface.
Definition track.h:268
tdble kRoughness
Roughtness in m of the surface (wave height)
Definition track.h:267
#define TRK_VAL_GRASS
Definition track.h:231
#define TRK_VAL_DIRT
Definition track.h:233
#define TR_CURB
Curb (border only)
Definition track.h:327
#define TRK_VAL_SAND
Definition track.h:232