The OpenD Programming Language

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 }