/extlibs/SFML/src/SFML/Audio/SoundBuffer.cpp
C++ | 283 lines | 167 code | 51 blank | 65 comment | 19 complexity | 856309d699e5e689b5a15f4b1a4d16ba MD5 | raw file
1//////////////////////////////////////////////////////////// 2// 3// SFML - Simple and Fast Multimedia Library 4// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) 5// 6// This software is provided 'as-is', without any express or implied warranty. 7// In no event will the authors be held liable for any damages arising from the use of this software. 8// 9// Permission is granted to anyone to use this software for any purpose, 10// including commercial applications, and to alter it and redistribute it freely, 11// subject to the following restrictions: 12// 13// 1. The origin of this software must not be misrepresented; 14// you must not claim that you wrote the original software. 15// If you use this software in a product, an acknowledgment 16// in the product documentation would be appreciated but is not required. 17// 18// 2. Altered source versions must be plainly marked as such, 19// and must not be misrepresented as being the original software. 20// 21// 3. This notice may not be removed or altered from any source distribution. 22// 23//////////////////////////////////////////////////////////// 24 25//////////////////////////////////////////////////////////// 26// Headers 27//////////////////////////////////////////////////////////// 28#include <SFML/Audio/SoundBuffer.hpp> 29#include <SFML/Audio/SoundFile.hpp> 30#include <SFML/Audio/Sound.hpp> 31#include <SFML/Audio/AudioDevice.hpp> 32#include <SFML/Audio/ALCheck.hpp> 33#include <SFML/System/Err.hpp> 34#include <memory> 35 36 37namespace sf 38{ 39//////////////////////////////////////////////////////////// 40SoundBuffer::SoundBuffer() : 41myBuffer (0), 42myDuration(0.f) 43{ 44 priv::EnsureALInit(); 45 46 // Create the buffer 47 ALCheck(alGenBuffers(1, &myBuffer)); 48} 49 50 51//////////////////////////////////////////////////////////// 52SoundBuffer::SoundBuffer(const SoundBuffer& copy) : 53Resource<SoundBuffer>(), 54myBuffer (0), 55mySamples (copy.mySamples), 56myDuration (copy.myDuration), 57mySounds () // don't copy the attached sounds 58{ 59 // Create the buffer 60 ALCheck(alGenBuffers(1, &myBuffer)); 61 62 // Update the internal buffer with the new samples 63 Update(copy.GetChannelsCount(), copy.GetSampleRate()); 64} 65 66 67//////////////////////////////////////////////////////////// 68SoundBuffer::~SoundBuffer() 69{ 70 // First detach the buffer from the sounds that use it (to avoid OpenAL errors) 71 for (SoundList::const_iterator it = mySounds.begin(); it != mySounds.end(); ++it) 72 (*it)->ResetBuffer(); 73 74 // Destroy the buffer 75 if (myBuffer) 76 ALCheck(alDeleteBuffers(1, &myBuffer)); 77} 78 79 80//////////////////////////////////////////////////////////// 81bool SoundBuffer::LoadFromFile(const std::string& filename) 82{ 83 // Open the sound file 84 priv::SoundFile file; 85 if (file.OpenRead(filename)) 86 { 87 // Get the sound parameters 88 std::size_t nbSamples = file.GetSamplesCount(); 89 unsigned int channelsCount = file.GetChannelsCount(); 90 unsigned int sampleRate = file.GetSampleRate(); 91 92 // Read the samples from the opened file 93 mySamples.resize(nbSamples); 94 if (file.Read(&mySamples[0], nbSamples) == nbSamples) 95 { 96 // Update the internal buffer with the new samples 97 return Update(channelsCount, sampleRate); 98 } 99 else 100 { 101 return false; 102 } 103 } 104 else 105 { 106 return false; 107 } 108} 109 110 111//////////////////////////////////////////////////////////// 112bool SoundBuffer::LoadFromMemory(const void* data, std::size_t sizeInBytes) 113{ 114 // Open the sound file 115 priv::SoundFile file; 116 if (file.OpenRead(data, sizeInBytes)) 117 { 118 // Get the sound parameters 119 std::size_t nbSamples = file.GetSamplesCount(); 120 unsigned int channelsCount = file.GetChannelsCount(); 121 unsigned int sampleRate = file.GetSampleRate(); 122 123 // Read the samples from the opened file 124 mySamples.resize(nbSamples); 125 if (file.Read(&mySamples[0], nbSamples) == nbSamples) 126 { 127 // Update the internal buffer with the new samples 128 return Update(channelsCount, sampleRate); 129 } 130 else 131 { 132 return false; 133 } 134 } 135 else 136 { 137 return false; 138 } 139} 140 141 142//////////////////////////////////////////////////////////// 143bool SoundBuffer::LoadFromSamples(const Int16* samples, std::size_t samplesCount, unsigned int channelsCount, unsigned int sampleRate) 144{ 145 if (samples && samplesCount && channelsCount && sampleRate) 146 { 147 // Copy the new audio samples 148 mySamples.assign(samples, samples + samplesCount); 149 150 // Update the internal buffer with the new samples 151 return Update(channelsCount, sampleRate); 152 } 153 else 154 { 155 // Error... 156 Err() << "Failed to load sound buffer from memory (" 157 << "Samples : " << samples << ", " 158 << "Samples count : " << samplesCount << ", " 159 << "Channels count : " << channelsCount << ", " 160 << "Sample rate : " << sampleRate << ")" 161 << std::endl; 162 163 return false; 164 } 165} 166 167 168//////////////////////////////////////////////////////////// 169bool SoundBuffer::SaveToFile(const std::string& filename) const 170{ 171 // Create the sound file in write mode 172 priv::SoundFile file; 173 if (file.OpenWrite(filename, GetChannelsCount(), GetSampleRate())) 174 { 175 // Write the samples to the opened file 176 file.Write(&mySamples[0], mySamples.size()); 177 178 return true; 179 } 180 else 181 { 182 return false; 183 } 184} 185 186 187//////////////////////////////////////////////////////////// 188const Int16* SoundBuffer::GetSamples() const 189{ 190 return mySamples.empty() ? NULL : &mySamples[0]; 191} 192 193 194//////////////////////////////////////////////////////////// 195std::size_t SoundBuffer::GetSamplesCount() const 196{ 197 return mySamples.size(); 198} 199 200 201//////////////////////////////////////////////////////////// 202unsigned int SoundBuffer::GetSampleRate() const 203{ 204 ALint sampleRate; 205 ALCheck(alGetBufferi(myBuffer, AL_FREQUENCY, &sampleRate)); 206 207 return sampleRate; 208} 209 210 211//////////////////////////////////////////////////////////// 212unsigned int SoundBuffer::GetChannelsCount() const 213{ 214 ALint channelsCount; 215 ALCheck(alGetBufferi(myBuffer, AL_CHANNELS, &channelsCount)); 216 217 return channelsCount; 218} 219 220 221//////////////////////////////////////////////////////////// 222float SoundBuffer::GetDuration() const 223{ 224 return myDuration; 225} 226 227 228//////////////////////////////////////////////////////////// 229SoundBuffer& SoundBuffer::operator =(const SoundBuffer& right) 230{ 231 SoundBuffer temp(right); 232 233 std::swap(mySamples, temp.mySamples); 234 std::swap(myBuffer, temp.myBuffer); 235 std::swap(myDuration, temp.myDuration); 236 std::swap(mySounds, temp.mySounds); // swap sounds too, so that they are detached when temp is destroyed 237 238 return *this; 239} 240 241 242//////////////////////////////////////////////////////////// 243bool SoundBuffer::Update(unsigned int channelsCount, unsigned int sampleRate) 244{ 245 // Check parameters 246 if (!channelsCount || !sampleRate || mySamples.empty()) 247 return false; 248 249 // Find the good format according to the number of channels 250 ALenum format = priv::AudioDevice::GetFormatFromChannelsCount(channelsCount); 251 252 // Check if the format is valid 253 if (format == 0) 254 { 255 Err() << "Unsupported number of channels (" << channelsCount << ")" << std::endl; 256 return false; 257 } 258 259 // Fill the buffer 260 ALsizei size = static_cast<ALsizei>(mySamples.size()) * sizeof(Int16); 261 ALCheck(alBufferData(myBuffer, format, &mySamples[0], size, sampleRate)); 262 263 // Compute the duration 264 myDuration = static_cast<float>(mySamples.size()) / sampleRate / channelsCount; 265 266 return true; 267} 268 269 270//////////////////////////////////////////////////////////// 271void SoundBuffer::AttachSound(Sound* sound) const 272{ 273 mySounds.insert(sound); 274} 275 276 277//////////////////////////////////////////////////////////// 278void SoundBuffer::DetachSound(Sound* sound) const 279{ 280 mySounds.erase(sound); 281} 282 283} // namespace sf