00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <console/ConsoleRuleMethodIAdapter.h>
00022 #include <common/Defines.h>
00023 #include <graph/OptionsDisplay.h>
00024 #include <common/Logger.h>
00025 #include <sound/Sound.h>
00026 #include <sound/SoundBufferFactory.h>
00027 #include <sound/PlayingSoundSource.h>
00028 #include <graph/OptionsDisplay.h>
00029 #ifdef __DARWIN__
00030 #include <OpenAL/al.h>
00031 #include <OpenAL/alc.h>
00032 #include <OpenAL/alut.h>
00033 #else
00034 #include <AL/al.h>
00035 #include <AL/alc.h>
00036 #include <AL/alut.h>
00037 #endif
00038 #include <algorithm>
00039
00040 Sound *Sound::instance_ = 0;
00041
00042 Sound *Sound::instance()
00043 {
00044 if (!instance_)
00045 {
00046 instance_ = new Sound;
00047 }
00048
00049 return instance_;
00050 }
00051
00052 Sound::Sound() :
00053 init_(false), totalTime_(0.0f),
00054 GameStateI("Sound")
00055 {
00056 new ConsoleRuleMethodIAdapter<Sound>(
00057 this, &Sound::showSoundBuffers, "SoundBuffers");
00058 new ConsoleRuleMethodIAdapterEx<Sound>(
00059 this, &Sound::soundPlay, "SoundPlay",
00060 ConsoleUtil::formParams(
00061 ConsoleRuleParam("filename", ConsoleRuleTypeString)));
00062 }
00063
00064 Sound::~Sound()
00065 {
00066 if (init_)
00067 {
00068 {
00069 SourceList::iterator itor;
00070 for (itor = totalSources_.begin();
00071 itor != totalSources_.end();
00072 itor++)
00073 {
00074 SoundSource *source = (*itor);
00075 delete source;
00076 }
00077 }
00078 {
00079 BufferMap::iterator itor;
00080 for (itor = bufferMap_.begin();
00081 itor != bufferMap_.end();
00082 itor++)
00083 {
00084 SoundBuffer *buffer = (*itor).second;
00085 delete buffer;
00086 }
00087 }
00088
00089 ALCcontext *context = alcGetCurrentContext();
00090 ALCdevice *device = alcGetContextsDevice(context);
00091 alcDestroyContext(context);
00092 alcCloseDevice(device);
00093 }
00094 init_ = false;
00095 }
00096
00097 void Sound::destroy()
00098 {
00099 delete this;
00100 instance_ = 0;
00101 }
00102
00103 static char *checkString(char *x)
00104 {
00105 return (char *)(x?x:"null");
00106 }
00107
00108 bool Sound::init(int channels)
00109 {
00110 ALCdevice *soundDevice = alcOpenDevice(0);
00111 if (!soundDevice)
00112 {
00113 S3D::dialogMessage("Scorched3D", "Failed to open sound device");
00114 return false;
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124 ALCcontext *soundContext = alcCreateContext(soundDevice, 0);
00125 if (!soundContext)
00126 {
00127 S3D::dialogMessage("Scorched3D", "Failed to create sound context");
00128 return false;
00129 }
00130
00131 alcMakeContextCurrent(soundContext);
00132 alDistanceModel(AL_INVERSE_DISTANCE);
00133
00134 Logger::log(S3D::formatStringBuffer("AL_VENDOR:%s",
00135 checkString((char *) alGetString(AL_VENDOR))));
00136 Logger::log(S3D::formatStringBuffer("AL_VERSION:%s",
00137 checkString((char *) alGetString(AL_VERSION))));
00138 Logger::log(S3D::formatStringBuffer("AL_RENDERER:%s",
00139 checkString((char *) alGetString(AL_RENDERER))));
00140 Logger::log(S3D::formatStringBuffer("AL_EXTENSIONS:%s",
00141 checkString((char *) alGetString(AL_EXTENSIONS))));
00142 Logger::log(S3D::formatStringBuffer("ALC_DEVICE_SPECIFIER:%s",
00143 checkString((char *) alcGetString(soundDevice, ALC_DEVICE_SPECIFIER))));
00144
00145
00146 for (int i=1; i<=OptionsDisplay::instance()->getSoundChannels(); i++)
00147 {
00148 SoundSource *source = new SoundSource;
00149 if (!source->create())
00150 {
00151 S3D::dialogMessage("Scorched3D",
00152 S3D::formatStringBuffer("Failed to create sound channel number %i", i));
00153 return false;
00154 }
00155 totalSources_.push_back(source);
00156 availableSources_.push_back(source);
00157 }
00158
00159 init_ = true;
00160 return init_;
00161 }
00162
00163 void Sound::soundPlay(std::vector<ConsoleRuleValue> &values)
00164 {
00165 ConsoleRuleValue &fileName = values[1];
00166
00167 SoundBuffer *buffer =
00168 fetchOrCreateBuffer(fileName.valueString);
00169 VirtualSoundSource *source =
00170 new VirtualSoundSource(10000, false, true);
00171 source->setRelative();
00172 source->play(buffer);
00173 }
00174
00175 void Sound::showSoundBuffers()
00176 {
00177
00178 int i = 1;
00179 Logger::log(S3D::formatStringBuffer("%i sounds playing, %i sources free",
00180 getPlayingChannels(),
00181 getAvailableChannels()));
00182 PlayingSourceList::iterator itor;
00183 for (itor = playingSources_.begin();
00184 itor != playingSources_.end();
00185 itor++, i++)
00186 {
00187 PlayingSoundSource *source = (*itor);
00188 if (source->getVirtualSource())
00189 {
00190 Logger::log(S3D::formatStringBuffer("%i - %u,%f - %s%s:%s",
00191 i,
00192 source->getVirtualSource()->getPriority(),
00193 source->getVirtualSource()->getDistance(),
00194 (source->getStopped()?"Finished":(source->getVirtualSource()->getPlaying()?"Playing":"Stopped")),
00195 (source->getVirtualSource()->getLooping()?"(Looped)":""),
00196 source->getVirtualSource()->getBuffer()->getFileName()));
00197 }
00198 else
00199 {
00200 Logger::log(S3D::formatStringBuffer("%i - Pending Removal"));
00201 }
00202 }
00203 }
00204
00205 void Sound::simulate(const unsigned state, float frameTime)
00206 {
00207
00208
00209 PlayingSourceList::iterator playingitor;
00210 for (playingitor = playingSources_.begin();
00211 playingitor != playingSources_.end();
00212 playingitor++)
00213 {
00214 SoundSource *source = (*playingitor)->getActualSource();
00215 if (source && source->getPlaying())
00216 {
00217 source->simulate();
00218 }
00219 }
00220
00221
00222 totalTime_ += frameTime;
00223 if (totalTime_ < 0.2f) return;
00224 totalTime_ = 0.0f;
00225
00226 updateSources();
00227 }
00228
00229 static inline bool lt_virt(PlayingSoundSource *p2, PlayingSoundSource *p1)
00230 {
00231 float dist1 = 0.0f;
00232 float dist2 = 0.0f;
00233 unsigned int priority1 = 0;
00234 unsigned int priority2 = 0;
00235
00236 VirtualSoundSource *v1 = p1->getVirtualSource();
00237 VirtualSoundSource *v2 = p2->getVirtualSource();
00238
00239 if (v1 && !p1->getStopped()) priority1 = v1->getPriority();
00240 if (v2 && !p2->getStopped()) priority2 = v2->getPriority();
00241 if (v1) dist1 = v1->getDistance();
00242 if (v2) dist2 = v2->getDistance();
00243
00244 return (priority1 < priority2 ||
00245 (priority1 == priority2 && dist1 > dist2));
00246 }
00247
00248 void Sound::addPlaying(VirtualSoundSource *virt)
00249 {
00250
00251 PlayingSoundSource *source = new PlayingSoundSource(virt);
00252 playingSources_.push_back(source);
00253 virt->setPlayingSource(source);
00254
00255 updateSources();
00256 }
00257
00258 void Sound::updateSources()
00259 {
00260
00261 Vector listenerPosition = listener_.getPosition();
00262 PlayingSourceList::iterator fitor;
00263 for (fitor = playingSources_.begin();
00264 fitor != playingSources_.end();
00265 fitor++)
00266 {
00267 PlayingSoundSource *source = (*fitor);
00268 if (source->getVirtualSource())
00269 {
00270 source->getVirtualSource()->updateDistance(listenerPosition);
00271 }
00272 }
00273
00274
00275 std::sort(playingSources_.begin(), playingSources_.end(), lt_virt);
00276
00277
00278 int totalSources = (int) totalSources_.size();
00279 int totalPlaying = (int) playingSources_.size();
00280 int count = 0;
00281 PlayingSourceList::reverse_iterator ritor;
00282 for (ritor = playingSources_.rbegin();
00283 ritor != playingSources_.rend();
00284 ritor++, count++)
00285 {
00286 PlayingSoundSource *source = (*ritor);
00287
00288 bool stopSource = false;
00289
00290
00291 if (source->getStopped())
00292 {
00293 stopSource = true;
00294 }
00295
00296 else if (totalPlaying - count <= totalSources)
00297 {
00298 if (source->getActualSource())
00299 {
00300 if (source->getActualSource()->getPlaying())
00301 {
00302
00303 }
00304 else
00305 {
00306
00307 stopSource = true;
00308 }
00309 }
00310 else if (!source->getActualSource())
00311 {
00312
00313 DIALOG_ASSERT(!availableSources_.empty());
00314 source->setActualSource(availableSources_.back());
00315 availableSources_.pop_back();
00316 source->getVirtualSource()->actualPlay();
00317 }
00318 }
00319
00320 else
00321 {
00322 stopSource = true;
00323 }
00324
00325
00326 if (stopSource)
00327 {
00328
00329 if (source->getActualSource())
00330 {
00331
00332 source->getActualSource()->stop();
00333 availableSources_.push_back(source->getActualSource());
00334 source->setActualSource(0);
00335 }
00336
00337
00338 if (source->getVirtualSource())
00339 {
00340 if (!source->getVirtualSource()->getLooping())
00341 {
00342 source->setStopped(true);
00343 }
00344 }
00345 }
00346 }
00347
00348
00349 while (!playingSources_.empty())
00350 {
00351 PlayingSoundSource *source = playingSources_.back();
00352 if (source->getStopped())
00353 {
00354 if (source->getVirtualSource())
00355 {
00356 source->getVirtualSource()->setPlayingSource(0);
00357 }
00358
00359 DIALOG_ASSERT(!(source->getActualSource()));
00360 delete source;
00361 playingSources_.pop_back();
00362 }
00363 else break;
00364 }
00365
00366
00367
00368
00369 bool repeat = true;
00370 while (repeat)
00371 {
00372 repeat = false;
00373 VirtualSourceList::iterator manitor;
00374 for (manitor = managedSources_.begin();
00375 manitor != managedSources_.end();
00376 manitor++)
00377 {
00378 VirtualSoundSource *source = (*manitor);
00379 if (!source->getPlaying())
00380 {
00381 managedSources_.erase(manitor);
00382 delete source;
00383 repeat = true;
00384 break;
00385 }
00386 }
00387 }
00388 }
00389
00390 void Sound::removePlaying(VirtualSoundSource *virt)
00391 {
00392 if (virt->getPlayingSource())
00393 {
00394 virt->getPlayingSource()->setStopped(true);
00395 virt->getPlayingSource()->setVirtualSource(0);
00396 }
00397 virt->setPlayingSource(0);
00398
00399 updateSources();
00400 }
00401
00402 void Sound::addManaged(VirtualSoundSource *source)
00403 {
00404 managedSources_.push_back(source);
00405 }
00406
00407 int Sound::getAvailableChannels()
00408 {
00409 return availableSources_.size();
00410 }
00411
00412 int Sound::getPlayingChannels()
00413 {
00414 return playingSources_.size();
00415 }
00416
00417 SoundListener *Sound::getDefaultListener()
00418 {
00419 return &listener_;
00420 }
00421
00422 SoundBuffer *Sound::createBuffer(char *fileName)
00423 {
00424
00425 SoundBuffer *buffer = SoundBufferFactory::createBuffer(
00426 (const char *) fileName);
00427 if (!buffer)
00428 {
00429 S3D::dialogExit("Failed to load sound",
00430 S3D::formatStringBuffer("\"%s\"", fileName));
00431
00432 delete buffer;
00433 return 0;
00434 }
00435 return buffer;
00436 }
00437
00438 SoundBuffer *Sound::fetchOrCreateBuffer(const std::string &filename)
00439 {
00440 BufferMap::iterator itor = bufferMap_.find(filename);
00441 if (itor != bufferMap_.end())
00442 {
00443 return (*itor).second;
00444 }
00445
00446 SoundBuffer *buffer = createBuffer((char *) filename.c_str());
00447 bufferMap_[filename] = buffer;
00448 return buffer;
00449 }