00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "audio3d.h"
00036
00037 #include "common/wave_ex.h"
00038 #include "perf/perf.h"
00039
00040
00041 namespace audio3d {
00042
00043
00044
00045 SoundManager::~SoundManager(void) throw() { }
00046
00047 static const float s_minR2 = 0.05;
00048
00049
00050
00051
00052
00053
00054
00055
00056 static void
00057 getVolumeAndPan
00058 (
00059 IN const point3d_t& r,
00060 IN const point3d_t& right,
00061 OUT float& volume,
00062 OUT float& pan
00063 )
00064 throw()
00065 {
00066 point3d_t n = r;
00067 normalize(n);
00068 pan = dotProduct(n, right);
00069 float R2 = dotProduct(r, r);
00070 if (R2 < s_minR2)
00071 R2 = s_minR2;
00072 volume = 1.0 / R2;
00073 }
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 class SndMgr : public SoundManager {
00084 public:
00085
00086 SndMgr(void) throw();
00087 ~SndMgr(void) throw() { }
00088
00089
00090 void initialize(IN const char * device_name,
00091 IN const char * parameters);
00092
00093
00094 id_t createListener(void);
00095 void updateListener(IN id_t listenerId,
00096 IN const point3d_t& position,
00097 IN const point3d_t& facing,
00098 IN const point3d_t& up);
00099 bool removeListener(IN id_t listenerId);
00100
00101 id_t createSound(IN id_t listenerId,
00102 IN const char * filename,
00103 IN float baseVolume);
00104 void updateSound(IN id_t soundId,
00105 IN const point3d_t& position);
00106 bool removeSound(IN id_t soundId);
00107
00108 void updateSounds(void);
00109
00110 private:
00111
00112 struct sound_t {
00113
00114 point3d_t position;
00115 audiere::OutputStreamPtr sound;
00116 float baseVolume;
00117 id_t listenerId;
00118 };
00119
00120 typedef std::map<id_t, smart_ptr<sound_t> > sound_map_t;
00121
00122 struct listener_t {
00123
00124 point3d_t position;
00125 point3d_t right;
00126 sound_map_t sounds;
00127 };
00128
00129 typedef std::map<id_t, smart_ptr<listener_t> > listener_map_t;
00130
00131
00132 id_t getNextId(void);
00133 listener_t * getListener(IN id_t id);
00134 sound_t * getSound(IN id_t id);
00135
00136
00137 audiere::AudioDevicePtr m_device;
00138 id_t m_objCtr;
00139 listener_map_t m_listeners;
00140 sound_map_t m_sounds;
00141 };
00142
00143
00144
00145 SndMgr::SndMgr(void)
00146 throw()
00147 {
00148 m_objCtr = 1;
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 void
00160 SndMgr::initialize
00161 (
00162 IN const char * device_name,
00163 IN const char * parameters
00164 )
00165 {
00166
00167
00168
00169
00170 m_device = audiere::OpenDevice(device_name, parameters);
00171 if (!m_device) {
00172 WAVE_EX(wex);
00173 wex << "Failed to open audio device";
00174 }
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 id_t
00186 SndMgr::createListener
00187 (
00188 void
00189 )
00190 {
00191 id_t id = this->getNextId();
00192
00193 smart_ptr<listener_t> l = new listener_t;
00194 ASSERT(l, "out of memory");
00195
00196
00197 l->position = point3d_t(0, 0, 0);
00198 l->right = point3d_t(1, 0, 0);
00199
00200 m_listeners[id] = l;
00201
00202 return id;
00203 }
00204
00205
00206
00207 void
00208 SndMgr::updateListener
00209 (
00210 IN id_t listenerId,
00211 IN const point3d_t& position,
00212 IN const point3d_t& facing,
00213 IN const point3d_t& up
00214 )
00215 {
00216 ASSERT(listenerId, "Bad listener id: %d", (int) listenerId);
00217
00218 listener_t * l = this->getListener(listenerId);
00219 ASSERT(l, "null");
00220
00221 l->position = position;
00222 l->right = crossProduct(facing, up);
00223 }
00224
00225
00226
00227 bool
00228 SndMgr::removeListener
00229 (
00230 IN id_t listenerId
00231 )
00232 {
00233 ASSERT(listenerId, "Bad listener id: %d", (int) listenerId);
00234
00235 listener_map_t::iterator i = m_listeners.find(listenerId);
00236 if (m_listeners.end() == i) {
00237 DPRINTF("Listener not found? %d", (int) listenerId);
00238 return false;
00239 }
00240 m_listeners.erase(i);
00241 return true;
00242 }
00243
00244
00245
00246 id_t
00247 SndMgr::createSound
00248 (
00249 IN id_t listenerId,
00250 IN const char * filename,
00251 IN float baseVolume
00252 )
00253 {
00254 ASSERT(listenerId, "bad listener id: %d", (int) listenerId);
00255 ASSERT(filename, "null");
00256 ASSERT(baseVolume >= 0.0 && baseVolume <= 1.0,
00257 "bad base volume: %f", baseVolume);
00258
00259
00260 listener_t * l = this->getListener(listenerId);
00261 ASSERT(l, "null");
00262
00263
00264 smart_ptr<sound_t> sound = new sound_t;
00265 ASSERT(sound, "out of memory");
00266
00267 sound->sound = audiere::OpenSound(m_device, filename);
00268 if (!sound->sound) {
00269 WAVE_EX(wex);
00270 wex << "Failed to create sound from file: " << filename;
00271 }
00272 sound->listenerId = listenerId;
00273 sound->baseVolume = baseVolume;
00274
00275
00276 id_t id = this->getNextId();
00277 l->sounds[id] = sound;
00278 m_sounds[id] = sound;
00279 ASSERT(3 == sound.get_ref_count(), "bad ref count!");
00280
00281 return id;
00282 }
00283
00284
00285
00286 void
00287 SndMgr::updateSound
00288 (
00289 IN id_t soundId,
00290 IN const point3d_t& position
00291 )
00292 {
00293 ASSERT(soundId, "Bad sound id: %d", (int) soundId);
00294
00295 sound_t * sound = this->getSound(soundId);
00296 ASSERT(sound, "null");
00297
00298 sound->position = position;
00299 }
00300
00301
00302
00303 bool
00304 SndMgr::removeSound
00305 (
00306 IN id_t soundId
00307 )
00308 {
00309 ASSERT(soundId, "Bad sound id: %d", (int) soundId);
00310
00311 bool retval = false;
00312
00313
00314 sound_t * sound = this->getSound(soundId);
00315
00316
00317 listener_t * l = this->getListener(sound->listenerId);
00318 ASSERT(l, "null");
00319 sound_map_t::iterator i = l->sounds.find(soundId);
00320 if (l->sounds.end() != i) {
00321 l->sounds.erase(i);
00322 }
00323
00324
00325 i = m_sounds.find(soundId);
00326 if (m_sounds.end() != i) {
00327 m_sounds.erase(i);
00328 retval = true;
00329 }
00330
00331 return retval;
00332 }
00333
00334
00335
00336 void
00337 SndMgr::updateSounds
00338 (
00339 void
00340 )
00341 {
00342
00343 for (listener_map_t::iterator i = m_listeners.begin();
00344 i != m_listeners.end(); ++i) {
00345
00346 listener_t * l = i->second;
00347 ASSERT(l, "null listener in map?");
00348
00349
00350 for (sound_map_t::iterator j = l->sounds.begin();
00351 j != l->sounds.end(); ++j) {
00352 sound_t * sound = j->second;
00353 ASSERT(sound, "null sound in space map?");
00354 ASSERT(sound->sound, "null");
00355
00356
00357 float volume, pan;
00358 getVolumeAndPan(sound->position - l->position,
00359 l->right, volume, pan);
00360 ASSERT(volume >= 0 && volume <= 1, "Bad volume: %f",
00361 volume);
00362 ASSERT(pan >= -1 && pan <= 1, "Bad pan: %f", pan);
00363
00364 volume *= sound->baseVolume;
00365 if (volume > 1.0) {
00366 volume = 1.0;
00367 }
00368
00369
00370 sound->sound->setVolume(volume);
00371 sound->sound->setPan(pan);
00372
00373
00374 if (!sound->sound->isPlaying())
00375 sound->sound->play();
00376 }
00377 }
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 id_t
00389 SndMgr::getNextId
00390 (
00391 void
00392 )
00393 {
00394 id_t id = m_objCtr;
00395 m_objCtr++;
00396 return id;
00397 }
00398
00399
00400
00401 SndMgr::listener_t *
00402 SndMgr::getListener
00403 (
00404 IN id_t id
00405 )
00406 {
00407 ASSERT(id, "null");
00408
00409 listener_map_t::iterator i = m_listeners.find(id);
00410 ASSERT(m_listeners.end() != i, "No such listener: %d", (int) id);
00411 return i->second;
00412 }
00413
00414
00415
00416 SndMgr::sound_t *
00417 SndMgr::getSound
00418 (
00419 IN id_t id
00420 )
00421 {
00422 ASSERT(id, "null");
00423
00424 sound_map_t::iterator i = m_sounds.find(id);
00425 ASSERT(m_sounds.end() != i, "no such sound: %d", (int) id);
00426
00427 return i->second;
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438 smart_ptr<SoundManager>
00439 SoundManager::create
00440 (
00441 IN const char * device_name,
00442 IN const char * parameters
00443 )
00444 {
00445
00446
00447
00448 smart_ptr<SndMgr> local = new SndMgr;
00449 ASSERT(local, "out of memory");
00450
00451 local->initialize(device_name, parameters);
00452
00453 return local;
00454 }
00455
00456
00457
00458 };
00459