SoundBuffer.cpp
1 //
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 //
24 
26 // Headers
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/OpenAL.hpp>
33 #include <iostream>
34 #include <memory>
35 
36 
37 namespace sf
38 {
43 myBuffer (0),
44 myDuration(0.f)
45 {
46  // Create the buffer
47  ALCheck(alGenBuffers(1, &myBuffer));
48 }
49 
50 
55 AudioResource (Copy),
56 Resource<SoundBuffer>(Copy),
57 myBuffer (0),
58 mySamples (Copy.mySamples),
59 myDuration (Copy.myDuration),
60 mySounds () // don't copy the attached sounds
61 {
62  // Create the buffer
63  ALCheck(alGenBuffers(1, &myBuffer));
64 
65  // Update the internal buffer with the new samples
66  Update(Copy.GetChannelsCount(), Copy.GetSampleRate());
67 }
68 
69 
74 {
75  // First detach the buffer from the sounds that use it (to avoid OpenAL errors)
76  for (SoundList::const_iterator it = mySounds.begin(); it != mySounds.end(); ++it)
77  (*it)->ResetBuffer();
78 
79  // Destroy the buffer
80  if (myBuffer)
81  ALCheck(alDeleteBuffers(1, &myBuffer));
82 }
83 
84 
88 bool SoundBuffer::LoadFromFile(const std::string& Filename)
89 {
90  // Create the sound file
91  std::auto_ptr<priv::SoundFile> File(priv::SoundFile::CreateRead(Filename));
92 
93  // Open the sound file
94  if (File.get())
95  {
96  // Get the sound parameters
97  std::size_t NbSamples = File->GetSamplesCount();
98  unsigned int ChannelsCount = File->GetChannelsCount();
99  unsigned int SampleRate = File->GetSampleRate();
100 
101  // Read the samples from the opened file
102  mySamples.resize(NbSamples);
103  if (File->Read(&mySamples[0], NbSamples) == NbSamples)
104  {
105  // Update the internal buffer with the new samples
106  return Update(ChannelsCount, SampleRate);
107  }
108  else
109  {
110  // Error...
111  std::cerr << "Failed to read audio data from file \"" << Filename << "\"" << std::endl;
112 
113  return false;
114  }
115  }
116  else
117  {
118  // Error...
119  std::cerr << "Failed to load sound buffer from file \"" << Filename << "\"" << std::endl;
120 
121  return false;
122  }
123 }
124 
125 
129 bool SoundBuffer::LoadFromMemory(const char* Data, std::size_t SizeInBytes)
130 {
131  // Create the sound file
132  std::auto_ptr<priv::SoundFile> File(priv::SoundFile::CreateRead(Data, SizeInBytes));
133 
134  // Open the sound file
135  if (File.get())
136  {
137  // Get the sound parameters
138  std::size_t NbSamples = File->GetSamplesCount();
139  unsigned int ChannelsCount = File->GetChannelsCount();
140  unsigned int SampleRate = File->GetSampleRate();
141 
142  // Read the samples from the opened file
143  mySamples.resize(NbSamples);
144  if (File->Read(&mySamples[0], NbSamples) == NbSamples)
145  {
146  // Update the internal buffer with the new samples
147  return Update(ChannelsCount, SampleRate);
148  }
149  else
150  {
151  // Error...
152  std::cerr << "Failed to read audio data from file in memory" << std::endl;
153 
154  return false;
155  }
156  }
157  else
158  {
159  // Error...
160  std::cerr << "Failed to load sound buffer from file in memory" << std::endl;
161 
162  return false;
163  }
164 }
165 
166 
171 bool SoundBuffer::LoadFromSamples(const Int16* Samples, std::size_t SamplesCount, unsigned int ChannelsCount, unsigned int SampleRate)
172 {
173  if (Samples && SamplesCount && ChannelsCount && SampleRate)
174  {
175  // Copy the new audio samples
176  mySamples.assign(Samples, Samples + SamplesCount);
177 
178  // Update the internal buffer with the new samples
179  return Update(ChannelsCount, SampleRate);
180  }
181  else
182  {
183  // Error...
184  std::cerr << "Failed to load sound buffer from memory ("
185  << "Samples : " << Samples << ", "
186  << "Samples count : " << SamplesCount << ", "
187  << "Channels count : " << ChannelsCount << ", "
188  << "Sample rate : " << SampleRate << ")"
189  << std::endl;
190 
191  return false;
192  }
193 }
194 
195 
199 bool SoundBuffer::SaveToFile(const std::string& Filename) const
200 {
201  // Create the sound file in write mode
202  std::auto_ptr<priv::SoundFile> File(priv::SoundFile::CreateWrite(Filename, GetChannelsCount(), GetSampleRate()));
203  if (File.get())
204  {
205  // Write the samples to the opened file
206  File->Write(&mySamples[0], mySamples.size());
207 
208  return true;
209  }
210  else
211  {
212  // Error...
213  std::cerr << "Failed to save sound buffer to file \"" << Filename << "\"" << std::endl;
214 
215  return false;
216  }
217 }
218 
219 
223 const Int16* SoundBuffer::GetSamples() const
224 {
225  return mySamples.empty() ? NULL : &mySamples[0];
226 }
227 
228 
232 std::size_t SoundBuffer::GetSamplesCount() const
233 {
234  return mySamples.size();
235 }
236 
237 
241 unsigned int SoundBuffer::GetSampleRate() const
242 {
243  ALint SampleRate;
244  ALCheck(alGetBufferi(myBuffer, AL_FREQUENCY, &SampleRate));
245 
246  return SampleRate;
247 }
248 
249 
253 unsigned int SoundBuffer::GetChannelsCount() const
254 {
255  ALint ChannelsCount;
256  ALCheck(alGetBufferi(myBuffer, AL_CHANNELS, &ChannelsCount));
257 
258  return ChannelsCount;
259 }
260 
261 
266 {
267  return myDuration;
268 }
269 
270 
275 {
276  SoundBuffer Temp(Other);
277 
278  std::swap(mySamples, Temp.mySamples);
279  std::swap(myBuffer, Temp.myBuffer);
280  std::swap(myDuration, Temp.myDuration);
281  std::swap(mySounds, Temp.mySounds); // swap sounds too, so that they are detached when Temp is destroyed
282 
283  return *this;
284 }
285 
286 
290 bool SoundBuffer::Update(unsigned int ChannelsCount, unsigned int SampleRate)
291 {
292  // Check parameters
293  if (!SampleRate || !ChannelsCount || mySamples.empty())
294  return false;
295 
296  // Find the good format according to the number of channels
297  ALenum Format = priv::AudioDevice::GetInstance().GetFormatFromChannelsCount(ChannelsCount);
298 
299  // Check if the format is valid
300  if (Format == 0)
301  {
302  std::cerr << "Unsupported number of channels (" << ChannelsCount << ")" << std::endl;
303  return false;
304  }
305 
306  // Fill the buffer
307  ALsizei Size = static_cast<ALsizei>(mySamples.size()) * sizeof(Int16);
308  ALCheck(alBufferData(myBuffer, Format, &mySamples[0], Size, SampleRate));
309 
310  // Compute the duration
311  myDuration = static_cast<float>(mySamples.size()) / SampleRate / ChannelsCount;
312 
313  return true;
314 }
315 
316 
320 void SoundBuffer::AttachSound(Sound* Instance) const
321 {
322  mySounds.insert(Instance);
323 }
324 
325 
329 void SoundBuffer::DetachSound(Sound* Instance) const
330 {
331  mySounds.erase(Instance);
332 }
333 
334 } // namespace sf
const Int16 * GetSamples() const
Return the sound samples.
Base class for every resource that needs to notify dependent classes about its destruction.
Definition: Resource.hpp:50
bool LoadFromMemory(const char *Data, std::size_t SizeInBytes)
Load the sound buffer from a file in memory.
std::size_t GetSamplesCount() const
Return the samples count.
SoundBuffer & operator=(const SoundBuffer &Other)
Assignment operator.
float GetDuration() const
Get the sound duration.
~SoundBuffer()
Destructor.
Definition: SoundBuffer.cpp:73
SoundBuffer()
Default constructor.
Definition: SoundBuffer.cpp:42
bool LoadFromSamples(const Int16 *Samples, std::size_t SamplesCount, unsigned int ChannelsCount, unsigned int SampleRate)
Load the sound buffer from an array of samples - assumed format for samples is 16 bits signed integer...
bool LoadFromFile(const std::string &Filename)
Load the sound buffer from a file.
Definition: SoundBuffer.cpp:88
unsigned int GetSampleRate() const
Get the sample rate.
unsigned int GetChannelsCount() const
Return the number of channels (1 = mono, 2 = stereo, ...)
bool SaveToFile(const std::string &Filename) const
Save the sound buffer to a file.
SoundBuffer is the low-level for loading and manipulating sound buffers.
Definition: SoundBuffer.hpp:46
Abstract base class for every class that owns a device-dependant resource – allow them to initialize ...