Changeset 6412 for code/branches/pickup2/src/orxonox/sound/BaseSound.cc
- Timestamp:
- Dec 25, 2009, 1:18:03 PM (16 years ago)
- Location:
- code/branches/pickup2
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/pickup2
- Property svn:mergeinfo changed
-
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 }
Note: See TracChangeset
for help on using the changeset viewer.