Changeset 6412 for code/branches/pickup2/src/orxonox/sound
- Timestamp:
- Dec 25, 2009, 1:18:03 PM (15 years ago)
- Location:
- code/branches/pickup2
- Files:
-
- 10 edited
- 4 copied
Legend:
- Unmodified
- Added
- Removed
-
code/branches/pickup2
- Property svn:mergeinfo changed
-
code/branches/pickup2/src/orxonox/sound/AmbientSound.cc
r5929 r6412 31 31 #include "core/CoreIncludes.h" 32 32 #include "core/EventIncludes.h" 33 #include "core/GameMode.h" 34 #include "core/Resource.h" 33 35 #include "core/XMLPort.h" 36 #include "SoundManager.h" 34 37 35 38 namespace orxonox … … 39 42 AmbientSound::AmbientSound(BaseObject* creator) 40 43 : BaseObject(creator) 44 , Synchronisable(creator) 45 , bPlayOnLoad_(false) 41 46 { 42 47 RegisterObject(AmbientSound); 48 49 // Ambient sounds always fade in 50 this->setVolume(0); 51 this->registerVariables(); 43 52 } 44 53 45 AmbientSound::~AmbientSound()54 void AmbientSound::preDestroy() 46 55 { 56 if (GameMode::playsSound()) 57 { 58 // Smoothly fade out by keeping a SmartPtr 59 SoundManager::getInstance().unregisterAmbientSound(this); 60 } 61 } 62 63 void AmbientSound::registerVariables() 64 { 65 registerVariable(ambientSource_, ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::ambientSourceChanged)); 66 registerVariable(bLooping_, ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::loopingChanged)); 67 registerVariable(pitch_, ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::pitchChanged)); 68 registerVariable(bPlayOnLoad_, ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::playOnLoadChanged)); 47 69 } 48 70 … … 50 72 { 51 73 SUPER(AmbientSound, XMLPort, xmlelement, mode); 52 XMLPortParamExtern(AmbientSound, BaseSound, this, "source", setSource, getSource,xmlelement, mode);53 XMLPortParam Extern(AmbientSound, BaseSound, this, "loop", setLoop, getLoop, xmlelement, mode);54 XMLPortParam Extern(AmbientSound, BaseSound, this, "playOnLoad", setPlayOnLoad, getPlayOnLoad, xmlelement, mode);74 BaseSound::XMLPortExtern(xmlelement, mode); 75 XMLPortParam(AmbientSound, "ambientSource", setAmbientSource, getAmbientSource, xmlelement, mode); 76 XMLPortParam(AmbientSound, "playOnLoad", setPlayOnLoad, getPlayOnLoad, xmlelement, mode); 55 77 } 56 78 … … 60 82 XMLPortEventState(AmbientSound, BaseObject, "play", play, xmlelement, mode); 61 83 } 84 85 void AmbientSound::play() 86 { 87 if (GameMode::playsSound()) 88 SoundManager::getInstance().registerAmbientSound(this); 89 } 90 91 void AmbientSound::stop() 92 { 93 if (GameMode::playsSound()) 94 SoundManager::getInstance().unregisterAmbientSound(this); 95 } 96 97 void AmbientSound::pause() 98 { 99 if (GameMode::playsSound()) 100 SoundManager::getInstance().pauseAmbientSound(this); 101 } 102 103 float AmbientSound::getRealVolume() 104 { 105 assert(GameMode::playsSound()); 106 return SoundManager::getInstance().getRealVolume(SoundType::Music); 107 } 108 109 void AmbientSound::setAmbientSource(const std::string& source) 110 { 111 this->ambientSource_ = source; 112 this->moodChanged(this->getMood()); 113 } 114 115 void AmbientSound::moodChanged(const std::string& mood) 116 { 117 if (GameMode::playsSound()) 118 { 119 const std::string& path = "ambient/" + MoodManager::getInstance().getMood() + '/' + this->ambientSource_; 120 shared_ptr<ResourceInfo> fileInfo = Resource::getInfo(path); 121 if (fileInfo != NULL) 122 this->setSource(path); 123 else 124 COUT(3) << "Sound: " << this->ambientSource_ << ": Not a valid name! Ambient sound will not change." << std::endl; 125 } 126 } 127 128 void AmbientSound::setPlayOnLoad(bool val) 129 { 130 this->bPlayOnLoad_ = val; 131 if (val) 132 this->play(); 133 } 134 135 void AmbientSound::changedActivity() 136 { 137 SUPER(AmbientSound, changedActivity); 138 if (this->isActive()) 139 this->play(); 140 else 141 this->stop(); 142 } 62 143 } -
code/branches/pickup2/src/orxonox/sound/AmbientSound.h
r5929 r6412 22 22 * Author: 23 23 * Reto Grieder 24 * Kevin Young 24 25 * Co-authors: 25 26 * ... 26 27 * 27 28 */ 29 28 30 #ifndef _AmbientSound_H__ 29 31 #define _AmbientSound_H__ … … 32 34 33 35 #include "core/BaseObject.h" 34 #include "sound/BaseSound.h" 36 #include "network/synchronisable/Synchronisable.h" 37 #include "BaseSound.h" 38 #include "MoodManager.h" 35 39 36 40 namespace orxonox … … 41 45 * 42 46 */ 43 class _OrxonoxExport AmbientSound : public BaseSound, public BaseObject 47 class _OrxonoxExport AmbientSound : public BaseSound, public BaseObject, public Synchronisable, public MoodListener 44 48 { 49 friend class SoundManager; 50 45 51 public: 46 52 AmbientSound(BaseObject* creator); 47 virtual ~AmbientSound();48 53 49 virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); 50 virtual void XMLEventPort(Element& xmlelement, XMLPort::Mode mode); 54 void XMLPort(Element& xmlelement, XMLPort::Mode mode); 55 void XMLEventPort(Element& xmlelement, XMLPort::Mode mode); 56 void changedActivity(); 57 58 void play(); 59 void stop(); 60 void pause(); 61 62 void setAmbientSource(const std::string& source); 63 inline const std::string& getAmbientSource() const 64 { return this->ambientSource_; } 65 66 void setPlayOnLoad(bool val); 67 bool getPlayOnLoad() const 68 { return this->bPlayOnLoad_; } 69 70 protected: 71 ~AmbientSound() { } 51 72 52 73 private: 74 void preDestroy(); 75 void registerVariables(); 76 float getRealVolume(); 77 void moodChanged(const std::string& mood); 78 inline void ambientSourceChanged() 79 { this->setAmbientSource(this->ambientSource_); } 80 inline void playOnLoadChanged() 81 { this->setPlayOnLoad(this->bPlayOnLoad_); } 82 83 std::string ambientSource_; //!< Analogous to source_, but mood independent 84 bool bPlayOnLoad_; //!< Play the sound immediately when loaded 53 85 }; 54 86 } -
code/branches/pickup2/src/orxonox/sound/BaseSound.cc
r5929 r6412 29 29 #include "BaseSound.h" 30 30 31 #include <cassert> 31 32 #include <vector> 32 #include <AL/alut.h> 33 #include <vorbis/vorbisfile.h> 33 #include <al.h> 34 34 35 35 #include "core/CoreIncludes.h" 36 36 #include "core/GameMode.h" 37 37 #include "core/Resource.h" 38 #include "core/XMLPort.h" 39 #include "SoundBuffer.h" 40 #include "SoundManager.h" 38 41 39 42 namespace orxonox 40 43 { 41 44 BaseSound::BaseSound() 42 : audioSource_(0) 43 , audioBuffer_(0) 44 , bPlayOnLoad_(false) 45 , bLoop_(false) 45 : bPooling_(false) 46 , volume_(1.0) 47 , bLooping_(false) 48 , state_(Stopped) 49 , pitch_ (1.0) 46 50 { 47 51 RegisterRootObject(BaseSound); 52 53 // Initialise audioSource_ to a value that is not a source 54 // 0 is unfortunately not guaranteed to be no source ID. 55 this->audioSource_ = 123456789; 56 while (alIsSource(++this->audioSource_)); 48 57 } 49 58 50 59 BaseSound::~BaseSound() 51 60 { 52 this->setSource(""); 53 } 54 55 void BaseSound::play() 56 { 57 if (alIsSource(this->audioSource_)) 58 { 59 if (this->bLoop_) 60 alSourcei(this->audioSource_, AL_LOOPING, AL_TRUE); 61 else 62 alSourcei(this->audioSource_, AL_LOOPING, AL_FALSE); 61 this->stop(); 62 // Release buffer 63 if (this->soundBuffer_ != NULL) 64 { 65 assert(GameMode::playsSound()); 66 SoundManager::getInstance().releaseSoundBuffer(this->soundBuffer_, this->bPooling_); 67 } 68 } 69 70 void BaseSound::XMLPortExtern(Element& xmlelement, XMLPort::Mode mode) 71 { 72 XMLPortParam(BaseSound, "volume", setVolume, getVolume, xmlelement, mode); 73 XMLPortParam(BaseSound, "looping", setLooping, getLooping, xmlelement, mode); 74 XMLPortParam(BaseSound, "pitch", setPitch, getPitch, xmlelement, mode); 75 XMLPortParam(BaseSound, "source", setSource, getSource, xmlelement, mode); 76 } 77 78 void BaseSound::doPlay() 79 { 80 this->state_ = Playing; 81 if (GameMode::playsSound() && this->getSourceState() != AL_PLAYING && this->soundBuffer_ != NULL) 82 { 83 if (!alIsSource(this->audioSource_)) 84 { 85 this->audioSource_ = SoundManager::getInstance().getSoundSource(this); 86 if (!alIsSource(this->audioSource_)) 87 return; 88 this->initialiseSource(); 89 } 90 63 91 alSourcePlay(this->audioSource_); 64 65 if (alGetError() != AL_NO_ERROR) 66 { 67 COUT(2) << "Sound: OpenAL: Error playin sound " << this->audioSource_ << std::endl; 68 } 69 } 70 } 71 72 void BaseSound::stop() 73 { 74 if (alIsSource(this->audioSource_)) 92 if (int error = alGetError()) 93 COUT(2) << "Sound: Error playing sound: " << SoundManager::getALErrorString(error) << std::endl; 94 } 95 } 96 97 void BaseSound::doStop() 98 { 99 this->state_ = Stopped; 100 if (alIsSource(this->audioSource_)) 101 { 75 102 alSourceStop(this->audioSource_); 76 } 77 78 void BaseSound::pause() 79 { 103 // Release buffer 104 alSourcei(this->audioSource_, AL_BUFFER, AL_NONE); 105 // Release source again 106 SoundManager::getInstance().releaseSoundSource(this->audioSource_); 107 // Get a no source ID 108 this->audioSource_ += 123455; 109 while (alIsSource(++this->audioSource_)); 110 } 111 } 112 113 void BaseSound::doPause() 114 { 115 if (this->isStopped()) 116 return; 117 this->state_ = Paused; 80 118 if (alIsSource(this->audioSource_)) 81 119 alSourcePause(this->audioSource_); 82 120 } 83 121 84 bool BaseSound::isPlaying() 85 { 86 if (alIsSource(this->audioSource_)) 87 return getSourceState() == AL_PLAYING; 88 return false; 89 } 90 91 bool BaseSound::isPaused() 92 { 93 if (alIsSource(this->audioSource_)) 94 return getSourceState() == AL_PAUSED; 95 return true; 96 } 97 98 bool BaseSound::isStopped() 99 { 100 if (alIsSource(this->audioSource_)) 101 return getSourceState() == AL_INITIAL || getSourceState() == AL_STOPPED; 102 return true; 103 } 104 105 void BaseSound::setPlayOnLoad(bool val) 106 { 107 this->bPlayOnLoad_ = true; 108 this->play(); 122 ALint BaseSound::getSourceState() const 123 { 124 if (alIsSource(this->audioSource_)) 125 { 126 ALint state; 127 alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state); 128 return state; 129 } 130 else 131 return AL_INITIAL; 132 } 133 134 void BaseSound::initialiseSource() 135 { 136 this->updateVolume(); 137 this->setPitch(this->getPitch()); 138 this->setLooping(this->getLooping()); 139 alSource3f(this->audioSource_, AL_POSITION, 0, 0, 0); 140 alSource3f(this->audioSource_, AL_VELOCITY, 0, 0, 0); 141 alSource3f(this->audioSource_, AL_DIRECTION, 0, 0, 0); 142 if (ALint error = alGetError()) 143 COUT(2) << "Sound Warning: Setting source parameters to 0 failed: " 144 << SoundManager::getALErrorString(error) << std::endl; 145 assert(this->soundBuffer_ != NULL); 146 alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer()); 147 if (ALuint error = alGetError()) 148 COUT(1) << "Sound Error: Could not set buffer \"" << this->source_ << "\": " << SoundManager::getALErrorString(error) << std::endl; 149 } 150 151 void BaseSound::setVolume(float vol) 152 { 153 this->volume_ = clamp(vol, 0.0f, 1.0f); 154 if (this->volume_ != vol) 155 COUT(2) << "Sound warning: volume out of range, clamping value." << std::endl; 156 this->updateVolume(); 157 } 158 159 void BaseSound::updateVolume() 160 { 161 if (alIsSource(this->audioSource_)) 162 { 163 float volume = this->volume_ * this->getRealVolume(); 164 alSourcef(this->audioSource_, AL_GAIN, volume); 165 if (int error = alGetError()) 166 COUT(2) << "Sound: Error setting volume to " << volume 167 << ": " << SoundManager::getALErrorString(error) << std::endl; 168 } 169 } 170 171 void BaseSound::setLooping(bool val) 172 { 173 this->bLooping_ = val; 174 if (alIsSource(this->audioSource_)) 175 alSourcei(this->audioSource_, AL_LOOPING, (val ? AL_TRUE : AL_FALSE)); 176 } 177 178 void BaseSound::setPitch(float pitch) 179 { 180 if (pitch > 2 || pitch < 0.5) 181 { 182 COUT(2) << "Sound warning: pitch out of range, cropping value." << std::endl; 183 pitch = pitch > 2 ? 2 : pitch; 184 pitch = pitch < 0.5 ? 0.5 : pitch; 185 } 186 this->pitch_ = pitch; 187 if (alIsSource(this->audioSource_)) 188 { 189 alSourcef(this->audioSource_, AL_PITCH, pitch); 190 if (int error = alGetError()) 191 COUT(2) << "Sound: Error setting pitch: " << SoundManager::getALErrorString(error) << std::endl; 192 } 109 193 } 110 194 111 195 void BaseSound::setSource(const std::string& source) 112 196 { 197 if (!GameMode::playsSound()) 198 { 199 this->source_ = source; 200 return; 201 } 202 203 if (this->soundBuffer_ != NULL) 204 { 205 if (this->soundBuffer_->getFilename() == source) 206 { 207 assert(this->source_ == source_); 208 return; 209 } 210 // Stopping is imperative here! 211 if (alIsSource(this->audioSource_)) 212 { 213 alSourceStop(this->audioSource_); 214 alSourcei(this->audioSource_, AL_BUFFER, AL_NONE); 215 } 216 SoundManager::getInstance().releaseSoundBuffer(this->soundBuffer_, this->bPooling_); 217 this->soundBuffer_.reset(); 218 } 219 113 220 this->source_ = source; 114 if (!GameMode::playsSound()) 115 return; 116 117 if (source.empty() && alIsSource(this->audioSource_)) 118 { 119 // Unload sound 120 alSourcei(this->audioSource_, AL_BUFFER, 0); 121 alDeleteSources(1, &this->audioSource_); 122 alDeleteBuffers(1, &this->audioBuffer_); 123 return; 124 } 125 126 COUT(3) << "Sound: OpenAL ALUT: loading file " << source << std::endl; 127 // Get DataStream from the resources 128 shared_ptr<ResourceInfo> fileInfo = Resource::getInfo(source); 129 if (fileInfo == NULL) 130 { 131 COUT(2) << "Warning: Sound file '" << source << "' not found" << std::endl; 132 return; 133 } 134 dataStream_ = Resource::open(source); 135 // Read everything into a temporary buffer 136 char* buffer = new char[fileInfo->size]; 137 dataStream_->read(buffer, fileInfo->size); 138 dataStream_->seek(0); 139 140 this->audioBuffer_ = alutCreateBufferFromFileImage(buffer, fileInfo->size); 141 delete[] buffer; 142 143 if (this->audioBuffer_ == AL_NONE) 144 { 145 COUT(2) << "Sound: OpenAL ALUT: " << alutGetErrorString(alutGetError()) << std::endl; 146 if (source.find("ogg", 0) != std::string::npos) 147 { 148 COUT(2) << "Sound: Trying fallback ogg loader" << std::endl; 149 this->audioBuffer_ = loadOggFile(); 150 } 151 152 if (this->audioBuffer_ == AL_NONE) 153 { 154 COUT(2) << "Sound: fallback ogg loader failed: " << alutGetErrorString(alutGetError()) << std::endl; 221 // Don't load "" 222 if (source_.empty()) 223 return; 224 225 // Get new sound buffer 226 this->soundBuffer_ = SoundManager::getInstance().getSoundBuffer(this->source_); 227 if (this->soundBuffer_ == NULL) 228 return; 229 230 if (alIsSource(this->audioSource_)) // already playing or paused 231 { 232 // Set new buffer 233 alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer()); 234 if (ALuint error = alGetError()) 235 { 236 COUT(1) << "Sound Error: Could not set buffer \"" << source << "\": " << SoundManager::getALErrorString(error) << std::endl; 155 237 return; 156 238 } 157 } 158 159 alGenSources(1, &this->audioSource_); 160 alSourcei(this->audioSource_, AL_BUFFER, this->audioBuffer_); 161 if (alGetError() != AL_NO_ERROR) 162 { 163 COUT(2) << "Sound: OpenAL: Error loading sample file: " << source << std::endl; 164 return; 165 } 166 167 alSource3f(this->audioSource_, AL_POSITION, 0, 0, 0); 168 169 if (this->bPlayOnLoad_) 170 this->play(); 171 } 172 173 ALint BaseSound::getSourceState() 174 { 175 ALint state; 176 alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state); 177 return state; 178 } 179 180 size_t readVorbis(void* ptr, size_t size, size_t nmemb, void* datasource) 181 { 182 return static_cast<Ogre::DataStream*>(datasource)->read(ptr, size * nmemb); 183 } 184 185 int seekVorbis(void* datasource, ogg_int64_t offset, int whence) 186 { 187 Ogre::DataStream* stream = static_cast<Ogre::DataStream*>(datasource); 188 int offset_beg = offset; 189 if (whence == SEEK_CUR) 190 offset_beg = stream->tell() + offset; 191 else if (whence == SEEK_END) 192 offset_beg = stream->size() + offset; 193 else if (whence != SEEK_SET) 194 return -1; 195 stream->seek(offset_beg); 196 return 0; 197 } 198 199 long tellVorbis(void* datasource) 200 { 201 return static_cast<long>(static_cast<Ogre::DataStream*>(datasource)->tell()); 202 } 203 204 ALuint BaseSound::loadOggFile() 205 { 206 char inbuffer[4096]; 207 std::vector<char> outbuffer; 208 OggVorbis_File vf; 209 vorbis_info* vorbisInfo; 210 int eof = false; 211 int current_section; 212 ALuint buffer; 213 ALenum format; 214 215 // Open file with custom streaming 216 ov_callbacks vorbisCallbacks; 217 vorbisCallbacks.read_func = &readVorbis; 218 vorbisCallbacks.seek_func = &seekVorbis; 219 vorbisCallbacks.tell_func = &tellVorbis; 220 vorbisCallbacks.close_func = NULL; 221 222 int ret = ov_open_callbacks(dataStream_.get(), &vf, NULL, 0, vorbisCallbacks); 223 if (ret < 0) 224 { 225 COUT(2) << "Sound: libvorbisfile: File does not seem to be an Ogg Vorbis bitstream" << std::endl; 226 ov_clear(&vf); 227 return AL_NONE; 228 } 229 230 while (!eof) 231 { 232 long ret = ov_read(&vf, inbuffer, sizeof(inbuffer), 0, 2, 1, ¤t_section); 233 if (ret == 0) 234 { 235 eof = true; 236 } 237 else if (ret < 0) 238 { 239 COUT(2) << "Sound: libvorbisfile: error reading the file" << std::endl; 240 ov_clear(&vf); 241 return AL_NONE; 242 } 243 else 244 { 245 outbuffer.insert(outbuffer.end(), inbuffer, inbuffer + sizeof(inbuffer)); 246 } 247 } 248 249 vorbisInfo = ov_info(&vf, -1); 250 if (vorbisInfo->channels == 1) 251 format = AL_FORMAT_MONO16; 252 else 253 format = AL_FORMAT_STEREO16; 254 255 alGenBuffers(1, &buffer); 256 alBufferData(buffer, format, &outbuffer[0], outbuffer.size(), vorbisInfo->rate); 257 ov_clear(&vf); 258 259 return buffer; 260 } 261 262 } // namespace: orxonox 239 240 // Sound was already playing or paused because there was a source acquired 241 assert(this->isPlaying() || this->isPaused()); 242 alSourcePlay(this->audioSource_); 243 if (int error = alGetError()) 244 COUT(2) << "Sound: Error playing sound: " << SoundManager::getALErrorString(error) << std::endl; 245 if (this->isPaused()) 246 alSourcePause(this->audioSource_); 247 } 248 else // No source acquired so far, but might be set to playing or paused 249 { 250 State state = this->state_; // save 251 if (this->isPlaying() || this->isPaused()) 252 doPlay(); 253 if (state == Paused) 254 { 255 this->state_ = Paused; 256 doPause(); 257 } 258 } 259 } 260 261 void BaseSound::stateChanged() 262 { 263 switch (this->state_) 264 { 265 case Playing: 266 this->play(); 267 break; 268 case Paused: 269 this->pause(); 270 break; 271 case Stopped: 272 default: 273 this->stop(); 274 break; 275 } 276 } 277 } -
code/branches/pickup2/src/orxonox/sound/BaseSound.h
r5929 r6412 26 26 * 27 27 */ 28 28 29 #ifndef _BaseSound_H__ 29 30 #define _BaseSound_H__ … … 32 33 33 34 #include <string> 34 #include < OgreSharedPtr.h>35 #include <boost/shared_ptr.hpp> 35 36 #include <OgreDataStream.h> 36 37 #include "core/OrxonoxClass.h" … … 47 48 public: 48 49 BaseSound(); 50 51 void XMLPortExtern(Element& xmlelement, XMLPort::Mode mode); 52 53 virtual void play() { this->doPlay(); } 54 virtual void stop() { this->doStop(); } 55 virtual void pause() { this->doPause(); } 56 57 bool isPlaying() const { return this->state_ == Playing; } 58 bool isPaused() const { return this->state_ == Paused; } 59 bool isStopped() const { return this->state_ == Stopped; } 60 61 virtual void setSource(const std::string& source); 62 virtual const std::string& getSource() const 63 { return this->source_; } 64 65 void setVolume(float vol); 66 float getVolume() const 67 { return this->volume_; } 68 void updateVolume(); 69 70 bool getLooping() const 71 { return this->bLooping_; } 72 void setLooping(bool val); 73 74 float getPitch() const 75 { return this->pitch_; } 76 void setPitch(float pitch); 77 78 protected: 79 enum State 80 { 81 Stopped, 82 Playing, 83 Paused 84 }; 85 49 86 virtual ~BaseSound(); 50 87 51 void play();52 void stop();53 void pause();88 void doPlay(); 89 void doStop(); 90 void doPause(); 54 91 55 bool isPlaying(); 56 bool isPaused(); 57 bool isStopped(); 92 // network callbacks 93 inline void pitchChanged() 94 { this->setPitch(this->pitch_); } 95 inline void loopingChanged() 96 { this->setLooping(this->bLooping_); } 97 inline void volumeChanged() 98 { this->setVolume(this->volume_); } 99 inline void sourceChanged() 100 { this->setSource(this->source_); } 101 void stateChanged(); 58 102 59 v oid setSource(const std::string& source);60 const std::string& getSource() { return this->source_; }103 virtual void initialiseSource(); 104 ALint getSourceState() const; 61 105 62 bool getPlayOnLoad() { return this->bPlayOnLoad_; } 63 void setPlayOnLoad(bool val); 106 virtual float getRealVolume() = 0; 64 107 65 bool getLoop() { return this->bLoop_; } 66 void setLoop(bool val) { this->bLoop_ = val; } 67 68 protected: 69 ALuint loadOggFile(); 70 ALint getSourceState(); 71 72 ALuint audioSource_; 73 ALuint audioBuffer_; 108 ALuint audioSource_; 109 bool bPooling_; 110 shared_ptr<SoundBuffer> soundBuffer_; 111 std::string source_; 112 float volume_; 113 bool bLooping_; 114 State state_; 115 float pitch_; 74 116 75 117 private: 76 std::string source_; 77 bool bPlayOnLoad_; 78 bool bLoop_; 79 DataStreamPtr dataStream_; 118 DataStreamPtr dataStream_; 80 119 }; 81 120 } -
code/branches/pickup2/src/orxonox/sound/CMakeLists.txt
r5929 r6412 2 2 AmbientSound.cc 3 3 BaseSound.cc 4 SoundBuffer.cc 4 5 SoundManager.cc 5 6 WorldSound.cc 7 SoundStreamer.cc 6 8 ) 7 9 -
code/branches/pickup2/src/orxonox/sound/SoundManager.cc
r5929 r6412 22 22 * Author: 23 23 * Erwin 'vaiursch' Herrsche 24 * Kevin Young 25 * Reto Grieder 24 26 * Co-authors: 25 27 * ... … … 30 32 31 33 #include <AL/alut.h> 34 #include <utility> 32 35 33 36 #include "util/Exception.h" 34 37 #include "util/Math.h" 35 38 #include "util/ScopeGuard.h" 39 #include "util/Clock.h" 40 #include "core/ConfigValueIncludes.h" 41 #include "core/CoreIncludes.h" 36 42 #include "core/GameMode.h" 37 43 #include "core/ScopedSingletonManager.h" 44 #include "core/Resource.h" 45 #include "SoundBuffer.h" 46 #include "BaseSound.h" 47 #include "AmbientSound.h" 48 #include "WorldSound.h" 38 49 39 50 namespace orxonox 40 51 { 41 SoundManager* SoundManager::singletonPtr_s = NULL;42 52 ManageScopedSingleton(SoundManager, ScopeID::Graphics, true); 43 53 54 std::string SoundManager::getALErrorString(ALenum code) 55 { 56 switch (code) 57 { 58 case AL_NO_ERROR: return "No error"; 59 case AL_INVALID_NAME: return "Invalid AL parameter name"; 60 case AL_INVALID_ENUM: return "Invalid AL enum"; 61 case AL_INVALID_VALUE: return "Invalid AL value"; 62 case AL_INVALID_OPERATION: return "Invalid AL operation"; 63 case AL_OUT_OF_MEMORY: return "AL reports out of memory"; 64 default: return "Unknown AL error"; 65 } 66 } 67 44 68 SoundManager::SoundManager() 45 { 46 if (!alutInitWithoutContext(NULL,NULL)) 47 ThrowException(InitialisationFailed, "OpenAL ALUT error: " << alutGetErrorString(alutGetError())); 69 : effectsPoolSize_(0) 70 { 71 RegisterRootObject(SoundManager); 72 73 // See whether we even want to load 74 bool bDisableSound_ = false; 75 SetConfigValue(bDisableSound_, false); 76 if (bDisableSound_) 77 ThrowException(InitialisationAborted, "Sound: Not loading at all"); 78 79 if (!alutInitWithoutContext(NULL, NULL)) 80 ThrowException(InitialisationFailed, "Sound Error: ALUT initialisation failed: " << alutGetErrorString(alutGetError())); 48 81 Loki::ScopeGuard alutExitGuard = Loki::MakeGuard(&alutExit); 49 82 50 COUT(3) << "OpenAL: Opening sound device..." << std::endl; 83 /* 84 // Get list of available sound devices and display them 85 const char* devices = alcGetString(NULL, ALC_DEVICE_SPECIFIER); 86 char* device = new char[strlen(devices)+1]; 87 strcpy(device, devices); 88 std::string renderDevice; 89 SetConfigValue(renderDevice, std::string(device)).description("Sound device used for rendering"); 90 COUT(4) << "Sound: Available devices: "; 91 while (true) 92 { 93 this->deviceNames_.push_back(devices); 94 COUT(4) << '"' << devices << "\", "; 95 devices += strlen(devices) + 1; 96 if (*devices == '\0') 97 break; 98 } 99 COUT(4) << std::endl; 100 101 // Open the selected device 102 COUT(3) << "Sound: Opening device \"" << renderDevice << '\' << std::endl; 103 this->device_ = alcOpenDevice(renderDevice.c_str()); 104 */ 51 105 this->device_ = alcOpenDevice(NULL); 52 106 if (this->device_ == NULL) 53 107 { 54 COUT( 0) << "OpenaAL: Could not open sound device. Have you installed OpenAL?" << std::endl;108 COUT(1) << "Sound: Could not open sound device. Have you installed OpenAL?" << std::endl; 55 109 #ifdef ORXONOX_PLATFORM_WINDOWS 56 COUT( 0) << "Just getting the DLL with the dependencies is not enough for Windows (esp. Windows 7)!" << std::endl;110 COUT(1) << "Sound: Just getting the DLL with the dependencies is not enough for Windows (esp. Windows 7)!" << std::endl; 57 111 #endif 58 ThrowException(InitialisationFailed, " OpenAL error: Could not open sound device.");112 ThrowException(InitialisationFailed, "Sound Error: Could not open sound device."); 59 113 } 60 114 Loki::ScopeGuard closeDeviceGuard = Loki::MakeGuard(&alcCloseDevice, this->device_); 61 115 62 COUT(3) << "OpenAL: Sound device opened" << std::endl;116 // Create sound context and make it the currently used one 63 117 this->context_ = alcCreateContext(this->device_, NULL); 64 118 if (this->context_ == NULL) 65 ThrowException(InitialisationFailed, " OpenAL error: Could not create soundcontext");119 ThrowException(InitialisationFailed, "Sound Error: Could not create ALC context"); 66 120 Loki::ScopeGuard desroyContextGuard = Loki::MakeGuard(&alcDestroyContext, this->context_); 67 68 if (alcMakeContextCurrent(this->context_) == AL_TRUE) 69 COUT(3) << "OpenAL: Context " << this->context_ << " loaded" << std::endl; 70 71 COUT(4) << "Sound: OpenAL ALUT version: " << alutGetMajorVersion() << "." << alutGetMinorVersion() << std::endl; 72 73 const char* str = alutGetMIMETypes(ALUT_LOADER_BUFFER); 74 if (str == NULL) 75 COUT(2) << "OpenAL ALUT error: " << alutGetErrorString(alutGetError()) << std::endl; 121 if (!alcMakeContextCurrent(this->context_)) 122 ThrowException(InitialisationFailed, "Sound Error: Could not use ALC context"); 123 124 GameMode::setPlaysSound(true); 125 Loki::ScopeGuard resetPlaysSoundGuard = Loki::MakeGuard(&GameMode::setPlaysSound, false); 126 127 // Get some information about the sound 128 if (const char* version = alGetString(AL_VERSION)) 129 COUT(4) << "Sound: --- OpenAL Version: " << version << std::endl; 130 if (const char* vendor = alGetString(AL_VENDOR)) 131 COUT(4) << "Sound: --- OpenAL Vendor : " << vendor << std::endl; 132 if (const char* types = alutGetMIMETypes(ALUT_LOADER_BUFFER)) 133 COUT(4) << "Sound: --- Supported MIME Types: " << types << std::endl; 76 134 else 77 COUT(4) << "OpenAL ALUT supported MIME types: " << str << std::endl; 78 79 GameMode::setPlaysSound(true); 135 COUT(2) << "Sound Warning: MIME Type retrieval failed: " << alutGetErrorString(alutGetError()) << std::endl; 136 137 this->mute_[SoundType::All] = 1.0f; 138 this->mute_[SoundType::Music] = 1.0f; 139 this->mute_[SoundType::Effects] = 1.0f; 140 141 this->setConfigValues(); 142 143 // Try to get at least one source 144 ALuint source; 145 alGenSources(1, &source); 146 if (!alGetError() && alIsSource(source)) 147 this->availableSoundSources_.push_back(source); 148 else 149 ThrowException(InitialisationFailed, "Sound Error: Could not create even a single source"); 150 // Create a few initial sources 151 this->createSoundSources(this->minSources_ - 1); 152 80 153 // Disarm guards 81 154 alutExitGuard.Dismiss(); 82 155 closeDeviceGuard.Dismiss(); 83 156 desroyContextGuard.Dismiss(); 157 resetPlaysSoundGuard.Dismiss(); 158 159 COUT(4) << "Sound: Initialisation complete" << std::endl; 84 160 } 85 161 86 162 SoundManager::~SoundManager() 87 163 { 164 // Erase fade lists because of the smart pointers 165 this->fadeInList_.clear(); 166 this->fadeOutList_.clear(); 167 168 // If there are still used buffers around, well, that's just very bad... 169 if (this->soundBuffers_.size() != this->effectsPool_.size()) 170 COUT(1) << "Sound Error: Some sound buffers are still in use but OpenAL is about to shut down. Fix this!" << std::endl; 171 // Empty buffer pool and buffer list 172 this->effectsPool_.clear(); 173 this->soundBuffers_.clear(); 174 175 // There should not be any sources in use anymore 176 if (!this->usedSoundSources_.empty()) 177 COUT(1) << "Sound Error: Some sound sources are still in use but OpenAL is about to shut down. Fix this!" << std::endl; 178 while (!this->availableSoundSources_.empty()) 179 { 180 alDeleteSources(1, &this->availableSoundSources_.back()); 181 this->availableSoundSources_.pop_back(); 182 } 183 88 184 GameMode::setPlaysSound(false); 185 186 // Relieve context to destroy it 187 if (!alcMakeContextCurrent(NULL)) 188 COUT(1) << "Sound Error: Could not unset ALC context" << std::endl; 89 189 alcDestroyContext(this->context_); 190 if (ALCenum error = alcGetError(this->device_)) 191 { 192 if (error == AL_INVALID_OPERATION) 193 COUT(1) << "Sound Error: Could not destroy ALC context because it is the current one" << std::endl; 194 else 195 COUT(1) << "Sound Error: Could not destroy ALC context because it is invalid" << std::endl; 196 } 197 #ifdef AL_VERSION_1_1 198 if (!alcCloseDevice(this->device_)) 199 COUT(1) << "Sound Error: Could not destroy ALC device. This might be because there are still buffers in use!" << std::endl; 200 #else 90 201 alcCloseDevice(this->device_); 91 alutExit(); 202 #endif 203 if (!alutExit()) 204 COUT(1) << "Sound Error: Closing ALUT failed: " << alutGetErrorString(alutGetError()) << std::endl; 205 } 206 207 void SoundManager::setConfigValues() 208 { 209 SetConfigValue(crossFadeStep_, 0.2f) 210 .description("Determines how fast sounds should fade, per second.") 211 .callback(this, &SoundManager::checkFadeStepValidity); 212 213 SetConfigValueAlias(volume_[SoundType::All], "soundVolume_", 1.0f) 214 .description("Defines the overall volume.") 215 .callback(this, &SoundManager::checkSoundVolumeValidity); 216 SetConfigValueAlias(volume_[SoundType::Music], "ambientVolume_", 1.0f) 217 .description("Defines the ambient volume.") 218 .callback(this, &SoundManager::checkAmbientVolumeValidity); 219 SetConfigValueAlias(volume_[SoundType::Effects], "effectsVolume_", 1.0f) 220 .description("Defines the effects volume.") 221 .callback(this, &SoundManager::checkEffectsVolumeValidity); 222 223 SetConfigValue(minSources_, 16) 224 .description("Minimum number of sources being generated (if possible)"); 225 SetConfigValue(maxSources_, 1024) 226 .description("Maximum number of sources to be made available"); 227 } 228 229 void SoundManager::preUpdate(const Clock& time) 230 { 231 this->processCrossFading(time.getDeltaTime()); 232 233 // Check whether a sound object has stopped playing 234 for (unsigned int i = 0; i < this->usedSoundSources_.size(); ++i) 235 { 236 ALint state; 237 alGetSourcei(this->usedSoundSources_[i].first, AL_SOURCE_STATE, &state); 238 if (state == AL_STOPPED) 239 { 240 this->usedSoundSources_[i].second->stop(); 241 --i; 242 } 243 } 244 } 245 246 void SoundManager::checkFadeStepValidity() 247 { 248 if (crossFadeStep_ <= 0.0 || crossFadeStep_ >= 1.0 ) 249 { 250 COUT(2) << "Sound warning: fade step out of range, ignoring change." << std::endl; 251 ResetConfigValue(crossFadeStep_); 252 } 253 } 254 255 void SoundManager::checkVolumeValidity(SoundType::Value type) 256 { 257 float clampedVolume = clamp(this->volume_[type], 0.0f, 1.0f); 258 if (clampedVolume != this->volume_[type]) 259 COUT(2) << "Sound warning: Volume setting (" << type << ") out of range, clamping." << std::endl; 260 this->updateVolume(type); 261 } 262 263 void SoundManager::setVolume(float vol, SoundType::Value type) 264 { 265 if (type < 0 || type > SoundType::Effects) 266 return; 267 this->volume_[type] = vol; 268 this->checkVolumeValidity(type); 269 } 270 271 float SoundManager::getVolume(SoundType::Value type) 272 { 273 if (type < 0 || type > SoundType::Effects) 274 return 0.0f; 275 return this->volume_[type]; 276 } 277 278 float SoundManager::getRealVolume(SoundType::Value type) 279 { 280 if (type != SoundType::Music && type != SoundType::Effects) 281 return 0.0f; 282 return this->volume_[SoundType::All] * this->mute_[SoundType::All] * this->volume_[type] * this->mute_[type]; 283 } 284 285 void SoundManager::updateVolume(SoundType::Value type) 286 { 287 switch(type) 288 { 289 case SoundType::All: 290 for (ObjectList<BaseSound>::iterator it = ObjectList<BaseSound>::begin(); it != ObjectList<BaseSound>::end(); ++it) 291 (*it)->updateVolume(); 292 break; 293 case SoundType::Music: 294 for (ObjectList<AmbientSound>::iterator it = ObjectList<AmbientSound>::begin(); it != ObjectList<AmbientSound>::end(); ++it) 295 (*it)->updateVolume(); 296 break; 297 case SoundType::Effects: 298 for (ObjectList<WorldSound>::iterator it = ObjectList<WorldSound>::begin(); it != ObjectList<WorldSound>::end(); ++it) 299 (*it)->updateVolume(); 300 break; 301 default: 302 assert(false); 303 } 304 } 305 306 void SoundManager::toggleMute(SoundType::Value type) 307 { 308 if (type < 0 || type > SoundType::Effects) 309 return; 310 this->mute_[type] = (this->mute_[type] == 0) ? 1.0f : 0.0f; 311 this->updateVolume(type); 312 } 313 314 bool SoundManager::getMute(SoundType::Value type) 315 { 316 if (type < 0 || type > SoundType::Effects) 317 return true; 318 return (this->mute_[type] == 0); 92 319 } 93 320 … … 103 330 { 104 331 // update listener orientation 105 Vector3 up = orientation.xAxis(); // just a wild guess 106 Vector3 at = orientation.zAxis(); 107 108 ALfloat orient[6] = { at.x, at.y, at.z, 109 up.x, up.y, up.z }; 110 111 alListenerfv(AL_POSITION, orient); 332 const Vector3& direction = -orientation.zAxis(); 333 const Vector3& up = orientation.yAxis(); 334 335 ALfloat orient[6] = { direction.x, direction.y, direction.z, up.x, up.y, up.z }; 336 337 alListenerfv(AL_ORIENTATION, orient); 112 338 ALenum error = alGetError(); 113 339 if (error == AL_INVALID_VALUE) 114 340 COUT(2) << "Sound: OpenAL: Invalid listener orientation" << std::endl; 115 341 } 342 343 void SoundManager::registerAmbientSound(AmbientSound* newAmbient) 344 { 345 if (newAmbient != NULL) 346 { 347 for (AmbientList::const_iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it) 348 { 349 if (it->first == newAmbient) 350 { 351 COUT(2) << "Sound warning: Will not play an AmbientSound twice." << std::endl; 352 return; 353 } 354 } 355 356 if (!this->ambientSounds_.empty()) 357 { 358 this->fadeOut(ambientSounds_.front().first); 359 } 360 this->ambientSounds_.push_front(std::make_pair(newAmbient, false)); 361 newAmbient->doPlay(); 362 this->fadeIn(newAmbient); 363 } 364 } 365 366 void SoundManager::unregisterAmbientSound(AmbientSound* oldAmbient) 367 { 368 if (oldAmbient == NULL || ambientSounds_.empty()) 369 return; 370 371 if (this->ambientSounds_.front().first == oldAmbient) 372 { 373 this->fadeOut(oldAmbient); 374 this->ambientSounds_.pop_front(); 375 if (!this->ambientSounds_.empty()) 376 { 377 if (!this->ambientSounds_.front().second) // Not paused before 378 { 379 this->ambientSounds_.front().first->doPlay(); 380 } 381 this->fadeIn(this->ambientSounds_.front().first); 382 } 383 } 384 else 385 { 386 for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it) 387 { 388 if (it->first == oldAmbient) 389 { 390 this->fadeOut(oldAmbient); 391 this->ambientSounds_.erase(it); 392 break; 393 } 394 } 395 } 396 } 397 398 void SoundManager::pauseAmbientSound(AmbientSound* ambient) 399 { 400 if (ambient != NULL) 401 { 402 for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it) 403 { 404 if (it->first == ambient) 405 { 406 it->second = true; 407 this->fadeOut(it->first); 408 return; 409 } 410 } 411 } 412 } 413 414 void SoundManager::fadeIn(const SmartPtr<AmbientSound>& sound) 415 { 416 // If we're already fading out --> remove that 417 for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); it++) 418 { 419 if (*it == sound) 420 { 421 this->fadeOutList_.erase(it); 422 break; 423 } 424 } 425 // No duplicate entries 426 if (std::find(this->fadeInList_.begin(), this->fadeInList_.end(), sound) == this->fadeInList_.end()) 427 this->fadeInList_.push_back(sound); 428 } 429 430 void SoundManager::fadeOut(const SmartPtr<AmbientSound>& sound) 431 { 432 // If we're already fading in --> remove that 433 for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeInList_.begin(); it != this->fadeInList_.end(); it++) 434 { 435 if (*it == sound) 436 { 437 this->fadeInList_.erase(it); 438 break; 439 } 440 } 441 // No duplicate entries 442 if (std::find(this->fadeOutList_.begin(), this->fadeOutList_.end(), sound) == this->fadeOutList_.end()) 443 this->fadeOutList_.push_back(sound); 444 } 445 446 void SoundManager::processCrossFading(float dt) 447 { 448 449 // Hacky solution to the fade delay while loading a level. 450 if(dt > 0.2) 451 { 452 return; 453 } 454 455 // FADE IN 456 for (std::list<SmartPtr<AmbientSound> >::iterator it= this->fadeInList_.begin(); it != this->fadeInList_.end(); ) 457 { 458 if ((*it)->getVolume() + this->crossFadeStep_*dt > 1.0f) 459 { 460 (*it)->setVolume(1.0f); 461 this->fadeInList_.erase(it++); 462 } 463 else 464 { 465 (*it)->setVolume((*it)->getVolume() + this->crossFadeStep_*dt); 466 ++it; 467 } 468 } 469 470 // FADE OUT 471 for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); ) 472 { 473 if ((*it)->getVolume() - this->crossFadeStep_*dt < 0.0f) 474 { 475 (*it)->setVolume(0.0f); 476 477 // If sound is in the ambient list --> pause 478 for (AmbientList::const_iterator it2 = this->ambientSounds_.begin(); it2 != this->ambientSounds_.end(); ++it2) 479 { 480 if (it2->first == *it) 481 { 482 (*it)->doPause(); 483 break; 484 } 485 } 486 // If not pause (by loop above for instance) --> stop 487 if (!(*it)->isPaused()) 488 (*it)->doStop(); 489 490 this->fadeOutList_.erase(it++); 491 } 492 else 493 { 494 (*it)->setVolume((*it)->getVolume() - this->crossFadeStep_*dt); 495 ++it; 496 } 497 } 498 } 499 500 shared_ptr<SoundBuffer> SoundManager::getSoundBuffer(const std::string& filename) 501 { 502 shared_ptr<SoundBuffer> buffer; 503 // Check active or pooled buffers 504 SoundBufferMap::const_iterator it = this->soundBuffers_.find(filename); 505 if (it != this->soundBuffers_.end()) 506 { 507 buffer = it->second; 508 509 // Remove from effects pool if not active used before 510 if (buffer->poolIterator_ != this->effectsPool_.end()) 511 { 512 this->effectsPoolSize_ -= buffer->getSize(); 513 this->effectsPool_.erase(buffer->poolIterator_); 514 buffer->poolIterator_ = this->effectsPool_.end(); 515 } 516 } 517 else 518 { 519 try 520 { 521 buffer.reset(new SoundBuffer(filename, this->effectsPool_.end())); 522 } 523 catch (...) 524 { 525 COUT(1) << Exception::handleMessage() << std::endl; 526 return buffer; 527 } 528 this->soundBuffers_[filename] = buffer; 529 } 530 return buffer; 531 } 532 533 void SoundManager::releaseSoundBuffer(const shared_ptr<SoundBuffer>& buffer, bool bPoolBuffer) 534 { 535 // Check if others are still using the buffer 536 if (buffer.use_count() != 2) 537 return; 538 SoundBufferMap::iterator it = this->soundBuffers_.find(buffer->getFilename()); 539 if (it != this->soundBuffers_.end()) 540 { 541 if (bPoolBuffer) 542 { 543 // Pool already too large? 544 while (this->effectsPoolSize_ + it->second->getSize() > this->maxEffectsPoolSize_s && !this->effectsPool_.empty()) 545 { 546 shared_ptr<SoundBuffer> bufferDel = this->effectsPool_.back(); 547 this->effectsPoolSize_ -= bufferDel->getSize(); 548 bufferDel->poolIterator_ = this->effectsPool_.end(); 549 this->effectsPool_.pop_back(); 550 // Remove from buffer map too 551 SoundBufferMap::iterator itDel = this->soundBuffers_.find(bufferDel->getFilename()); 552 if (itDel != this->soundBuffers_.end()) 553 this->soundBuffers_.erase(itDel); 554 } 555 // Put buffer into the pool 556 this->effectsPoolSize_ += it->second->getSize(); 557 this->effectsPool_.push_front(it->second); 558 it->second->poolIterator_ = this->effectsPool_.begin(); 559 } 560 else 561 this->soundBuffers_.erase(it); 562 } 563 } 564 565 ALuint SoundManager::getSoundSource(BaseSound* object) 566 { 567 if (!this->availableSoundSources_.empty()) 568 { 569 ALuint source = this->availableSoundSources_.back(); 570 this->availableSoundSources_.pop_back(); 571 this->usedSoundSources_.push_back(std::make_pair(source, object)); 572 return source; 573 } 574 else 575 { 576 if (this->usedSoundSources_.size() < this->maxSources_) 577 { 578 ALuint source; 579 alGenSources(1, &source); 580 // Try to create new sources (50% more, but at least one) 581 if (alIsSource(source) && !alGetError()) 582 { 583 this->usedSoundSources_.push_back(std::make_pair(source, object)); 584 return source; 585 } 586 } 587 // Return no source ID 588 ALuint source = 123456789; 589 while (alIsSource(++source)); 590 return source; 591 } 592 } 593 594 void SoundManager::releaseSoundSource(ALuint source) 595 { 596 #ifndef NDEBUG 597 for (std::vector<ALuint>::const_iterator it = this->availableSoundSources_.begin(); it != this->availableSoundSources_.end(); ++it) 598 assert((*it) != source); 599 #endif 600 this->availableSoundSources_.push_back(source); 601 for (std::vector<std::pair<ALuint, BaseSound*> >::iterator it = this->usedSoundSources_.begin(); 602 it != this->usedSoundSources_.end(); ++it) 603 { 604 if (it->first == source) 605 { 606 this->usedSoundSources_.erase(it); 607 break; 608 } 609 } 610 int used = std::max(this->usedSoundSources_.size(), this->minSources_); 611 // Subtract those we added in the statement above trough std::max 612 int available = (int)this->availableSoundSources_.size() - (used - (int)this->usedSoundSources_.size()); 613 // Delete sources again to free resources if appropriate (more than 50% more available than used) 614 int toDelete = available - used / 2; 615 while (toDelete-- > 0) 616 { 617 alDeleteSources(1, &this->availableSoundSources_.back()); 618 if (alGetError()) 619 COUT(1) << "Sound Error: Failed to delete a source --> lost forever" << std::endl; 620 this->availableSoundSources_.pop_back(); 621 } 622 } 623 624 unsigned int SoundManager::createSoundSources(unsigned int n) 625 { 626 unsigned int count = this->availableSoundSources_.size() + this->usedSoundSources_.size(); 627 while (count < this->maxSources_ && count <= n) 628 { 629 ALuint source; 630 alGenSources(1, &source); 631 if (alIsSource(source) && !alGetError()) 632 this->availableSoundSources_.push_back(source); 633 else 634 break; 635 ++count; 636 } 637 return count - this->availableSoundSources_.size() - this->usedSoundSources_.size(); 638 } 116 639 } -
code/branches/pickup2/src/orxonox/sound/SoundManager.h
r5929 r6412 22 22 * Author: 23 23 * Erwin 'vaiursch' Herrsche 24 * Kevin Young 25 * Reto Grieder 24 26 * Co-authors: 25 27 * ... 26 28 */ 29 27 30 #ifndef _SoundManager_H__ 28 31 #define _SoundManager_H__ … … 30 33 #include "OrxonoxPrereqs.h" 31 34 32 #include <cassert>33 35 #include <list> 36 #include <map> 37 #include <string> 38 #include <boost/shared_ptr.hpp> 39 34 40 #include "util/Singleton.h" 35 #include "tools/interfaces/Tickable.h" 41 #include "core/OrxonoxClass.h" 42 #include "core/SmartPtr.h" 36 43 44 // tolua_begin 37 45 namespace orxonox 38 46 { 39 /** 40 * The SoundManager class manages the OpenAL device, context and listener 41 * position. It is a singleton. 42 * 43 */ 44 class _OrxonoxExport SoundManager : public Singleton<SoundManager> 47 //! Enum for the sound type. 48 namespace SoundType 45 49 { 50 enum Value 51 { 52 All = 0, 53 Music = 1, 54 Effects = 2 55 }; 56 } 57 58 //! The SoundManager class manages the OpenAL device, context and listener position. 59 class _OrxonoxExport SoundManager 60 // tolua_end 61 : public Singleton<SoundManager>, public OrxonoxClass 62 { // tolua_export 46 63 friend class Singleton<SoundManager>; 64 47 65 public: 48 66 SoundManager(); 49 67 ~SoundManager(); 50 68 69 void preUpdate(const Clock& time); 70 void setConfigValues(); 71 72 // tolua_begin 73 static SoundManager& getInstance() { return Singleton<SoundManager>::getInstance(); } 74 75 std::string getDeviceName(unsigned int index) const 76 { return index < this->deviceNames_.size() ? this->deviceNames_[index] : std::string(); } 77 // tolua_end 78 51 79 void setListenerPosition(const Vector3& position); 52 80 void setListenerOrientation(const Quaternion& orientation); 53 81 82 void registerAmbientSound(AmbientSound* newAmbient); 83 void unregisterAmbientSound(AmbientSound* oldAmbient); 84 void pauseAmbientSound(AmbientSound* ambient); 85 86 // tolua_begin 87 void setVolume(float vol, SoundType::Value type); 88 float getVolume(SoundType::Value type); 89 float getRealVolume(SoundType::Value type); 90 91 void toggleMute(SoundType::Value type); 92 bool getMute(SoundType::Value type); 93 // tolua_end 94 95 shared_ptr<SoundBuffer> getSoundBuffer(const std::string& filename); 96 void releaseSoundBuffer(const shared_ptr<SoundBuffer>& buffer, bool bPoolBuffer); 97 98 ALuint getSoundSource(BaseSound* object); 99 void releaseSoundSource(ALuint source); 100 101 static std::string getALErrorString(ALenum error); 102 54 103 private: 104 void processCrossFading(float dt); 105 void fadeIn(const SmartPtr<AmbientSound>& sound); 106 void fadeOut(const SmartPtr<AmbientSound>& sound); 107 108 void checkFadeStepValidity(); 109 110 void checkVolumeValidity(SoundType::Value type); 111 void checkSoundVolumeValidity() { this->checkVolumeValidity(SoundType::All); } 112 void checkAmbientVolumeValidity() { this->checkVolumeValidity(SoundType::Music); } 113 void checkEffectsVolumeValidity() { this->checkVolumeValidity(SoundType::Effects); } 114 void updateVolume(SoundType::Value type); 115 116 unsigned int createSoundSources(unsigned int n); 117 118 // OpenAL device/context related 119 std::vector<std::string> deviceNames_; 55 120 ALCdevice* device_; 56 121 ALCcontext* context_; 57 122 123 // Ambient sound related 124 typedef std::list<std::pair<AmbientSound*, bool> > AmbientList; 125 AmbientList ambientSounds_; 126 //! Absolute change per second (0.1 means 10% of the nominal volume) for cross fading 127 float crossFadeStep_; 128 std::list<SmartPtr<AmbientSound> > fadeInList_; 129 std::list<SmartPtr<AmbientSound> > fadeOutList_; 130 131 // Volume related 132 float volume_[3]; 133 float mute_[3]; 134 135 // Sound buffer related 136 static const unsigned int maxEffectsPoolSize_s = 40 * 1024 * 1024; 137 unsigned int effectsPoolSize_; 138 typedef std::list<shared_ptr<SoundBuffer> > EffectsPoolList; 139 EffectsPoolList effectsPool_; 140 typedef std::map<std::string, shared_ptr<SoundBuffer> > SoundBufferMap; 141 SoundBufferMap soundBuffers_; 142 143 // Sound source related 144 unsigned int minSources_; 145 unsigned int maxSources_; 146 std::vector<ALuint> availableSoundSources_; 147 std::vector<std::pair<ALuint, BaseSound*> > usedSoundSources_; 148 58 149 static SoundManager* singletonPtr_s; 59 }; 60 } 150 }; // tolua_export 151 } // tolua_export 61 152 62 153 #endif /* _SoundManager_H__ */ -
code/branches/pickup2/src/orxonox/sound/WorldSound.cc
r5929 r6412 35 35 #include "core/EventIncludes.h" 36 36 #include "core/XMLPort.h" 37 #include "Scene.h" 38 #include "SoundManager.h" 39 #include <core/ConsoleCommandCompilation.h> 37 40 38 41 namespace orxonox … … 44 47 { 45 48 RegisterObject(WorldSound); 49 // WorldSound buffers should be pooled when they're not used anymore 50 this->bPooling_ = true; 51 this->registerVariables(); 46 52 } 47 53 48 WorldSound::~WorldSound()54 void WorldSound::registerVariables() 49 55 { 56 registerVariable(volume_, ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::volumeChanged)); 57 registerVariable(source_, ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::sourceChanged)); 58 registerVariable(bLooping_, ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::loopingChanged)); 59 registerVariable(pitch_, ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::pitchChanged)); 60 registerVariable((int&)(BaseSound::state_), ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::stateChanged)); 50 61 } 51 62 … … 53 64 { 54 65 SUPER(WorldSound, XMLPort, xmlelement, mode); 55 XMLPortParamExtern(WorldSound, BaseSound, this, "source", setSource, getSource, xmlelement, mode); 56 XMLPortParamExtern(WorldSound, BaseSound, this, "loop", setLoop, getLoop, xmlelement, mode); 57 XMLPortParamExtern(WorldSound, BaseSound, this, "playOnLoad", setPlayOnLoad, getPlayOnLoad, xmlelement, mode); 66 BaseSound::XMLPortExtern(xmlelement, mode); 58 67 } 59 68 … … 62 71 SUPER(WorldSound, XMLEventPort, xmlelement, mode); 63 72 XMLPortEventState(WorldSound, BaseObject, "play", play, xmlelement, mode); 73 } 74 75 void WorldSound::initialiseSource() 76 { 77 BaseSound::initialiseSource(); 78 if (this->getScene()) 79 { 80 float refDist = this->getScene()->getSoundReferenceDistance(); 81 alSourcef(this->audioSource_, AL_REFERENCE_DISTANCE, refDist); 82 // TODO: 500 is very magical here. Derive something better 83 alSourcef(this->audioSource_, AL_MAX_DISTANCE, refDist * 500); 84 } 85 this->tick(0); // update position, orientation and velocity 64 86 } 65 87 … … 80 102 COUT(2) << "Sound: OpenAL: Invalid sound velocity" << std::endl; 81 103 82 const Quaternion& orient = this->getWorldOrientation(); 83 Vector3 at = orient.zAxis(); 84 alSource3f(this->audioSource_, AL_DIRECTION, at.x, at.y, at.z); 104 const Vector3& direction = -this->getWorldOrientation().zAxis(); 105 alSource3f(this->audioSource_, AL_DIRECTION, direction.x, direction.y, direction.z); 85 106 error = alGetError(); 86 107 if (error == AL_INVALID_VALUE) … … 89 110 } 90 111 112 void WorldSound::changedActivity() 113 { 114 SUPER(WorldSound, changedActivity); 115 if (this->isActive()) 116 this->play(); 117 else 118 this->stop(); 119 } 120 121 float WorldSound::getRealVolume() 122 { 123 assert(GameMode::playsSound()); 124 return SoundManager::getInstance().getRealVolume(SoundType::Effects); 125 } 91 126 } -
code/branches/pickup2/src/orxonox/sound/WorldSound.h
r5929 r6412 26 26 * 27 27 */ 28 28 29 #ifndef _WorldSound_H__ 29 30 #define _WorldSound_H__ … … 45 46 public: 46 47 WorldSound(BaseObject* creator); 47 virtual ~WorldSound();48 48 49 virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode); 50 virtual void XMLEventPort(Element& xmlelement, XMLPort::Mode mode); 49 void XMLPort(Element& xmlelement, XMLPort::Mode mode); 50 void XMLEventPort(Element& xmlelement, XMLPort::Mode mode); 51 void changedActivity(); 51 52 52 virtual void tick(float dt); 53 void tick(float dt); 54 55 protected: 56 ~WorldSound() {} 53 57 54 58 private: 59 void registerVariables(); 60 void initialiseSource(); 61 float getRealVolume(); 55 62 }; 56 63 }
Note: See TracChangeset
for help on using the changeset viewer.