1 /** 2 Library for sound file decoding and encoding. See README.md for licence explanations. 3 4 Copyright: Guillaume Piolats 2020. 5 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 */ 7 module audioformats; 8 9 10 // Public API 11 12 public import audioformats.stream; 13 14 15 import core.stdc.stdlib: free; 16 17 nothrow @nogc: 18 19 /// Encode a slice to a WAV file. 20 /// 21 /// Returns: `true` on success. 22 bool saveAsWAV(const(float)[] data, 23 const(char)[] filePath, 24 int numChannels = 1, 25 float sampleRate = 44100.0f, 26 EncodingOptions options = EncodingOptions.init) 27 { 28 return saveAsWAVImpl!float(data, filePath, numChannels, sampleRate, options); 29 } 30 ///ditto 31 bool saveAsWAV(const(double)[] data, 32 const(char)[] filePath, 33 int numChannels = 1, 34 float sampleRate = 44100.0f, 35 EncodingOptions options = EncodingOptions.init) 36 { 37 return saveAsWAVImpl!double(data, filePath, numChannels, sampleRate, options); 38 } 39 40 41 /// Encode a slice to a WAV in memory. 42 /// The returned slice MUST be freed with `freeEncodedAudio`. 43 /// 44 /// Returns: `null` in case of error. 45 const(ubyte)[] toWAV(const(float)[] data, 46 int numChannels = 1, 47 float sampleRate = 44100.0f, 48 EncodingOptions options = EncodingOptions.init) 49 { 50 return toWAVImpl!float(data, numChannels, sampleRate, options); 51 } 52 ///ditto 53 const(ubyte)[] toWAV(const(double)[] data, 54 int numChannels = 1, 55 float sampleRate = 44100.0f, 56 EncodingOptions options = EncodingOptions.init) 57 { 58 return toWAVImpl!double(data, numChannels, sampleRate, options); 59 } 60 61 62 /// Disowned audio buffers (with eg. `encodeToWAV`) must be freed with this function. 63 void freeEncodedAudio(const(ubyte)[] encoded) 64 { 65 free(cast(void*)encoded.ptr); 66 } 67 68 69 private: 70 71 72 const(ubyte)[] toWAVImpl(T)(const(T)[] data, int numChannels, float sampleRate, EncodingOptions options) 73 { 74 assert(data !is null); 75 import core.stdc.string: strlen; 76 77 AudioStream encoder; 78 encoder.openToBuffer(AudioFileFormat.wav, sampleRate, numChannels, options); 79 if (encoder.isError) 80 return null; 81 static if (is(T == float)) 82 encoder.writeSamplesFloat(data); 83 else 84 encoder.writeSamplesDouble(data); 85 if (encoder.isError) 86 return null; 87 const(ubyte)[] r = encoder.finalizeAndGetEncodedResultDisown(); 88 return r; 89 } 90 91 bool saveAsWAVImpl(T)(const(T)[] data, 92 const(char)[] filePath, 93 int numChannels, 94 float sampleRate, 95 EncodingOptions options) 96 { 97 if (data is null) 98 return false; 99 if (filePath is null) 100 return false; 101 102 import core.stdc.string: strlen; 103 104 AudioStream encoder; 105 encoder.openToFile(filePath, AudioFileFormat.wav, sampleRate, numChannels, options); 106 if (encoder.isError) 107 return false; // opening failed 108 109 static if (is(T == float)) 110 encoder.writeSamplesFloat(data); 111 else 112 encoder.writeSamplesDouble(data); 113 if (encoder.isError) 114 return false; // writing samples failed 115 116 encoder.flush(); 117 if (encoder.isError) 118 return false; // flushing failed 119 120 encoder.finalizeEncoding(); 121 if (encoder.isError) 122 return false; // finalizing encoding failed 123 return true; 124 }