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 public import audioformats.internals: AudioFormatsException; 16 import core.stdc.stdlib: free; 17 18 /// Frees an exception thrown by audio-formats. 19 void destroyAudioFormatException(AudioFormatsException e) nothrow @nogc 20 { 21 import audioformats.internals; 22 destroyFree!AudioFormatsException(e); 23 } 24 25 26 /// Encode a slice to a WAV file. 27 /// 28 /// Returns: `true` on success. 29 bool saveAsWAV(const(float)[] data, 30 const(char)[] filePath, 31 int numChannels = 1, 32 float sampleRate = 44100.0f, 33 EncodingOptions options = EncodingOptions.init) nothrow @nogc 34 { 35 return saveAsWAVImpl!float(data, filePath, numChannels, sampleRate, options); 36 } 37 ///ditto 38 bool saveAsWAV(const(double)[] data, 39 const(char)[] filePath, 40 int numChannels = 1, 41 float sampleRate = 44100.0f, 42 EncodingOptions options = EncodingOptions.init) nothrow @nogc 43 { 44 return saveAsWAVImpl!double(data, filePath, numChannels, sampleRate, options); 45 } 46 47 48 /// Encode a slice to a WAV in memory. 49 /// The returned slice MUST be freed with `freeEncodedAudio`. 50 /// 51 /// Returns: `null` in case of error. 52 const(ubyte)[] toWAV(const(float)[] data, 53 int numChannels = 1, 54 float sampleRate = 44100.0f, 55 EncodingOptions options = EncodingOptions.init) nothrow @nogc 56 { 57 return toWAVImpl!float(data, numChannels, sampleRate, options); 58 } 59 ///ditto 60 const(ubyte)[] toWAV(const(double)[] data, 61 int numChannels = 1, 62 float sampleRate = 44100.0f, 63 EncodingOptions options = EncodingOptions.init) nothrow @nogc 64 { 65 return toWAVImpl!double(data, numChannels, sampleRate, options); 66 } 67 68 69 /// Disowned audio buffers (with eg. `encodeToWAV`) must be freed with this function. 70 void freeEncodedAudio(const(ubyte)[] encoded) 71 { 72 free(cast(void*)encoded.ptr); 73 } 74 75 76 private: 77 78 79 const(ubyte)[] toWAVImpl(T)(const(T)[] data, int numChannels, float sampleRate, EncodingOptions options) nothrow @nogc 80 { 81 assert(data !is null); 82 import core.stdc.string: strlen; 83 84 try 85 { 86 AudioStream encoder; 87 encoder.openToBuffer(AudioFileFormat.wav, sampleRate, numChannels, options); 88 static if (is(T == float)) 89 encoder.writeSamplesFloat(data); 90 else 91 encoder.writeSamplesDouble(data); 92 const(ubyte)[] r = encoder.finalizeAndGetEncodedResultDisown(); 93 return r; 94 } 95 catch (AudioFormatsException e) 96 { 97 destroyAudioFormatException(e); 98 return null; 99 } 100 catch(Exception e) 101 { 102 return null; 103 } 104 } 105 106 bool saveAsWAVImpl(T)(const(T)[] data, 107 const(char)[] filePath, 108 int numChannels, 109 float sampleRate, 110 EncodingOptions options) nothrow @nogc 111 { 112 if (data is null) 113 return false; 114 if (filePath is null) 115 return false; 116 117 import core.stdc.string: strlen; 118 119 try 120 { 121 AudioStream encoder; 122 encoder.openToFile(filePath, AudioFileFormat.wav, sampleRate, numChannels, options); 123 static if (is(T == float)) 124 encoder.writeSamplesFloat(data); 125 else 126 encoder.writeSamplesDouble(data); 127 encoder.flush(); 128 encoder.finalizeEncoding(); 129 } 130 catch (AudioFormatsException e) 131 { 132 destroyAudioFormatException(e); 133 return false; 134 } 135 catch(Exception e) 136 { 137 return false; 138 } 139 return true; 140 }