1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2018 Jeremy DeHaan (dehaan.jeremiah@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 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 * 24 * 25 * DSFML is based on SFML (Copyright Laurent Gomila) 26 */ 27 28 /** 29 * A sound buffer holds the data of a sound, which is an array of audio samples. 30 * A sample is a 16 bits signed integer that defines the amplitude of the sound 31 * at a given time. The sound is then restituted by playing these samples at a 32 * high rate (for example, 44100 samples per second is the standard rate used 33 * for playing CDs). In short, audio samples are like texture pixels, and a 34 * SoundBuffer is similar to a Texture. 35 * 36 * A sound buffer can be loaded from a file (see `loadFromFile()` for the 37 * complete list of supported formats), from memory, from a custom stream 38 * (see $(INPUTSTREAM_LINK)) or directly from an array of samples. It can also 39 * be saved back to a file. 40 * 41 * Sound buffers alone are not very useful: they hold the audio data but cannot 42 * be played. To do so, you need to use the $(SOUND_LINK) class, which provides 43 * functions to play/pause/stop the sound as well as changing the way it is 44 * outputted (volume, pitch, 3D position, ...). 45 * 46 * This separation allows more flexibility and better performances: indeed a 47 * $(U SoundBuffer) is a heavy resource, and any operation on it is slow (often 48 * too slow for real-time applications). On the other side, a $(SOUND_LINK) is a 49 * lightweight object, which can use the audio data of a sound buffer and change 50 * the way it is played without actually modifying that data. Note that it is 51 * also possible to bind several $(SOUND_LINK) instances to the same 52 * $(U SoundBuffer). 53 * 54 * It is important to note that the Sound instance doesn't copy the buffer that 55 * it uses, it only keeps a reference to it. Thus, a $(U SoundBuffer) must not 56 * be destructed while it is used by a Sound (i.e. never write a function that 57 * uses a local $(U SoundBuffer) instance for loading a sound). 58 * 59 *Example: 60 * --- 61 * // Declare a new sound buffer 62 * auto buffer = SoundBuffer(); 63 * 64 * // Load it from a file 65 * if (!buffer.loadFromFile("sound.wav")) 66 * { 67 * // error... 68 * } 69 * 70 * // Create a sound source and bind it to the buffer 71 * auto sound1 = new Sound(); 72 * sound1.setBuffer(buffer); 73 * 74 * // Play the sound 75 * sound1.play(); 76 * 77 * // Create another sound source bound to the same buffer 78 * auto sound2 = new Sound(); 79 * sound2.setBuffer(buffer); 80 * 81 * // Play it with a higher pitch -- the first sound remains unchanged 82 * sound2.pitch = 2; 83 * sound2.play(); 84 * --- 85 * 86 * See_Also: 87 * $(SOUND_LINK), $(SOUNDBUFFERRECORDER_LINK) 88 */ 89 module dsfml.audio.soundbuffer; 90 91 public import dsfml.system.time; 92 93 import dsfml.audio.inputsoundfile; 94 import dsfml.audio.sound; 95 96 import dsfml.system.inputstream; 97 98 import std.stdio; 99 import std..string; 100 import std.algorithm; 101 import std.array; 102 103 import dsfml.system.err; 104 105 /** 106 * Storage for audio samples defining a sound. 107 */ 108 class SoundBuffer 109 { 110 package sfSoundBuffer* sfPtr; 111 112 /// Default constructor. 113 this() 114 { 115 sfPtr = sfSoundBuffer_construct(); 116 } 117 118 /// Destructor. 119 ~this() 120 { 121 import dsfml.system.config; 122 mixin(destructorOutput); 123 sfSoundBuffer_destroy(sfPtr); 124 } 125 126 /** 127 * Get the array of audio samples stored in the buffer. 128 * 129 * The format of the returned samples is 16 bits signed integer (short). 130 * 131 * Returns: Read-only array of sound samples. 132 */ 133 const(short[]) getSamples() const 134 { 135 auto sampleCount = sfSoundBuffer_getSampleCount(sfPtr); 136 if(sampleCount > 0) 137 return sfSoundBuffer_getSamples(sfPtr)[0 .. sampleCount]; 138 139 return null; 140 } 141 142 /** 143 * Get the sample rate of the sound. 144 * 145 * The sample rate is the number of samples played per second. The higher, 146 * the better the quality (for example, 44100 samples/s is CD quality). 147 * 148 * Returns: Sample rate (number of samples per second). 149 */ 150 uint getSampleRate() const 151 { 152 return sfSoundBuffer_getSampleRate(sfPtr); 153 } 154 155 /** 156 * Get the number of channels used by the sound. 157 * 158 * If the sound is mono then the number of channels will be 1, 2 for stereo, 159 * etc. 160 * 161 * Returns: Number of channels. 162 */ 163 uint getChannelCount() const 164 { 165 return sfSoundBuffer_getChannelCount(sfPtr); 166 } 167 168 /** 169 * Get the total duration of the sound. 170 * 171 * Returns: Sound duration. 172 */ 173 Time getDuration() const 174 { 175 return microseconds(sfSoundBuffer_getDuration(sfPtr)); 176 } 177 178 /** 179 * Load the sound buffer from a file. 180 * 181 * The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. The 182 * supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. 183 * 184 * Params: 185 * filename = Path of the sound file to load 186 * 187 * Returns: true if loading succeeded, false if it failed. 188 */ 189 bool loadFromFile(const(char)[] filename) 190 { 191 return sfSoundBuffer_loadFromFile(sfPtr, filename.ptr, filename.length); 192 } 193 194 /** 195 * Load the sound buffer from a file in memory. 196 * 197 * The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. The 198 * supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. 199 * 200 * Params: 201 * data = The array of data 202 * 203 * Returns: true if loading succeeded, false if it failed. 204 */ 205 bool loadFromMemory(const(void)[] data) 206 { 207 return sfSoundBuffer_loadFromMemory(sfPtr, data.ptr, data.length); 208 } 209 210 /* 211 * Load the sound buffer from a custom stream. 212 * 213 * The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. The 214 * supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. 215 * 216 * Params: 217 * stream = Source stream to read from 218 * 219 * Returns: true if loading succeeded, false if it failed. 220 */ 221 bool loadFromStream(InputStream stream) 222 { 223 return sfSoundBuffer_loadFromStream(sfPtr, new SoundBufferStream(stream)); 224 } 225 226 /** 227 * Load the sound buffer from an array of audio samples. 228 * 229 * The assumed format of the audio samples is 16 bits signed integer 230 * (short). 231 * 232 * Params: 233 * samples = Array of samples in memory 234 * channelCount = Number of channels (1 = mono, 2 = stereo, ...) 235 * sampleRate = Sample rate (number of samples to play per second) 236 * 237 * Returns: true if loading succeeded, false if it failed. 238 */ 239 bool loadFromSamples(const(short[]) samples, uint channelCount, uint sampleRate) 240 { 241 return sfSoundBuffer_loadFromSamples(sfPtr, samples.ptr, samples.length, channelCount, sampleRate); 242 } 243 244 /** 245 * Save the sound buffer to an audio file. 246 * 247 * The supported audio formats are: WAV, OGG/Vorbis, FLAC. 248 * 249 * Params: 250 * filename = Path of the sound file to write 251 * 252 * Returns: true if saving succeeded, false if it failed. 253 */ 254 bool saveToFile(const(char)[] filename) const 255 { 256 return sfSoundBuffer_saveToFile(sfPtr, filename.ptr, filename.length); 257 } 258 259 } 260 261 unittest 262 { 263 version(DSFML_Unittest_Audio) 264 { 265 import std.stdio; 266 267 writeln("Unit test for sound buffer"); 268 269 auto soundbuffer = new SoundBuffer(); 270 271 if(!soundbuffer.loadFromFile("res/TestSound.ogg")) 272 { 273 //error 274 return; 275 } 276 277 writeln("Sample Rate: ", soundbuffer.getSampleRate()); 278 279 writeln("Channel Count: ", soundbuffer.getChannelCount()); 280 281 writeln("Duration: ", soundbuffer.getDuration().asSeconds()); 282 283 writeln("Sample Count: ", soundbuffer.getSamples().length); 284 285 //use sound buffer here 286 287 writeln(); 288 } 289 } 290 291 private extern(C++) interface sfmlInputStream 292 { 293 long read(void* data, long size); 294 295 long seek(long position); 296 297 long tell(); 298 299 long getSize(); 300 } 301 302 private class SoundBufferStream:sfmlInputStream 303 { 304 private InputStream myStream; 305 306 this(InputStream stream) 307 { 308 myStream = stream; 309 } 310 311 extern(C++)long read(void* data, long size) 312 { 313 return myStream.read(data[0..cast(size_t)size]); 314 } 315 316 extern(C++)long seek(long position) 317 { 318 return myStream.seek(position); 319 } 320 321 extern(C++)long tell() 322 { 323 return myStream.tell(); 324 } 325 326 extern(C++)long getSize() 327 { 328 return myStream.getSize(); 329 } 330 } 331 332 package struct sfSoundBuffer; 333 334 private extern(C): 335 336 sfSoundBuffer* sfSoundBuffer_construct(); 337 338 bool sfSoundBuffer_loadFromFile(sfSoundBuffer* soundBuffer, const char* filename, size_t length); 339 340 bool sfSoundBuffer_loadFromMemory(sfSoundBuffer* soundBuffer, const void* data, size_t sizeInBytes); 341 342 bool sfSoundBuffer_loadFromStream(sfSoundBuffer* soundBuffer, sfmlInputStream stream); 343 344 bool sfSoundBuffer_loadFromSamples(sfSoundBuffer* soundBuffer, const short* samples, size_t sampleCount, uint channelCount, uint sampleRate); 345 346 sfSoundBuffer* sfSoundBuffer_copy(const sfSoundBuffer* soundBuffer); 347 348 void sfSoundBuffer_destroy(sfSoundBuffer* soundBuffer); 349 350 bool sfSoundBuffer_saveToFile(const sfSoundBuffer* soundBuffer, const char* filename, size_t length); 351 352 const(short)* sfSoundBuffer_getSamples(const sfSoundBuffer* soundBuffer); 353 354 size_t sfSoundBuffer_getSampleCount(const sfSoundBuffer* soundBuffer); 355 356 uint sfSoundBuffer_getSampleRate(const sfSoundBuffer* soundBuffer); 357 358 uint sfSoundBuffer_getChannelCount(const sfSoundBuffer* soundBuffer); 359 360 long sfSoundBuffer_getDuration(const sfSoundBuffer* soundBuffer);