TORCS  1.3.9
The Open Racing Car Simulator
OpenalSoundInterface.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  file : PlibSoundInterface.cpp
4  created : Thu Apr 7 04:21 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 #include "TorcsSound.h"
22 
23 
25 #undef USE_OPENAL_DOPPLER
26 
28 
29 
30 
31 OpenalSoundInterface::OpenalSoundInterface(float sampling_rate, int n_channels): SoundInterface (sampling_rate, n_channels)
32 {
33  car_src = NULL;
34 
35  ALfloat far_away[] = { 0.0f, 0.0f, 1000.0f };
36  ALfloat zeroes[] = { 0.0f, 0.0f, 0.0f };
37  ALfloat front[] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f };
38  dev = alcOpenDevice( NULL );
39  if( dev == NULL ) {
40  throw ("Could not open device");
41  }
42 
43  // Last zero is termination of the array, I think the current official beat SDK ignores that.
44  // ALCint attr[] = { ALC_MONO_SOURCES, 1024, ALC_STEREO_SOURCES, 0, 0};
45  cc = alcCreateContext( dev, NULL);
46  if(cc == NULL) {
47  alcCloseDevice( dev );
48  throw ("Could not create context.");
49  }
50 
51  alcMakeContextCurrent( cc );
52  alcGetError(dev);
53  alGetError();
54 
55  // Figure out the number of possible sources, watch out for an API update, perhaps
56  // one can get that easier later with al(c)GetInteger (I'm sure that there is no way to
57  // query this now) or even request a number with the context.
58  const int MAX_SOURCES = 1024;
59  int sources;
60  ALuint sourcelist[MAX_SOURCES];
61  for (sources = 0; sources < MAX_SOURCES; sources++) {
62  alGenSources(1, &sourcelist[sources]);
63  if (alGetError() != AL_NO_ERROR) {
64  break;
65  }
66  }
67 
68  int clear;
69  for (clear = 0; clear < sources; clear++) {
70  if (alIsSource(sourcelist[clear])) {
71  alDeleteSources(1, &sourcelist[clear]);
72  if (alGetError() != AL_NO_ERROR) {
73  printf("Error in probing OpenAL sources.\n");
74  }
75  } else {
76  printf("Error in probing OpenAL sources.\n");
77  }
78  }
79 
80  OSI_MAX_SOURCES = sources;
82 
83  // Figure out the number of buffers.
84  int buffers;
85  ALuint bufferlist[MAX_SOURCES];
86  for (buffers = 0; buffers < MAX_SOURCES; buffers++) {
87  alGenBuffers(1, &bufferlist[buffers]);
88  if (alGetError() != AL_NO_ERROR) {
89  break;
90  }
91  }
92 
93  for (clear = 0; clear < buffers; clear++) {
94  if (alIsBuffer(bufferlist[clear])) {
95  alDeleteBuffers(1, &bufferlist[clear]);
96  if (alGetError() != AL_NO_ERROR) {
97  printf("Error in probing OpenAL buffers.\n");
98  }
99  } else {
100  printf("Error in probing OpenAL buffers.\n");
101  }
102  }
103 
104  OSI_MAX_BUFFERS = buffers;
105 
106  printf("OpenAL backend info:\n Vendor: %s\n Renderer: %s\n Version: %s\n", alGetString(AL_VENDOR), alGetString(AL_RENDERER), alGetString(AL_VERSION));
107  printf(" Available sources: %d%s\n", OSI_MAX_SOURCES, (sources >= MAX_SOURCES) ? " or more" : "");
108  printf(" Available buffers: %d%s\n", OSI_MAX_BUFFERS, (buffers >= MAX_SOURCES) ? " or more" : "");
109 
110  alDistanceModel ( AL_INVERSE_DISTANCE );
111  int error = alGetError();
112  if (error != AL_NO_ERROR) {
113  printf("OpenAL Error: %d alDistanceModel\n", error);
114  }
115 
116  alDopplerFactor (1.0f);
117  //alSpeedOfSound (SPEED_OF_SOUND); // not defined in linux yet.
118  alDopplerVelocity (SPEED_OF_SOUND);
119  error = alGetError();
120  if (error != AL_NO_ERROR) {
121  printf("OpenAL Error: %d alDopplerX\n", error);
122  }
123 
124 
125  alListenerfv(AL_POSITION, far_away );
126  alListenerfv(AL_VELOCITY, zeroes );
127  alListenerfv(AL_ORIENTATION, front );
128  error = alGetError();
129  if (error != AL_NO_ERROR) {
130  printf("OpenAL Error: %d alListenerfv\n", error);
131  }
132 
133  engpri = NULL;
134  global_gain = 1.0f;
135 
136  // initialise mappings
145 
147 }
148 
150 {
151  delete sourcepool;
152  for (unsigned int i=0; i<sound_list.size(); i++) {
153  delete sound_list[i];
154  }
155  delete [] engpri;
156  alcDestroyContext (cc);
157  alcCloseDevice (dev);
158 
159  if (car_src) {
160  delete [] car_src;
161  }
162 }
163 
165 {
166  engpri = new SoundPri[n_cars];
167  car_src = new SoundSource[n_cars];
168 }
169 
170 
171 TorcsSound* OpenalSoundInterface::addSample (const char* filename, int flags, bool loop, bool static_pool)
172 {
173  TorcsSound* sound = new OpenalTorcsSound (filename, this, flags, loop, static_pool);
174  sound_list.push_back (sound);
175  return sound;
176 }
177 
178 void OpenalSoundInterface::update(CarSoundData** car_sound_data, int n_cars, sgVec3 p_obs, sgVec3 u_obs, sgVec3 c_obs, sgVec3 a_obs)
179 {
180 
181  ALfloat listener_pos[3];
182  //ALfloat listener_speed[3];
183  ALfloat listener_orientation[6];
184  ALfloat zeros[] = {0.0f, 0.0f, 0.0f};
185 
186  int i;
187  for (i = 0; i<3; i++) {
188  listener_pos[i] = p_obs[i];
189  //listener_speed[i] = 0;// u_obs[i];
190  listener_orientation[i] = c_obs[i];
191  listener_orientation[i+3] = a_obs[i];
192  }
193 
194  alListenerfv(AL_POSITION, listener_pos );
195 #ifdef USE_OPENAL_DOPPLER
196  alListenerfv(AL_VELOCITY, listener_speed );
197 #else
198  alListenerfv(AL_VELOCITY, zeros);
199 #endif
200  alListenerfv(AL_ORIENTATION, listener_orientation );
201  alListenerf(AL_GAIN, getGlobalGain());
202 
203  for (i = 0; i<n_cars; i++) {
205  int id = engpri[i].id;
206  sgVec3 p;
207  sgVec3 u;
209  car_sound_data[id]->getCarSpeed(u);
210  car_src[id].setSource (p, u);
211  car_src[id].setListener (p_obs, u_obs);
212  car_src[id].update();
213  engpri[id].a = car_src[id].a;
214  }
215 
216 
217  qsort ((void*) engpri, n_cars, sizeof(SoundPri), &sortSndPriority);
218 
219 
220  int nsrc = MIN(sourcepool->getNbSources(), n_engine_sounds);
221 
222  // Reverse order is important to gain free sources from stopped engine sounds
223  // before attempting to start new ones.
224  for (i = n_cars - 1; i >= 0; i--) {
225  int id = engpri[i].id;
226  sgVec3 p;
227  sgVec3 u;
228  CarSoundData* sound_data = car_sound_data[id];
229  sound_data->getCarPosition(p);
230  sound_data->getCarSpeed(u);
231  TorcsSound* engine = sound_data->getEngineSound();
232  engine->setSource(p, u);
233 #ifdef USE_OPENAL_DOPPLER
234  engine->setPitch (sound_data->engine.f);
235 #else
236  engine->setPitch (car_src[id].f*sound_data->engine.f);
237 #endif
238  engine->setVolume (sound_data->engine.a * exp(sound_data->engine.lp-1.0));
239  //engine->setLPFilter(sound_data->engine.lp);
240 
241  engine->update();
242  if (i < nsrc) {
243  engine->start();
244  } else {
245  engine->stop();
246  }
247  }
248 
249  float max_skid_vol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
250  int max_skid_id[4] = {0,0,0,0};
251  int id;
252  for (id = 0; id<n_cars; id++) {
253  CarSoundData* sound_data = car_sound_data[id];
254  for (int j=0; j<4; j++) {
255  float skvol=sound_data->attenuation*sound_data->wheel[j].skid.a;
256  if (skvol > max_skid_vol[j]) {
257  max_skid_vol[j] = skvol;
258  max_skid_id[j] = id;
259  }
260  }
261  }
262 
263  for (i = 0; i<4; i++) {
264  int id = max_skid_id[i];
265  WheelSoundData* sound_data = car_sound_data[id]->wheel;
266  skid_sound[i]->setSource (sound_data[i].p, sound_data[i].u);
267  skid_sound[i]->setVolume (sound_data[i].skid.a);
268 #ifdef USE_OPENAL_DOPPLER
269  skid_sound[i]->setPitch (MIN(sound_data[i].skid.f, 1.0f));
271 #else
272  float mod_f = car_src[id].f;
273  skid_sound[i]->setPitch (sound_data[i].skid.f * mod_f);
274 #endif
275  skid_sound[i]->update();
276  if (sound_data[i].skid.a > VOLUME_CUTOFF) {
277  skid_sound[i]->start();
278  } else {
279  skid_sound[i]->stop();
280  }
281  }
282 
283 
284  // other looping sounds
286  SortSingleQueue (car_sound_data, &road, n_cars);
288 
292 
296 
298  SortSingleQueue (car_sound_data, &curb, n_cars);
300 
304 
308 
312 
316 
317  axle.snd = axle_sound;
318  SortSingleQueue (car_sound_data, &axle, n_cars);
320 
321  // One-off sounds
322  for (id = 0; id<n_cars; id++) {
323  CarSoundData* sound_data = car_sound_data[id];
324  sgVec3 p;
325  sgVec3 u = {0, 0, 0};
326  if (sound_data->crash) {
327  if (++curCrashSnd>=NB_CRASH_SOUND) {
328  curCrashSnd = 0;
329  }
330  sound_data->getCarPosition(p);
331  sound_data->getCarSpeed(u);
337  }
338 
339  if (sound_data->bang) {
340  sound_data->getCarPosition(p);
341  sound_data->getCarSpeed(u);
342  bang_sound->setSource (p, u);
343  bang_sound->setVolume (1.0f);
344  bang_sound->setPitch (1.0f);
345  bang_sound->update();
346  bang_sound->start();
347  }
348 
349  if (sound_data->bottom_crash) {
350  sound_data->getCarPosition(p);
351  sound_data->getCarSpeed(u);
357  }
358 
359  if (sound_data->gear_changing) {
360  sound_data->getCarPosition(p);
361  sound_data->getCarSpeed(u);
365  gear_change_sound->setPitch (1.0f);
368  }
369  }
370 }
371 
372 
374 {
375  alListenerf(AL_GAIN, 0.0f);
376 }
377 
378 
380 {
381  int nbdynsources = OSI_MAX_SOURCES - n_static_sources_in_use;
382  sourcepool = new SharedSourcePool(nbdynsources);
383  printf(" #static sources: %d\n", n_static_sources_in_use);
384  printf(" #dyn sources : %d\n", sourcepool->getNbSources());
385 }
386 
387 
389 {
390  // Do we have a source left for static assigned sources?
392  alGenSources (1, source);
393  int error = alGetError();
394  if (error != AL_NO_ERROR) {
395  return false;
396  } else {
398  return true;
399  }
400  } else {
401  return false;
402  }
403 }
404 
406 {
407  int id = smap->id;
408  float max_vol = smap->max_vol;
409  QSoundChar CarSoundData::*p2schar = smap->schar;
410  QSoundChar* schar = &(car_sound_data[id]->*p2schar);
411  TorcsSound* snd = smap->snd;
412 
413  sgVec3 p;
414  sgVec3 u = {0.0f, 0.0f, 0.0f};
415 
417 #ifdef USE_OPENAL_DOPPLER
418  car_sound_data[id]->getCarSpeed(u);
419 #endif
420  snd->setSource (p, u);
421  snd->setVolume (schar->a);
422 #ifdef USE_OPENAL_DOPPLER
423  snd->setPitch (schar->f);
424 #else
425  snd->setPitch (schar->f * car_src[id].f);
426 #endif
427  snd->update();
428  if (max_vol > VOLUME_CUTOFF) {
429  snd->start();
430  } else {
431  snd->stop();
432  }
433 }
QSoundChar road
Definition: CarSoundData.h:100
Sound source management.
Definition: TorcsSound.h:141
float a
amplitude
int id
car ID.
void update()
Calculate environmental parameters for current situation.
Definition: TorcsSound.cpp:201
QSoundChar engine_backfire
Definition: CarSoundData.h:96
QSoundChar axle
Definition: CarSoundData.h:95
static CarSoundData ** car_sound_data
Definition: grsound.cpp:38
TorcsSound * bang_sound
sounds when suspension fully compressed
QueueSoundMap axle
QueueSoundMap turbo
SharedSourcePool * sourcepool
int curCrashSnd
holds current crash sound used - the sound cycles
TorcsSound * getEngineSound()
Definition: CarSoundData.h:107
QSoundChar turbo
Definition: CarSoundData.h:94
virtual void setPitch(float pitch)
Set the pitch.
Definition: TorcsSound.cpp:30
A queue containing mappings between sounds and sound sources.
virtual void stop()=0
TorcsSound * bottom_crash_sound
bang when crashing from a great height
float f
Definition: QSoundChar.h:7
QSoundChar CarSoundData::* schar
The calculated sound characteristic.
#define SPEED_OF_SOUND
Definition: sound_defines.h:10
TorcsSound * curb_ride_sound
rolling on curb
void setSource(sgVec3 p, sgVec3 u)
Set source position and velocity.
Definition: TorcsSound.cpp:262
Manages the source sound of each individual car.
Definition: CarSoundData.h:25
QSoundChar skid
Definition: CarSoundData.h:21
TorcsSound * backfire_loop_sound
exhaust backfire sound
WheelSoundData wheel[4]
Definition: CarSoundData.h:84
QSoundChar grass
Definition: CarSoundData.h:99
QueueSoundMap grass_skid
TorcsSound * grass_skid_sound
skidding on dirt/grass
TorcsSound * turbo_sound
turbo spinning sound
virtual bool getStaticSource(ALuint *source)
QueueSoundMap grass
virtual TorcsSound * addSample(const char *filename, int flags=(ACTIVE_VOLUME|ACTIVE_PITCH), bool loop=false, bool static_pool=true)
TorcsSound * road_ride_sound
rolling on normal road
virtual void update(CarSoundData **car_sound_data, int n_cars, sgVec3 p_obs, sgVec3 u_obs, sgVec3 c_obs, sgVec3 a_obs)
float a
Definition: QSoundChar.h:6
virtual void setSource(sgVec3 p, sgVec3 u)
Definition: TorcsSound.h:76
void setListener(sgVec3 p, sgVec3 u)
Set listener position and velocity.
Definition: TorcsSound.cpp:272
QueueSoundMap backfire_loop
float f
Environmental frequency shift.
Definition: TorcsSound.h:148
static const int OSI_MIN_DYNAMIC_SOURCES
Define this to use the OpenAL Doppler.
float attenuation
global distance attenuation
Definition: CarSoundData.h:85
bool gear_changing
Definition: CarSoundData.h:140
TorcsSound * snd
The raw sound.
float a
Environmental attenuation.
Definition: TorcsSound.h:147
Definition: Endpoint.h:36
virtual void setVolume(float vol)
Set the volume.
Definition: TorcsSound.cpp:25
virtual void update()=0
SoundPri * engpri
the engine priority, used for sorting
virtual void setReferenceDistance(float dist)
Definition: TorcsSound.h:80
static Point p[4]
Definition: Convex.cpp:54
QSoundChar drag_collision
Definition: CarSoundData.h:93
virtual void SetMaxSoundCar(CarSoundData **car_sound_data, QueueSoundMap *smap)
QSoundChar engine
Definition: CarSoundData.h:92
QSoundChar curb
Definition: CarSoundData.h:98
OpenalSoundInterface(float sampling_rate, int n_channels)
virtual float getGlobalGain()
void SortSingleQueue(CarSoundData **car_sound_data, QueueSoundMap *smap, int n_cars)
Find the max amplitude sound in car_sound_data and put it in smap.
void getCarPosition(sgVec3 p)
Definition: CarSoundData.h:121
QueueSoundMap road
The following are mappings for sound prioritisation.
SoundSource * car_src
std::vector< TorcsSound * > sound_list
keeps track of sounds used
TorcsSound * gear_change_sound
sound when changing gears
Openal torcs sound.
Definition: TorcsSound.h:158
#define NB_CRASH_SOUND
Definition: sound_defines.h:11
int getNbSources(void)
virtual void initSharedSourcePool()
int n_engine_sounds
number of simultaneous engines
virtual void start()=0
Sound interface.
void getCarSpeed(sgVec3 u)
Definition: CarSoundData.h:127
void copyEngPri(SoundPri &epri)
Definition: CarSoundData.h:108
TorcsSound * crash_sound[NB_CRASH_SOUND]
list of crash sounds
TorcsSound * metal_skid_sound
metal skidding on metal
TorcsSound * grass_ride_sound
rolling on dirt/grass
QSoundChar grass_skid
Definition: CarSoundData.h:97
Definition: Endpoint.h:36
virtual void setNCars(int n_cars)
int sortSndPriority(const void *a, const void *b)
#define VOLUME_CUTOFF
QueueSoundMap metal_skid
float max_vol
Max.
TorcsSound * axle_sound
axle/gear spinning sound
TorcsSound * skid_sound[4]
set of skid sounds, one per tyre
float lp
Definition: QSoundChar.h:8
A generic TORCS sound.
Definition: TorcsSound.h:53
int id
The id of the car producing the sound, used for retrieving doppler effects etc.
QueueSoundMap curb
Sound priority, used to sort cars according to amplitude attenuation.