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 nudsfml.audio.old.soundbuffer; 90 91 import bindbc.sfml.audio; 92 import bindbc.sfml.system; 93 94 public import nudsfml.system.time; 95 96 import nudsfml.audio.inputsoundfile; 97 import nudsfml.audio.sound; 98 99 import nudsfml.system.inputstream; 100 101 import std.stdio; 102 import std.string; 103 import std.algorithm; 104 import std.array; 105 106 import nudsfml.system.err; 107 108 /** 109 * Storage for audio samples defining a sound. 110 */ 111 class SoundBuffer { 112 package sfSoundBuffer* sfPtr; 113 114 /// Default constructor. 115 this() { 116 sfPtr = null; 117 } 118 119 /// Destructor. 120 ~this() { 121 import nudsfml.system.config; 122 123 mixin(destructorOutput); 124 if (sfPtr !is null) { 125 sfSoundBuffer_destroy(sfPtr); 126 } 127 } 128 129 /** 130 * Get the array of audio samples stored in the buffer. 131 * 132 * The format of the returned samples is 16 bits signed integer (short). 133 * 134 * Returns: Read-only array of sound samples. 135 */ 136 const(short[]) getSamples() const { 137 auto sampleCount = sfSoundBuffer_getSampleCount(sfPtr); 138 if (sampleCount > 0) 139 return sfSoundBuffer_getSamples(sfPtr)[0 .. sampleCount]; 140 141 return null; 142 } 143 144 /** 145 * Get the sample rate of the sound. 146 * 147 * The sample rate is the number of samples played per second. The higher, 148 * the better the quality (for example, 44100 samples/s is CD quality). 149 * 150 * Returns: Sample rate (number of samples per second). 151 */ 152 uint getSampleRate() const { 153 return sfSoundBuffer_getSampleRate(sfPtr); 154 } 155 156 /** 157 * Get the number of channels used by the sound. 158 * 159 * If the sound is mono then the number of channels will be 1, 2 for stereo, 160 * etc. 161 * 162 * Returns: Number of channels. 163 */ 164 uint getChannelCount() const { 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 return cast(Time) sfSoundBuffer_getDuration(sfPtr); 175 } 176 177 /** 178 * Load the sound buffer from a file. 179 * 180 * The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. The 181 * supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. 182 * 183 * Params: 184 * filename = Path of the sound file to load 185 * 186 * Returns: true if loading succeeded, false if it failed. 187 */ 188 bool loadFromFile(const(char)[] filename) { 189 import std.string; 190 191 if (sfPtr !is null) { 192 sfSoundBuffer_destroy(sfPtr); 193 } 194 sfPtr = sfSoundBuffer_createFromFile(filename.toStringz); 195 return sfPtr !is null; 196 } 197 198 /** 199 * Load the sound buffer from a file in memory. 200 * 201 * The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. The 202 * supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. 203 * 204 * Params: 205 * data = The array of data 206 * 207 * Returns: true if loading succeeded, false if it failed. 208 */ 209 bool loadFromMemory(const(void)[] data) { 210 if (sfPtr !is null) { 211 sfSoundBuffer_destroy(sfPtr); 212 } 213 sfPtr = sfSoundBuffer_createFromMemory(data.ptr, data.length); 214 return sfPtr !is null; 215 } 216 217 /* 218 * Load the sound buffer from a custom stream. 219 * 220 * The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC. The 221 * supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit. 222 * 223 * Params: 224 * stream = Source stream to read from 225 * 226 * Returns: true if loading succeeded, false if it failed. 227 */ 228 /*bool loadFromStream(InputStream stream) 229 { 230 return sfSoundBuffer_loadFromStream(sfPtr, new SoundBufferStream(stream)); 231 } 232 */ 233 /** 234 * Load the sound buffer from an array of audio samples. 235 * 236 * The assumed format of the audio samples is 16 bits signed integer 237 * (short). 238 * 239 * Params: 240 * samples = Array of samples in memory 241 * channelCount = Number of channels (1 = mono, 2 = stereo, ...) 242 * sampleRate = Sample rate (number of samples to play per second) 243 * 244 * Returns: true if loading succeeded, false if it failed. 245 */ 246 bool loadFromSamples(const(short[]) samples, uint channelCount, uint sampleRate) { 247 if (sfPtr !is null) { 248 sfSoundBuffer_destroy(sfPtr); 249 } 250 sfPtr = sfSoundBuffer_createFromSamples(samples.ptr, samples.length, channelCount, sampleRate); 251 return sfPtr !is null; 252 } 253 254 /** 255 * Save the sound buffer to an audio file. 256 * 257 * The supported audio formats are: WAV, OGG/Vorbis, FLAC. 258 * 259 * Params: 260 * filename = Path of the sound file to write 261 * 262 * Returns: true if saving succeeded, false if it failed. 263 */ 264 bool saveToFile(const(char)[] filename) const { 265 import std.string; 266 267 return sfSoundBuffer_saveToFile(sfPtr, filename.toStringz) > 0; 268 } 269 270 } 271 272 unittest { 273 version (DSFML_Unittest_Audio) { 274 import std.stdio; 275 276 writeln("Unit test for sound buffer"); 277 278 auto soundbuffer = new SoundBuffer(); 279 280 if (!soundbuffer.loadFromFile("res/TestSound.ogg")) { 281 //error 282 return; 283 } 284 285 writeln("Sample Rate: ", soundbuffer.getSampleRate()); 286 287 writeln("Channel Count: ", soundbuffer.getChannelCount()); 288 289 writeln("Duration: ", soundbuffer.getDuration().asSeconds()); 290 291 writeln("Sample Count: ", soundbuffer.getSamples().length); 292 293 //use sound buffer here 294 295 writeln(); 296 } 297 } 298 299 private extern (C++) interface sfmlInputStream { 300 long read(void* data, long size); 301 302 long seek(long position); 303 304 long tell(); 305 306 long getSize(); 307 } 308 309 private class SoundBufferStream : sfmlInputStream { 310 private InputStream myStream; 311 312 this(InputStream stream) { 313 myStream = stream; 314 } 315 316 extern (C++) long read(void* data, long size) { 317 return myStream.read(data[0 .. cast(size_t) size]); 318 } 319 320 extern (C++) long seek(long position) { 321 return myStream.seek(position); 322 } 323 324 extern (C++) long tell() { 325 return myStream.tell(); 326 } 327 328 extern (C++) long getSize() { 329 return myStream.getSize(); 330 } 331 }