The OpenD Programming Language

1 /**
2 Audio decoder and encoder abstraction. This delegates to format-specific encoders/decoders.
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.stream;
8 
9 import core.stdc.stdio;
10 import core.stdc.string;
11 import core.stdc.stdlib: malloc, realloc, free;
12 
13 import audioformats.io;
14 import audioformats.internals;
15 
16 version(decodeMP3) import audioformats.minimp3_ex;
17 version(decodeFLAC) import audioformats.drflac;
18 version(decodeOGG) import audioformats.stb_vorbis2;
19 version(decodeOPUS) import audioformats.dopus;
20 version(decodeMOD) import audioformats.pocketmod;
21 
22 version(decodeWAV) import audioformats.wav;
23 else version(encodeWAV) import audioformats.wav;
24 
25 version(decodeQOA) import audioformats.qoa;
26 else version(encodeQOA) import audioformats.qoa;
27 
28 version(decodeXM) import audioformats.libxm;
29 
30 /// Library for sound file decoding and encoding.
31 /// All operations are blocking, and should not be done in a real-time audio thread.
32 /// (besides, you would also need resampling for playback).
33 /// Also not thread-safe, synchronization in on yours.
34 
35 /// Format of audio files.
36 enum AudioFileFormat
37 {
38     wav,  /// WAVE format
39     mp3,  /// MP3  format
40     flac, /// FLAC format
41     ogg,  /// OGG  format
42     opus, /// Opus format
43     qoa,  /// QOA format https://qoaformat.org/
44     mod,  /// ProTracker MOD format
45     xm,   /// FastTracker II Extended Module format
46     unknown
47 }
48 
49 /// Output sample format.
50 enum AudioSampleFormat
51 {
52     s8,   /// Signed 8-bit PCM
53     s16,  /// Signed 16-bit PCM
54     s24,  /// Signed 24-bit PCM
55     fp32, /// 32-bit floating-point
56     fp64  /// 64-bit floating-point
57 }
58 
59 /// An optional struct, passed when encoding a sound (WAV or QOA).
60 struct EncodingOptions
61 {
62     /// The desired sample bitdepth to encode with. This ignored for QOA.
63     AudioSampleFormat sampleFormat = AudioSampleFormat.fp32; // defaults to 32-bit float
64 
65     /// Enable dither when exporting 8-bit, 16-bit, 24-bit WAV, or QOA
66     bool enableDither = true;
67 }
68 
69 /// Returns: String representation of an `AudioFileFormat`.
70 string convertAudioFileFormatToString(AudioFileFormat fmt)
71 {
72     final switch(fmt) with (AudioFileFormat)
73     {
74         case wav:     return "wav";
75         case mp3:     return "mp3";
76         case flac:    return "flac";
77         case ogg:     return "ogg";
78         case opus:    return "opus";
79         case qoa:     return "qoa";
80         case mod:     return "mod";
81         case xm:      return "xm";
82         case unknown: return "unknown";
83     }
84 }
85 
86 
87 /// The length of things you shouldn't query a length about:
88 ///    - files that are being written
89 ///    - audio files you don't know the extent
90 enum audiostreamUnknownLength = -1;
91 
92 /// An AudioStream is a pointer to a dynamically allocated `Stream`.
93 /// It can encode and decode to audio files or in memory.
94 ///
95 /// AudioStream are subtyped like this:
96 ///
97 ///               AudioStream         AudioStream can be: isError() or isValid().
98 ///                /     \            Image start their life as AudioStream.init in error state.
99 ///        isError()  or  isValid()   Image that are `isError` can only call the open functions to reboot them.
100 ///
101 /// TODO: specify how usable is an isError() stream, what is still available (if any)
102 public struct AudioStream
103 {
104 public: // This is also part of the public API 
105 nothrow @nogc:
106 
107     /// Opens an audio stream that decodes from a file.
108     /// This stream will be opened for reading only.
109     ///
110     /// Params: 
111     ///     path An UTF-8 path to the sound file.
112     ///
113     /// Note: throws a manually allocated exception in case of error. Free it with `destroyAudioFormatsException`.
114     // TODO: break API, make that nothrow, and use isError flag instead
115     void openFromFile(const(char)[] path)
116     {
117         cleanUp();
118         clearErrorStatus();
119 
120         fileContext = mallocNew!FileContext();
121         bool err;
122         fileContext.initialize(path, false, &err);
123         if (err)
124         {
125             cleanUp();
126             setError(kErrorFileOpenFailed.ptr);
127             return;
128         }
129 
130         userData = fileContext;
131 
132         _io = mallocNew!IOCallbacks();
133         _io.seek          = &file_seek;
134         _io.tell          = &file_tell;
135         _io.getFileLength = &file_getFileLength;
136         _io.read          = &file_read;
137         _io.write         = null;
138         _io.skip          = &file_skip;
139         _io.flush         = null;
140 
141         startDecoding();
142     }
143 
144     /// Opens an audio stream that decodes from memory.
145     /// This stream will be opened for reading only.
146     /// Note: throws a manually allocated exception in case of error. Free it with `destroyAudioFormatsException`.
147     ///
148     /// Params: inputData The whole file to decode.
149     // TODO: break API, make that nothrow, and use isError flag instead
150     void openFromMemory(const(ubyte)[] inputData) @nogc
151     {
152         cleanUp();
153         clearErrorStatus();
154 
155         memoryContext = mallocNew!MemoryContext();
156         memoryContext.initializeWithConstantInput(inputData.ptr, inputData.length);
157 
158         userData = memoryContext;
159 
160         _io = mallocNew!IOCallbacks();
161         _io.seek          = &memory_seek;
162         _io.tell          = &memory_tell;
163         _io.getFileLength = &memory_getFileLength;
164         _io.read          = &memory_read;
165         _io.write         = null;
166         _io.skip          = &memory_skip;
167         _io.flush         = null;
168 
169         startDecoding();
170     }
171 
172     /// Opens an audio stream that writes to file.
173     /// This stream will be open for writing only.
174     /// Note: throws a manually allocated exception in case of error. Free it with `destroyAudioFormatsException`.
175     ///
176     /// Params: 
177     ///     path An UTF-8 path to the sound file.
178     ///     format Audio file format to generate.
179     ///     sampleRate Sample rate of this audio stream. This samplerate might be rounded up to the nearest integer number.
180     ///     numChannels Number of channels of this audio stream.
181     // TODO: break API, make that nothrow, and use isError flag instead
182     void openToFile(const(char)[] path, 
183                     AudioFileFormat format, 
184                     float sampleRate, 
185                     int numChannels, 
186                     EncodingOptions options = EncodingOptions.init) @nogc
187     {
188         cleanUp();
189         clearErrorStatus();
190         
191         fileContext = mallocNew!FileContext();
192         bool err;
193         fileContext.initialize(path, true, &err);
194 
195         if (err)
196         {
197             cleanUp();
198             setError(kErrorFileOpenFailed.ptr);
199             return;
200         }
201 
202         userData = fileContext;
203 
204         _io = mallocNew!IOCallbacks();
205         _io.seek          = &file_seek;
206         _io.tell          = &file_tell;
207         _io.getFileLength = null;
208         _io.read          = null;
209         _io.write         = &file_write;
210         _io.skip          = null;
211         _io.flush         = &file_flush;
212 
213         startEncoding(format, sampleRate, numChannels, options);
214     }
215 
216     /// Opens an audio stream that writes to a dynamically growable output buffer.
217     /// This stream will be open for writing only.
218     /// Access to the internal buffer after encoding with `finalizeAndGetEncodedResult`.
219     /// Note: throws a manually allocated exception in case of error. Free it with `destroyAudioFormatsException`.
220     ///
221     /// Params: 
222     ///     format Audio file format to generate.
223     ///     sampleRate Sample rate of this audio stream. This samplerate might be rounded up to the nearest integer number.
224     ///     numChannels Number of channels of this audio stream.
225     // TODO: break API, make that nothrow, and use isError flag instead
226     void openToBuffer(AudioFileFormat format, 
227                       float sampleRate, 
228                       int numChannels,
229                       EncodingOptions options = EncodingOptions.init) @nogc
230     {
231         cleanUp();
232         clearErrorStatus();
233 
234         memoryContext = mallocNew!MemoryContext();
235         memoryContext.initializeWithInternalGrowableBuffer();
236         userData = memoryContext;
237 
238         _io = mallocNew!IOCallbacks();
239         _io.seek          = &memory_seek;
240         _io.tell          = &memory_tell;
241         _io.getFileLength = null;
242         _io.read          = null;
243         _io.write         = &memory_write_append;
244         _io.skip          = null;
245         _io.flush         = &memory_flush;
246 
247         startEncoding(format, sampleRate, numChannels, options);
248     }
249 
250     /// Opens an audio stream that writes to a pre-defined area in memory of `maxLength` bytes.
251     /// This stream will be open for writing only.
252     /// Destroy this stream with `closeAudioStream`.
253     /// Note: throws a manually allocated exception in case of error. Free it with `destroyAudioFormatsException`.
254     ///
255     /// Params: 
256     ///     data Pointer to output memory.
257     ///     size_t maxLength.
258     ///     format Audio file format to generate.
259     ///     sampleRate Sample rate of this audio stream. This samplerate might be rounded up to the nearest integer number.
260     ///     numChannels Number of channels of this audio stream.
261     // TODO: break API, make that nothrow, and use isError flag instead
262     void openToMemory(ubyte* data, 
263                       size_t maxLength,
264                       AudioFileFormat format,
265                       float sampleRate, 
266                       int numChannels,
267                       EncodingOptions options = EncodingOptions.init) @nogc
268     {
269         cleanUp();
270         clearErrorStatus();
271 
272         memoryContext = mallocNew!MemoryContext();
273         memoryContext.initializeWithExternalOutputBuffer(data, maxLength);
274         userData = memoryContext;
275 
276         _io = mallocNew!IOCallbacks();
277         _io.seek          = &memory_seek;
278         _io.tell          = &memory_tell;
279         _io.getFileLength = null;
280         _io.read          = null;
281         _io.write         = &memory_write_limited;
282         _io.skip          = null;
283         _io.flush         = &memory_flush;
284 
285         startEncoding(format, sampleRate, numChannels, options);
286     }
287 
288     ~this() @nogc
289     {
290         cleanUp();
291     }
292 
293     /// FUTURE: will replace Exception.
294     /// An AudioStream that is `isError` cannot be used except for initialization again.
295     bool isError() pure const
296     {
297         return _error !is null;
298     }
299 
300     /// AudioStream is valid, meaning it is not in error state.
301     /// Always return `!isError()`.
302     bool isValid() pure const
303     {
304         return _error is null;
305     }
306 
307     /// The error message (null if no error currently held).
308     /// This slice is followed by a '\0' zero terminal character, so
309     /// it can be safely given to a print function.
310     /// Tags: none.
311     immutable(char)[] errorMessage() pure const @trusted
312     {
313         if (_error is null)
314             return null;
315         return _error[0..strlen(_error)];
316     }
317 
318     /// Returns: File format of this stream.
319     AudioFileFormat getFormat() nothrow @nogc
320     {
321         return _format;
322     }
323 
324     /// Returns: `true` if using this stream's operations is acceptable in an audio thread (eg: no file I/O).
325     bool realtimeSafe() nothrow @nogc
326     {
327         return fileContext is null;
328     }
329 
330     /// Returns: `true` if this stream is concerning a tracker module format.
331     /// This is useful because the seek/tell functions are different.
332     bool isModule() nothrow @nogc
333     {
334         final switch(_format) with (AudioFileFormat)
335         {
336             case wav:
337             case mp3:
338             case flac:
339             case ogg:
340             case opus:
341             case qoa:
342                 return false;
343             case mod:
344             case xm:
345                 return true;
346             case unknown:
347                 assert(false);
348 
349         }
350     }
351 
352     /// Returns: `true` if this stream allows seeking.
353     /// Note: the particular function to call for seeking depends on whether the stream is a tracker module.
354     /// See_also: `seekPosition`.
355     bool canSeek() nothrow @nogc
356     {
357         final switch(_format) with (AudioFileFormat)
358         {
359             case wav:
360             case mp3:
361             case flac:
362             case ogg:
363             case opus:
364             case qoa:
365                 return true;
366             case mod:
367             case xm:
368                 return true;
369             case unknown:
370                 assert(false);
371 
372         }
373     }
374 
375     /// Returns: `true` if this stream is currently open for reading (decoding).
376     ///          `false` if the stream has been destroyed, or if it was created for encoding instead.
377     bool isOpenForReading() nothrow @nogc
378     {
379         return (_io !is null) && (_io.read !is null);
380     }
381 
382     deprecated("Use isOpenForWriting instead") alias isOpenedForWriting = isOpenForWriting;
383 
384     /// Returns: `true` if this stream is currently open for writing (encoding).
385     ///          `false` if the stream has been destroyed, finalized with `finalizeEncoding()`, 
386     ///          or if it was created for decoding instead.    
387     bool isOpenForWriting() nothrow @nogc
388     {
389         // Note: 
390         //  * when opened for reading, I/O operations given are: seek/tell/getFileLength/read.
391         //  * when opened for writing, I/O operations given are: seek/tell/write/flush.
392         return (_io !is null) && (_io.read is null);
393     }
394 
395     /// Returns: Number of channels in this stream. 1 means mono, 2 means stereo...
396     int getNumChannels() nothrow @nogc
397     {
398         return _numChannels;
399     }
400 
401     /// Returns: Length of this stream in frames.
402     /// Note: may return the special value `audiostreamUnknownLength` if the length is unknown.
403     long getLengthInFrames() nothrow @nogc
404     {
405         return _lengthInFrames;
406     }
407 
408     /// Returns: Sample-rate of this stream in Hz.
409     float getSamplerate() nothrow @nogc
410     {
411         return _sampleRate;
412     }
413 
414     /// Read interleaved float samples in the given buffer `outData`.
415     /// 
416     /// Params:
417     ///     outData Buffer where to put decoded samples. Samples are arranged in an interleaved fashion.
418     ///             Must have room for `frames` x `getNumChannels()` samples.
419     ///             For a stereo file, the output data will contain LRLRLR... repeated `result` times.
420     ///
421     ///     frames The number of multichannel frames to be read. 
422     ///            A frame is `getNumChannels()` samples.
423     ///
424     /// Returns: Number of actually read frames. Multiply by `getNumChannels()` to get the number of read samples.
425     ///          When that number is less than `frames`, it means the stream is done decoding, or that there was a decoding error.
426     ///          If there was an error, `isError()` is set. Do not call decoding again in that case.
427     ///
428     /// TODO: once this returned less than `frames`, are we guaranteed we can keep calling that and it returns 0?
429     int readSamplesFloat(float* outData, int frames) nothrow @nogc
430     {
431         assert(isOpenForReading());
432 
433         final switch(_format)
434         {
435             case AudioFileFormat.opus:
436             {
437                 version(decodeOPUS)
438                 {
439                     // Can't decoder further than end of the stream.
440                     if (_opusPositionFrame + frames > _lengthInFrames)
441                     {
442                         frames = cast(int)(_lengthInFrames - _opusPositionFrame);
443                     }
444 
445                     int decoded = 0;
446                     while (decoded < frames)
447                     {
448                         // Is there any sample left in _opusBuffer?
449                         // If not decode some frames.
450                         if (_opusBuffer is null || _opusBuffer.length == 0)
451                         {
452                             bool err;
453                             _opusBuffer = _opusDecoder.readFrame(&err);
454                             if (err)
455                             {   
456                                 setError(kErrorDecoderInitializationFailed.ptr);
457                                 return 0;
458                             }
459                             if (_opusBuffer is null)
460                                 break;
461                         }
462 
463                         int samplesInBuffer = cast(int) _opusBuffer.length;
464                         int framesInBuffer  = samplesInBuffer / _numChannels;
465                         if (framesInBuffer == 0)
466                             break;
467 
468                         // Frames to pull are min( frames left to decode, frames available)
469                         int framesToDecode = frames - decoded;
470                         int framesToUse = framesToDecode < framesInBuffer ? framesToDecode : framesInBuffer;
471                         assert(framesToUse != 0);
472 
473                         int samplesToUse = framesToUse * _numChannels;
474                         int outOffset = decoded*_numChannels;
475 
476                         if (outData !is null) // for seeking, we have the ability in OPUS to call readSamplesFloat with no outData
477                         {
478                             for (int n = 0; n < samplesToUse; ++n)
479                             {
480                                 outData[outOffset + n] = _opusBuffer[n] / 32767.0f;
481                             }
482                         }
483                         _opusBuffer = _opusBuffer[samplesToUse..$]; // reduce size of intermediate buffer
484                         decoded += framesToUse;
485                     }
486                     _opusPositionFrame += decoded;
487                     assert(_opusPositionFrame <= _lengthInFrames);
488                     return decoded;
489                 }
490             }
491 
492             case AudioFileFormat.flac:
493             {
494                 version(decodeFLAC)
495                 {
496                     assert(_flacDecoder !is null);
497 
498                     if (_flacPositionFrame == _lengthInFrames)
499                         return 0; // internally the decoder might be elsewhere
500 
501                     int* integerData = cast(int*)outData;
502 
503                     int samples = cast(int) drflac_read_s32(_flacDecoder, frames * _numChannels, integerData);
504 
505                     // "Samples are always output as interleaved signed 32-bit PCM."
506                     // Convert to float with type-punning. Note that this looses some precision.
507                     double factor = 1.0 / int.max;
508                     foreach(n; 0..samples)
509                     {
510                         outData[n] = integerData[n]  * factor;
511                     }
512                     int framesDecoded = samples / _numChannels;
513                     _flacPositionFrame += framesDecoded;
514                     return framesDecoded;
515                 }
516                 else
517                 {
518                     assert(false); // Impossible
519                 }
520             }
521             
522             case AudioFileFormat.ogg:
523             {
524                 version(decodeOGG)
525                 {
526                     assert(_oggHandle !is null);
527                     int framesRead = stb_vorbis_get_samples_float_interleaved(_oggHandle, _numChannels, outData, frames * _numChannels);
528                     _oggPositionFrame += framesRead;
529                     return framesRead;
530                 }
531                 else
532                 {
533                     assert(false); // Impossible
534                 }
535             }
536 
537             case AudioFileFormat.mp3:
538             {
539                 version(decodeMP3)
540                 {
541                     assert(_mp3DecoderNew !is null);
542 
543                     int samplesNeeded = frames * _numChannels;
544                     int result = cast(int) mp3dec_ex_read(_mp3DecoderNew, outData, samplesNeeded);
545                     if (result < 0) // error
546                     {
547                         setError(kErrorDecodingError.ptr);
548                         return 0;
549                     }
550                     return result / _numChannels;
551                 }
552                 else
553                 {
554                     assert(false); // Impossible
555                 }
556             }
557             case AudioFileFormat.wav:
558                 version(decodeWAV)
559                 {
560                     assert(_wavDecoder !is null);
561                     bool err;
562                     int readFrames = _wavDecoder.readSamples!float(outData, frames, &err); 
563                     if (err)
564                     {
565                         setError(kErrorDecodingError.ptr);
566                         return 0;
567                     }
568                     else
569                         return readFrames;
570                 }
571                 else
572                 {
573                     assert(false); // Impossible
574                 }
575 
576             case AudioFileFormat.qoa:
577                 version(decodeQOA)
578                 {
579                     bool err;
580                     int readFrames = _qoaDecoder.readSamples!float(outData, frames, &err); 
581                     if (err)
582                     {
583                         setError(kErrorDecodingError.ptr);
584                         return 0;
585                     }
586                     else
587                         return readFrames;
588                 }
589                 else
590                 {
591                     assert(false);
592                 }
593 
594 
595             case AudioFileFormat.xm:
596                 version(decodeXM)
597                 {
598                     assert(_xmDecoder !is null);
599 
600                     if (xm_get_loop_count(_xmDecoder) >= 1)
601                         return 0; // song is finished
602 
603                     xm_generate_samples(_xmDecoder, outData, frames);
604                     return frames; // Note: XM decoder pads end with zeroes.
605                 }
606                 else
607                 {
608                     assert(false); // Impossible
609                 }
610 
611             case AudioFileFormat.mod:
612                 version(decodeMOD)
613                 {
614                     if (pocketmod_loop_count(_modDecoder) >= 1)
615                         return 0; // end stream after MOD finishes, looping not supported
616                     assert(_modDecoder !is null);
617                     int bytesReturned = pocketmod_render(_modDecoder, outData, frames * 2 * 4);
618                     assert((bytesReturned % 8) == 0);
619                     return bytesReturned / 8;
620                 }
621                 else
622                 {
623                     assert(false); // Impossible
624                 }
625 
626             case AudioFileFormat.unknown:
627                 // One shouldn't ever get there, since in this case
628                 // opening has failed.
629                 assert(false);
630         }
631     }
632     ///ditto
633     int readSamplesFloat(float[] outData) nothrow @nogc
634     {
635         assert( (outData.length % _numChannels) == 0);
636         return readSamplesFloat(outData.ptr, cast(int)(outData.length / _numChannels) );
637     }
638 
639     /// Read interleaved double samples in the given buffer `outData`.
640     /// 
641     /// Params:
642     ///     outData Buffer where to put decoded samples. Samples are arranged in an interleaved fashion.
643     ///             Must have room for `frames` x `getNumChannels()` samples.
644     ///             For a stereo file, the output data will contain LRLRLR... repeated `result` times.
645     ///
646     ///     frames The number of multichannel frames to be read. 
647     ///            A frame is `getNumChannels()` samples.
648     ///
649     /// Note: the only formats to possibly take advantage of double decoding are WAV and FLAC.
650     ///
651     /// Returns: Number of actually read frames. Multiply by `getNumChannels()` to get the number of read samples.
652     ///          When that number is less than `frames`, it means the stream is done decoding, or that there was a decoding error.
653     ///          If there was an error, `isError()` is set. Do not call decoding again in that case.
654     ///
655     /// TODO: once this returned less than `frames`, are we guaranteed we can keep calling that and it returns 0?
656     int readSamplesDouble(double* outData, int frames) nothrow @nogc
657     {
658         assert(isOpenForReading());
659 
660         switch(_format)
661         {
662             case AudioFileFormat.wav:
663                 version(decodeWAV)
664                 {
665                     assert(_wavDecoder !is null);
666                     bool err;
667                     int readFrames = _wavDecoder.readSamples!double(outData, frames, &err); 
668                     if (err)
669                     {
670                         setError(kErrorDecodingError.ptr);
671                         return 0;
672                     }
673                     return readFrames;
674                 }
675                 else
676                 {
677                     assert(false); // Impossible
678                 }
679 
680            case AudioFileFormat.qoa:
681                 version(decodeQOA)
682                 {
683                     bool err;
684                     int readFrames = _qoaDecoder.readSamples!double(outData, frames, &err); 
685                     if (err)
686                     {
687                         setError(kErrorDecodingError.ptr);
688                         return 0;
689                     }
690                     else
691                         return readFrames;
692                 }
693                 else
694                 {
695                     assert(false);
696                 }
697 
698             case AudioFileFormat.flac:
699             {
700                 version(decodeFLAC)
701                 {
702                     assert(_flacDecoder !is null);
703 
704                     if (_flacPositionFrame == _lengthInFrames)
705                         return 0; // internally the decoder might be elsewhere
706 
707                     // use second half of the output buffer as temporary integer decoding area
708                     int* integerData = (cast(int*)outData) + frames;
709                     int samples = cast(int) drflac_read_s32(_flacDecoder, frames, integerData);
710 
711                     // "Samples are always output as interleaved signed 32-bit PCM."
712                     // Converting to double doesn't loose mantissa, unlike float.
713                     double factor = 1.0 / int.max;
714                     foreach(n; 0..samples)
715                     {
716                         outData[n] = integerData[n]  * factor;
717                     }
718                     int framesDecoded = samples / _numChannels;
719                     _flacPositionFrame += framesDecoded;
720                     return framesDecoded;
721                 }
722                 else
723                 {
724                     assert(false); // Impossible
725                 }
726             }
727 
728             case AudioFileFormat.unknown:
729                 // One shouldn't ever get there
730                 assert(false);
731 
732             default:
733                 // Decode to float buffer, and then convert
734                 if (_floatDecodeBuf.length < frames * _numChannels)
735                     _floatDecodeBuf.reallocBuffer(frames * _numChannels);
736                 int read = readSamplesFloat(_floatDecodeBuf.ptr, frames);
737                 for (int n = 0; n < read * _numChannels; ++n)
738                     outData[n] = _floatDecodeBuf[n];
739                 return read;
740         }
741     }
742     ///ditto
743     int readSamplesDouble(double[] outData) nothrow @nogc
744     {
745         assert( (outData.length % _numChannels) == 0);
746         return readSamplesDouble(outData.ptr, cast(int)(outData.length / _numChannels) );
747     }
748 
749     /// Write interleaved float samples to the stream, from the given buffer `inData[0..frames]`.
750     /// 
751     /// Params:
752     ///     inData Buffer of interleaved samples to append to the stream.
753     ///            Must contain `frames` x `getNumChannels()` samples.
754     ///            For a stereo file, `inData` contains LRLRLR... repeated `frames` times.
755     ///
756     ///     frames The number of frames to append to the stream.
757     ///            A frame is `getNumChannels()` samples.
758     ///
759     /// Returns: Number of actually written frames. Multiply by `getNumChannels()` to get the number of written samples.
760     ///          When that number is less than `frames`, it means the stream had a write error.
761     ///          In that case, the `isError()` flag is also set.
762     int writeSamplesFloat(const(float)* inData, int frames) nothrow @nogc
763     {
764         assert(_io && _io.write !is null);
765 
766         final switch(_format)
767         {
768             case AudioFileFormat.mp3:
769             case AudioFileFormat.flac:
770             case AudioFileFormat.ogg:
771             case AudioFileFormat.opus:
772             case AudioFileFormat.mod:
773             case AudioFileFormat.xm:
774             case AudioFileFormat.unknown:
775             {
776                 assert(false); // Shouldn't have arrived here, such encoding aren't supported.
777             }
778             case AudioFileFormat.qoa:
779             {
780                 version(encodeQOA)
781                 {
782                     bool err;
783                     int writtenFrames = _qoaEncoder.writeSamples!float(inData, frames, &err);
784                     if (err)
785                     {
786                         setError(kErrorEncodingError.ptr);
787                         return 0;
788                     }
789                     return writtenFrames;
790                 }
791                 else
792                 {
793                     assert(false, "no support for WAV encoding");
794                 }
795             }
796             case AudioFileFormat.wav:
797             {
798                 version(encodeWAV)
799                 {
800                     bool err;
801                     int writtenFrames = _wavEncoder.writeSamples(inData, frames, &err);
802                     if (err)
803                     {
804                         setError(kErrorEncodingError.ptr);
805                         return 0;
806                     }
807                     return writtenFrames;
808                 }
809                 else
810                 {
811                     assert(false, "no support for WAV encoding");
812                 }
813             }
814         }
815     }
816     ///ditto
817     int writeSamplesFloat(const(float)[] inData) nothrow @nogc
818     {
819         assert( (inData.length % _numChannels) == 0);
820         return writeSamplesFloat(inData.ptr, cast(int)(inData.length / _numChannels));
821     }
822 
823     /// Write interleaved double samples to the stream, from the given buffer `inData[0..frames]`.
824     /// 
825     /// Params:
826     ///     inData Buffer of interleaved samples to append to the stream.
827     ///            Must contain `frames` x `getNumChannels()` samples.
828     ///            For a stereo file, `inData` contains LRLRLR... repeated `frames` times.
829     ///
830     ///     frames The number of frames to append to the stream.
831     ///            A frame is `getNumChannels()` samples.
832     ///
833     /// Note: this only does something if the output format is WAV and was setup for 64-bit output.
834     ///
835     /// Returns: Number of actually written frames. Multiply by `getNumChannels()` to get the number of written samples.
836     ///          When that number is less than `frames`, it means the stream had a write error.
837     ///          In that case, the `isError()` flag is also set.
838     int writeSamplesDouble(const(double)* inData, int frames) nothrow @nogc
839     {
840         assert (_io && _io.write !is null);
841 
842         switch (_format)
843         {
844             case AudioFileFormat.unknown:
845                 // One shouldn't ever get there
846                 assert(false);
847 
848             case AudioFileFormat.qoa:
849                 {
850                     version(encodeQOA)
851                     {
852                         bool err;
853                         int writtenFrames = _qoaEncoder.writeSamples!double(inData, frames, &err);
854                         if (err)
855                         {
856                             setError(kErrorEncodingError.ptr);
857                             return 0;
858                         }
859                         return writtenFrames;
860                     }
861                     else
862                     {
863                         assert(false);
864                     }
865                 }
866 
867             case AudioFileFormat.wav:
868                 {
869                     version(encodeWAV)
870                     {
871                         bool err;
872                         int writtenFrames = _wavEncoder.writeSamples(inData, frames, &err);
873                         if (err)
874                         {
875                             setError(kErrorEncodingError.ptr);
876                             return 0;
877                         }
878                         return writtenFrames;
879                     }
880                     else
881                     {
882                         assert(false);
883                     }
884                 }
885 
886             default:
887                 // Convert to float buffer, and then convert
888                 if (_floatDecodeBuf.length < frames * _numChannels)
889                     _floatDecodeBuf.reallocBuffer(frames * _numChannels);
890 
891                 for (int n = 0; n < frames * _numChannels; ++n)
892                     _floatDecodeBuf[n] = inData[n];
893                
894                 return writeSamplesFloat(_floatDecodeBuf.ptr, frames);
895         }
896     }
897     ///ditto
898     int writeSamplesDouble(const(double)[] inData) nothrow @nogc
899     {
900         assert( (inData.length % _numChannels) == 0);
901         return writeSamplesDouble(inData.ptr, cast(int)(inData.length / _numChannels));
902     }
903 
904     // -----------------------------------------------------------------------------------------------------
905     // <module functions>
906     // Those tracker module-specific functions below can only be called when `isModule()` returns `true`.
907     // Additionally, seeking function can only be called if `canSeek()` also returns `true`.
908     // -----------------------------------------------------------------------------------------------------
909 
910     /// Length. Returns the amount of patterns in the module
911     /// Formats that support this: MOD, XM.
912     int countModulePatterns() nothrow
913     {
914         assert(isOpenForReading() && isModule());
915         final switch(_format) with (AudioFileFormat)
916         {
917             case mp3: 
918             case flac:
919             case ogg:
920             case opus:
921             case wav:
922             case qoa:
923             case unknown:
924                 assert(false);
925             case mod:
926                 return _modDecoder.num_patterns;
927             case xm:
928                 return xm_get_number_of_patterns(_xmDecoder);
929         }
930     }
931 
932     /// Length. Returns the amount of PLAYED patterns in the module
933     /// Formats that support this: MOD, XM.
934     int getModuleLength() nothrow
935     {
936         assert(isOpenForReading() && isModule());
937         final switch(_format) with (AudioFileFormat)
938         {
939             case mp3: 
940             case flac:
941             case ogg:
942             case opus:
943             case wav:
944             case qoa:
945             case unknown:
946                 assert(false);
947             case mod:
948                 return _modDecoder.length;
949             case xm:
950                 return xm_get_module_length(_xmDecoder);
951         }
952     }
953 
954     /// Tell. Returns amount of rows in a pattern.
955     /// Formats that support this: MOD, XM.
956     /// Returns: -1 on error. Else, number of patterns.
957     int rowsInPattern(int pattern) nothrow
958     {
959         assert(isOpenForReading() && isModule());
960         final switch(_format) with (AudioFileFormat)
961         {
962             case mp3: 
963             case flac:
964             case ogg:
965             case opus:
966             case wav:
967             case qoa:
968             case unknown:
969                 assert(false);
970 
971             case mod:
972                 // According to http://lclevy.free.fr/mo3/mod.txt
973                 // there's 64 lines (aka rows) per pattern.
974                 // TODO: error checking, make sure no out of bounds happens.
975                 return 64;
976 
977             case xm:
978             {
979                 int numPatterns = xm_get_number_of_patterns(_xmDecoder);
980                 if (pattern < 0 || pattern >= numPatterns)
981                     return -1;
982 
983                 return xm_get_number_of_rows(_xmDecoder, cast(ushort) pattern);
984             }
985         }
986     }
987 
988     /// Tell. Returns the current playing pattern id
989     /// Formats that support this: MOD, XM
990     int tellModulePattern() nothrow
991     {
992         assert(isOpenForReading() && isModule());
993         final switch(_format) with (AudioFileFormat)
994         {
995             case mp3: 
996             case flac:
997             case ogg:
998             case opus:
999             case wav:
1000             case qoa:
1001             case unknown:
1002                 assert(false);
1003             case mod:
1004                 return _modDecoder.pattern;
1005             case xm:
1006                 return _xmDecoder.current_table_index;
1007         }
1008     }
1009 
1010     /// Tell. Returns the current playing row id
1011     /// Formats that support this: MOD, XM
1012     int tellModuleRow() nothrow
1013     {
1014         assert(isOpenForReading() && isModule());
1015         final switch(_format) with (AudioFileFormat)
1016         {
1017             case mp3: 
1018             case flac:
1019             case ogg:
1020             case opus:
1021             case wav:
1022             case qoa:
1023             case unknown:
1024                 assert(false);
1025             case mod:
1026                 return _modDecoder.line;
1027             case xm:
1028                 return _xmDecoder.current_row;
1029         }
1030     }
1031 
1032     /// Playback info. Returns the amount of multi-channel frames remaining in the current playing pattern.
1033     /// Formats that support this: MOD
1034     int framesRemainingInPattern() nothrow
1035     {
1036         assert(isOpenForReading() && isModule());
1037         final switch(_format) with (AudioFileFormat)
1038         {
1039             case mp3: 
1040             case flac:
1041             case ogg:
1042             case opus:
1043             case wav:
1044             case qoa:
1045             case unknown:
1046                 assert(false);
1047 
1048             case mod:
1049                 return pocketmod_count_remaining_samples(_modDecoder);
1050             case xm:
1051                 return xm_count_remaining_samples(_xmDecoder);
1052         }
1053     }
1054 
1055     /// Seeking. Subsequent reads start from pattern + row, 0 index
1056     /// Only available for input streams.
1057     /// Formats that support seeking per pattern/row: MOD, XM
1058     /// Returns: `true` in case of success.
1059     bool seekPosition(int pattern, int row) nothrow
1060     {
1061         assert(isOpenForReading() && isModule() && canSeek());
1062         final switch(_format) with (AudioFileFormat)
1063         {
1064             case mp3: 
1065             case flac:
1066             case ogg:
1067             case opus:
1068             case wav:
1069             case qoa:
1070             case unknown:
1071                 assert(false);
1072 
1073             case mod:
1074                 // NOTE: This is untested.
1075                 return pocketmod_seek(_modDecoder, pattern, row, 0);
1076 
1077             case xm:
1078                 return xm_seek(_xmDecoder, pattern, row, 0);
1079         }
1080     }
1081 
1082     // -----------------------------------------------------------------------------------------------------
1083     // </module functions>
1084     // -----------------------------------------------------------------------------------------------------
1085 
1086     // -----------------------------------------------------------------------------------------------------
1087     // <non-module functions>
1088     // Those functions below can't be used for tracker module formats, because there is no real concept of 
1089     // absolute position in these formats.
1090     // -----------------------------------------------------------------------------------------------------
1091 
1092     /// Seeking. Subsequent reads start from multi-channel frame index `frames`.
1093     /// Only available for input streams, for streams whose `canSeek()` returns `true`.
1094     /// Warning: `seekPosition(lengthInFrames)` is Undefined Behaviour for now. (it works in MP3).
1095     bool seekPosition(int frame)
1096     {
1097         assert(isOpenForReading() && !isModule() && canSeek()); // seeking doesn't have the same sense with modules.
1098         final switch(_format) with (AudioFileFormat)
1099         {
1100             case mp3: 
1101                 version(decodeMP3)
1102                 {
1103                     assert(_lengthInFrames != audiostreamUnknownLength);
1104                     if (frame < 0 || frame > _lengthInFrames)
1105                         return false;
1106                     return (mp3dec_ex_seek(_mp3DecoderNew, frame * _numChannels) == 0);
1107                 }
1108                 else
1109                     assert(false);
1110             case flac:
1111                 version(decodeFLAC)
1112                 {
1113                     if (frame < 0 || frame > _lengthInFrames)
1114                         return false;
1115                     if (_flacPositionFrame == frame)
1116                         return true;
1117 
1118                     // Note: seeking + FLAC is a dark side of that library. 
1119                     // I'm not entirely sure we are handling all cases perfectly.
1120                     // But weren't able to fault the current situation.
1121                     // Would probably be easier to re-tanslate drflac if a problem arised.
1122 
1123                     bool success = drflac_seek_to_sample(_flacDecoder, frame * _numChannels);
1124                     if (success || frame == _lengthInFrames) // always succeed if end of stream is requested
1125                         _flacPositionFrame = frame;
1126                     return success;
1127                 }
1128                 else
1129                     assert(false);
1130 
1131             case qoa:
1132             {
1133                 version(decodeQOA)
1134                 {
1135                     if (frame < 0 || frame > _lengthInFrames)
1136                         return false;
1137                     return _qoaDecoder.seekPosition(frame);
1138                 }
1139                 else
1140                     assert(false);
1141             }
1142 
1143             case ogg:
1144                 version(decodeOGG)
1145                 {
1146                     if (_oggPositionFrame == frame)
1147                         return true;
1148 
1149                     if (_oggPositionFrame == _lengthInFrames)
1150                     {
1151                         // When the OGG stream is finished, and an earlier position is detected, 
1152                         // the OGG decoder has to be restarted
1153                         assert(_oggHandle !is null);
1154                         cleanUpCodecs();
1155                         assert(_oggHandle is null);
1156                         startDecoding();
1157                         assert(_oggHandle !is null);
1158                     }
1159 
1160                     if (stb_vorbis_seek(_oggHandle, frame) == 1)
1161                     {
1162                         _oggPositionFrame = frame;
1163                         return true;
1164                     }
1165                     else
1166                       return false;
1167                 }
1168                 else 
1169                     assert(false);
1170             case opus:
1171                 version(decodeOPUS)
1172                 {
1173                     if (frame < 0 || frame > _lengthInFrames)
1174                         return false;
1175 
1176                     bool err;
1177                     long where = _opusDecoder.ogg.seekPCM(frame, &err);
1178                     if (err)
1179                         return false;
1180 
1181                     _opusPositionFrame = where;
1182                     int toSkip = cast(int)(frame - where);
1183 
1184                     // skip remaining samples for sample-accurate seeking
1185                     // Note: this also updates _opusPositionFrame
1186                     int skipped = readSamplesFloat(null, cast(int) toSkip);
1187                     // TODO: if decoding `toSkip` samples failed, restore previous state?
1188                     return skipped == toSkip;
1189                 }
1190                 else 
1191                     assert(false);
1192 
1193             case mod:
1194             case xm:
1195                 assert(false);
1196 
1197             case wav:
1198                 version(decodeWAV)
1199                     return _wavDecoder.seekPosition(frame);
1200                 else
1201                     assert(false);
1202             case unknown:
1203                 assert(false);
1204 
1205         }
1206     }
1207 
1208     /// Tell. Returns the current position in multichannel frames. -1 on error.
1209     int tellPosition()
1210     {
1211         assert(isOpenForReading() && !isModule() && canSeek()); // seeking doesn't have the same meaning with modules.
1212         final switch(_format) with (AudioFileFormat)
1213         {
1214             case mp3: 
1215                 version(decodeMP3)
1216                 {
1217                     return cast(int) _mp3DecoderNew.cur_sample / _numChannels;
1218                 }
1219                 else
1220                     assert(false);
1221             case flac:
1222                 version(decodeFLAC)
1223                 {
1224                     // Implemented externally since drflac is impenetrable.
1225                     return cast(int) _flacPositionFrame;
1226                 }
1227                 else
1228                     assert(false);
1229             case ogg:
1230                 version(decodeOGG)
1231                     return cast(int) _oggPositionFrame;
1232                 else 
1233                     assert(false);
1234 
1235             case qoa:
1236                 version(decodeQOA)
1237                     return _qoaDecoder.tellPosition();
1238                 else
1239                     assert(false);
1240 
1241             case opus:
1242                 version(decodeOPUS)
1243                 {
1244                     return cast(int) _opusPositionFrame; // implemented externally
1245                 }
1246                 else 
1247                     assert(false);
1248 
1249             case wav:
1250                 version(decodeWAV)
1251                     return _wavDecoder.tellPosition();
1252                 else
1253                     assert(false);
1254 
1255             case mod:
1256             case xm:
1257             case unknown:
1258                 assert(false);
1259 
1260         }
1261     }
1262 
1263 
1264     // -----------------------------------------------------------------------------------------------------
1265     // </non-module functions>
1266     // -----------------------------------------------------------------------------------------------------
1267 
1268     /// Call `fflush()` on written samples, if any. 
1269     /// It is only useful for streamable output formats, that may want to flush things to disk.
1270     void flush() nothrow @nogc
1271     {
1272         assert( _io && (_io.write !is null) );
1273         bool success = _io.flush(userData);
1274         if (!success)
1275             setError(kErrorFlushFailed.ptr);
1276     }
1277     
1278     /// Finalize encoding. After finalization, further writes are not possible anymore
1279     /// however the stream is considered complete and valid for storage.
1280     /// Returns: `true` in case of success. `false` in case of I/O error.
1281     ///          This also sets the `isError` flag in this case.
1282     bool finalizeEncoding() nothrow @nogc 
1283     {
1284         // If you crash here, it's because `finalizeEncoding` has been called twice.
1285         assert(isOpenForWriting());
1286 
1287         final switch(_format) with (AudioFileFormat)
1288         {
1289             case mp3:
1290             case flac:
1291             case ogg:
1292             case opus:
1293             case mod:
1294             case xm:
1295                 assert(false);
1296 
1297             case qoa:
1298                 { 
1299                     version(encodeQOA)
1300                     {
1301                         bool success = _qoaEncoder.finalizeEncoding();
1302                         if (!success)
1303                         {
1304                             setError(kErrorEncodingError.ptr);
1305                             return false;
1306                         }
1307                         break;
1308                     }
1309                     else
1310                         assert(false);
1311                 }
1312 
1313             case wav:
1314                 { 
1315                     version(encodeWAV)
1316                     {
1317                         assert(_wavEncoder !is null);
1318                         bool err;
1319                         _wavEncoder.finalizeEncoding(&err);
1320                         if (err)
1321                         {
1322                             setError(kErrorEncodingError.ptr);
1323                             return false;
1324                         }
1325                         break;
1326                     }
1327                     else
1328                         assert(false);
1329                 }
1330             case unknown:
1331                 assert(false);
1332         }
1333         _io.write = null; // prevents further encodings
1334         return true;
1335     }
1336 
1337     /// Finalize encoding and get internal buffer.
1338     /// This can be called multiple times, in which cases the stream is finalized only the first time.
1339     /// Returns: `null` in case of error (also isError flag), else an array of bytes.
1340     const(ubyte)[] finalizeAndGetEncodedResult() @nogc
1341     {
1342         // only callable while appending, else it's a programming error
1343         assert( (memoryContext !is null) && ( memoryContext.bufferCanGrow ) );
1344 
1345         if (!finalizeEncodingIfNeeded())
1346             return null;
1347 
1348         return memoryContext.buffer[0..memoryContext.size];
1349     }
1350 
1351     /// Finalize encoding and get internal buffer, which is disowned by the `AudioStream`.
1352     /// The caller has to call `freeEncodedAudio` manually.
1353     /// This can be called exactly one time, if a growable owned buffer was used.
1354     /// Returns: `null` in case of error (also isError flag), else an array of bytes.
1355     const(ubyte)[] finalizeAndGetEncodedResultDisown() @nogc
1356     {
1357         const(ubyte)[] buf = finalizeAndGetEncodedResult();
1358         memoryContext.disownBuffer();
1359         return buf;
1360     }
1361 
1362 private:
1363     IOCallbacks* _io;
1364 
1365     // This type of context is a closure to remember where the data is.
1366     void* userData; // is equal to either fileContext or memoryContext
1367     FileContext* fileContext;
1368     MemoryContext* memoryContext;
1369 
1370     // This type of context is a closure to remember where _io and user Data is.
1371     DecoderContext* _decoderContext;
1372 
1373     AudioFileFormat _format;
1374     float _sampleRate; 
1375     int _numChannels;
1376     long _lengthInFrames;
1377 
1378     // Start life as errored.
1379     immutable(char)* _error = "Stream not initialized".ptr; // Using a constant would crash LDC
1380 
1381     float[] _floatDecodeBuf;
1382 
1383     // Decoders
1384     version(decodeMP3)
1385     {
1386         mp3dec_ex_t* _mp3DecoderNew; // allocated on heap since it's a 16kb object
1387         mp3dec_io_t* _mp3io;
1388     }
1389     version(decodeFLAC)
1390     {
1391         drflac* _flacDecoder;
1392         long _flacPositionFrame;
1393     }
1394     version(decodeOGG)
1395     {
1396         ubyte[] _oggBuffer; // all allocations from the ogg decoder
1397         stb_vorbis* _oggHandle;
1398         long _oggPositionFrame;
1399     }
1400     version(decodeWAV)
1401     {
1402         WAVDecoder _wavDecoder;
1403     }
1404     version(decodeQOA)
1405     {
1406         QOADecoder _qoaDecoder;
1407     }
1408     version(encodeQOA)
1409     {
1410         QOAEncoder _qoaEncoder;
1411     }
1412     version(decodeMOD)
1413     {
1414         pocketmod_context* _modDecoder = null;
1415         ubyte[] _modContent = null; // whole buffer, copied
1416     }
1417     version(decodeXM)
1418     {
1419         xm_context_t* _xmDecoder = null;
1420         ubyte* _xmContent = null;
1421     }
1422 
1423     version(decodeOPUS)
1424     {
1425         OpusFile _opusDecoder;
1426         short[] _opusBuffer;
1427         long _opusPositionFrame;
1428     }
1429 
1430     // Encoder
1431     version(encodeWAV)
1432     {
1433         WAVEncoder _wavEncoder;
1434     }
1435 
1436     // Clean-up encoder/decoder-related data, but not I/O related things. Useful to restart the decoder.
1437     // After callign that, you can call `startDecoder` again.
1438     void cleanUpCodecs() nothrow @nogc
1439     {
1440         // Write the last needed bytes if needed
1441         finalizeEncodingIfNeeded();
1442 
1443         version(decodeMP3)
1444         {
1445             if (_mp3DecoderNew !is null)
1446             {
1447                 mp3dec_ex_close(_mp3DecoderNew);
1448                 free(_mp3DecoderNew);
1449                 _mp3DecoderNew = null;
1450             }
1451             if (_mp3io !is null)
1452             {
1453                 free(_mp3io);
1454                 _mp3io = null;
1455             }
1456         }
1457 
1458         version(decodeFLAC)
1459         {
1460             if (_flacDecoder !is null)
1461             {
1462                 drflac_close(_flacDecoder);
1463                 _flacDecoder = null;
1464                 _flacPositionFrame = 0;
1465             }
1466         }
1467 
1468         version(decodeOGG)
1469         {
1470             if (_oggHandle !is null)
1471             {
1472                 stb_vorbis_close(_oggHandle);
1473                 _oggHandle = null;
1474                 _oggPositionFrame = 0;
1475             }
1476             _oggBuffer.reallocBuffer(0);
1477         }
1478 
1479         version(decodeOPUS)
1480         {
1481             if (_opusDecoder !is null)
1482             {
1483                 opusClose(_opusDecoder);
1484                 _opusDecoder = null;
1485             }
1486             _opusBuffer = null;
1487         }
1488 
1489         version(decodeWAV)
1490         {
1491             if (_wavDecoder !is null)
1492             {
1493                 destroyFree(_wavDecoder);
1494                 _wavDecoder = null;
1495             }
1496         }
1497 
1498         version(decodeXM)
1499         {
1500             if (_xmDecoder !is null)
1501             {
1502                 xm_free_context(_xmDecoder);
1503                 _xmDecoder = null;
1504             }
1505             if (_xmContent != null)
1506             {
1507                 free(_xmContent);
1508                 _xmContent = null;
1509             }
1510         }
1511 
1512         version(decodeMOD)
1513         {
1514             if (_modDecoder !is null)
1515             {
1516                 free(_modDecoder);
1517                 _modDecoder = null;
1518                 _modContent.reallocBuffer(0);
1519             }
1520         }
1521 
1522         version(encodeWAV)
1523         {
1524             if (_wavEncoder !is null)
1525             {
1526                 destroyFree(_wavEncoder);
1527                 _wavEncoder = null;
1528             }
1529         }
1530     }
1531 
1532     // Set a zero-terminated error string. Object is now in isError state, refusing to do things 
1533     // until re-initialized.
1534     void setError(immutable(char)* messageZ) nothrow @nogc
1535     {
1536         _error = messageZ;
1537     }
1538 
1539     // Sets the stream as error-free. Called by initialization.
1540     void clearErrorStatus()
1541     {
1542         _error = null;
1543     }
1544 
1545     // clean-up the whole Stream object so that it can be reused for anything else.
1546     void cleanUp() nothrow @nogc
1547     {
1548         cleanUpCodecs();
1549 
1550         if (_decoderContext)
1551         {
1552             destroyFree(_decoderContext);
1553             _decoderContext = null;
1554         }
1555 
1556         if (fileContext !is null)
1557         {
1558             if (fileContext.file !is null)
1559             {
1560                 int result = fclose(fileContext.file);
1561 
1562                 // Note: perennial error of "what to do if fclose failed".
1563                 // In C++ a destructor that throw is a crash.
1564                 // C++ fstream sets the fail bit, but doesn't crash neither throw.
1565                 // I guess noone checks iostream's failbit after close.
1566                 // Let's do nothing then.
1567             }
1568             destroyFree(fileContext);
1569             fileContext = null;
1570         }
1571 
1572         if (memoryContext !is null)
1573         {
1574             // TODO destroy buffer if any is owned
1575             destroyFree(memoryContext);
1576             memoryContext = null;
1577         }
1578 
1579         if (_io !is null)
1580         {
1581             destroyFree(_io);
1582             _io = null;
1583         }
1584     }
1585 
1586     void startDecoding() @nogc
1587     {
1588         // Create a decoder context
1589         if ( _decoderContext is null)
1590         {
1591             _decoderContext = mallocNew!DecoderContext;
1592             _decoderContext.userDataIO = userData;
1593             _decoderContext.callbacks = _io;
1594         }
1595 
1596         version(decodeOPUS)
1597         {
1598             bool err;
1599             _opusDecoder = opusOpen(_io, userData, &err);
1600             if (err)
1601             {
1602                 _opusDecoder = null;
1603             }
1604             else
1605             {
1606                 assert(_opusDecoder !is null);
1607                 _format = AudioFileFormat.opus;
1608                 _sampleRate = _opusDecoder.rate; // Note: Opus file are always 48Khz
1609                 _numChannels = _opusDecoder.channels();
1610                 _lengthInFrames = _opusDecoder.smpduration();
1611                 _opusPositionFrame = 0;
1612                 return;
1613             }
1614         }
1615 
1616         version(decodeFLAC)
1617         {
1618             _io.seek(0, false, userData);
1619             
1620             // Is it a FLAC?
1621             {
1622                 drflac_read_proc onRead = &flac_read;
1623                 drflac_seek_proc onSeek = &flac_seek;
1624                 void* pUserData = _decoderContext;
1625                 _flacDecoder = drflac_open (onRead, onSeek, _decoderContext);
1626                 if (_flacDecoder !is null)
1627                 {
1628                     _format = AudioFileFormat.flac;
1629                     _sampleRate = _flacDecoder.sampleRate;
1630                     _numChannels = _flacDecoder.channels;
1631                     _lengthInFrames = _flacDecoder.totalSampleCount / _numChannels;
1632                     _flacPositionFrame = 0;
1633                     return;
1634                 }
1635             }
1636         }
1637 
1638         version(decodeWAV)
1639         {
1640             // Check if it's a WAV.
1641 
1642             _io.seek(0, false, userData);
1643             _wavDecoder = mallocNew!WAVDecoder(_io, userData);
1644             if(_wavDecoder.scan() == WAVDecoder.WAVError.none)
1645             {
1646                 // WAV detected
1647                 _format = AudioFileFormat.wav;
1648                 _sampleRate = _wavDecoder._sampleRate;
1649                 _numChannels = _wavDecoder._channels;
1650                 _lengthInFrames = _wavDecoder._lengthInFrames;
1651                 return;
1652             }
1653             destroyFree(_wavDecoder);
1654             _wavDecoder = null;
1655         }
1656 
1657         version(decodeQOA)
1658         {
1659             // Check if it's a QOA.
1660             _io.seek(0, false, userData);
1661             
1662             if (_qoaDecoder.initialize(_io, userData))
1663             {
1664                 _format = AudioFileFormat.qoa;
1665                 _sampleRate = _qoaDecoder.samplerate;  // Note: overflow possible on cast from uint to int
1666                 _numChannels = _qoaDecoder.numChannels;   // Note: overflow possible on cast
1667                 _lengthInFrames = _qoaDecoder.totalFrames; // Note: overflow possible on cast
1668                 return;
1669             }
1670         }
1671 
1672         version(decodeOGG)
1673         {
1674             _io.seek(0, false, userData);
1675             
1676             // Is it an OGG?
1677             {
1678                 //"In my test files the maximal-size usage is ~150KB", so let's take a bit more
1679                 //
1680                 // Issue #28 actually taking even more than that for Q10 OGG encodes.
1681                 // This new threshold supports all streams encoded with OGG and Audacity, but not 
1682                 // sure of correctness in absolute terms.
1683                 _oggBuffer.reallocBuffer(220 * 1024);
1684                 stb_vorbis_alloc alloc;
1685                 alloc.alloc_buffer = cast(ubyte*)(_oggBuffer.ptr);
1686                 alloc.alloc_buffer_length_in_bytes = cast(int)(_oggBuffer.length);
1687 
1688                 int error;
1689 
1690                 _oggHandle = stb_vorbis_open_file(_io, userData, &error, &alloc);
1691                 if (error == VORBIS__no_error)
1692                 {
1693                     _format = AudioFileFormat.ogg;
1694                     _sampleRate = _oggHandle.sample_rate;
1695                     _numChannels = _oggHandle.channels;
1696                     _lengthInFrames = stb_vorbis_stream_length_in_samples(_oggHandle);
1697                     return;
1698                 }
1699                 else
1700                 {
1701                     _oggHandle = null;
1702                 }
1703             }
1704         }
1705 
1706         version(decodeMP3)
1707         {
1708             // Check if it's a MP3.
1709             {
1710                 _io.seek(0, false, userData);
1711 
1712                 ubyte* scratchBuffer = cast(ubyte*) malloc(MINIMP3_BUF_SIZE*2);
1713                 scope(exit) free(scratchBuffer);
1714 
1715                 _mp3io = cast(mp3dec_io_t*) malloc(mp3dec_io_t.sizeof);
1716                 _mp3io.read      = &mp3_io_read;
1717                 _mp3io.read_data = _decoderContext;
1718                 _mp3io.seek      = &mp3_io_seek;
1719                 _mp3io.seek_data = _decoderContext;
1720 
1721                 if ( mp3dec_detect_cb(_mp3io, scratchBuffer, MINIMP3_BUF_SIZE*2) == 0 )
1722                 {
1723                     // This is a MP3. Attempt to open a stream.
1724 
1725                     // Allocate a mp3dec_ex_t object
1726                     _mp3DecoderNew = cast(mp3dec_ex_t*) malloc(mp3dec_ex_t.sizeof);
1727 
1728                     int result = mp3dec_ex_open_cb(_mp3DecoderNew, _mp3io, MP3D_SEEK_TO_SAMPLE);
1729 
1730                     if (0 == result)
1731                     {
1732                         // MP3 detected
1733                         // but it seems we need to iterate all frames to know the length...
1734                         _format = AudioFileFormat.mp3;
1735                         _sampleRate = _mp3DecoderNew.info.hz;
1736                         _numChannels = _mp3DecoderNew.info.channels;
1737                         _lengthInFrames = _mp3DecoderNew.samples / _numChannels;
1738                         return;
1739                     }
1740                     else
1741                     {
1742                         free(_mp3DecoderNew);
1743                         _mp3DecoderNew = null;
1744                         free(_mp3io);
1745                         _mp3io = null;
1746                     }
1747                 }
1748             }
1749         }
1750 
1751         version(decodeXM)
1752         {
1753             {
1754                 // we need the first 60 bytes to check if XM
1755                 char[60] xmHeader;
1756                 int bytes;
1757 
1758                 _io.seek(0, false, userData);
1759                 long lenBytes = _io.getFileLength(userData);
1760                 if (lenBytes < 60) 
1761                     goto not_a_xm;
1762 
1763                 bytes = _io.read(xmHeader.ptr, 60, userData);
1764                 if (bytes != 60)
1765                     goto not_a_xm;
1766 
1767                if (0 != xm_check_sanity_preload(xmHeader.ptr, 60))
1768                    goto not_a_xm;
1769 
1770                 _xmContent = cast(ubyte*) malloc(cast(int)lenBytes);
1771                 _io.seek(0, false, userData);
1772                 bytes = _io.read(_xmContent, cast(int)lenBytes, userData);
1773                 if (bytes != cast(int)lenBytes)
1774                     goto not_a_xm;
1775 
1776                 if (0 == xm_create_context_safe(&_xmDecoder, cast(const(char)*)_xmContent, cast(size_t)lenBytes, 44100))
1777                 {
1778                     assert(_xmDecoder !is null);
1779 
1780                     xm_set_max_loop_count(_xmDecoder, 1);
1781 
1782                     _format = AudioFileFormat.xm;
1783                     _sampleRate = 44100.0f;
1784                     _numChannels = 2;
1785                     _lengthInFrames = audiostreamUnknownLength;
1786                     return;
1787                 }
1788 
1789                 not_a_xm:
1790                 assert(_xmDecoder == null);
1791                 free(_xmContent);
1792                 _xmContent = null;
1793             }
1794         } 
1795 
1796         version(decodeMOD)
1797         {
1798             {
1799                 // we need either the first 1084 or 600 bytes if available
1800                 _io.seek(0, false, userData);
1801                 long lenBytes = _io.getFileLength(userData);
1802                 if (lenBytes >= 600)
1803                 {
1804                     int headerBytes = lenBytes > 1084 ? 1084 : cast(int)lenBytes;
1805 
1806                     ubyte[1084] header;
1807                     int bytes = _io.read(header.ptr, headerBytes, userData);
1808 
1809                     if (_pocketmod_ident(null, header.ptr, bytes))
1810                     {
1811                         // This is a MOD, allocate a proper context, and read the whole file.
1812                         _modDecoder = cast(pocketmod_context*) malloc(pocketmod_context.sizeof);
1813 
1814                         // Read whole .mod in a buffer, since the decoder work all from memory
1815                         _io.seek(0, false, userData);
1816                         _modContent.reallocBuffer(cast(size_t)lenBytes);
1817                         bytes = _io.read(_modContent.ptr, cast(int)lenBytes, userData);
1818 
1819                         if (pocketmod_init(_modDecoder, _modContent.ptr, bytes, 44100))
1820                         {
1821                             _format = AudioFileFormat.mod;
1822                             _sampleRate = 44100.0f;
1823                             _numChannels = 2;
1824                             _lengthInFrames = audiostreamUnknownLength;
1825                             return;
1826                         }
1827                     }
1828                 }
1829             }
1830         }
1831 
1832         _format = AudioFileFormat.unknown;
1833         _sampleRate = float.nan;
1834         _numChannels = 0;
1835         _lengthInFrames = -1;
1836 
1837         setError(kErrorUnknownFormat.ptr);
1838     }
1839 
1840     /// Start encoding in a given format, on I/O error set the error flag.
1841     /// After calling this, check `isError`.
1842     void startEncoding(AudioFileFormat format,
1843                        float sampleRate, 
1844                        int numChannels, 
1845                        EncodingOptions options) @nogc
1846     { 
1847         _format = format;
1848         _sampleRate = sampleRate;
1849         _numChannels = numChannels;
1850 
1851         // Note: fractional sample rates not supported by QOA and WAV, signal an integer one
1852         int isampleRate = cast(int)(sampleRate + 0.5f);
1853 
1854         final switch(format) with (AudioFileFormat)
1855         {
1856             case mp3:  
1857             case flac:
1858             case ogg:
1859             case opus:
1860             case mod:
1861             case xm:   
1862                 setError(kErrorUnsupportedEncodingFormat.ptr); 
1863                 break;
1864             case qoa:
1865             {
1866                 version(encodeQOA)
1867                 {
1868                     bool err;
1869                     _qoaEncoder.initialize(_io, userData, isampleRate, numChannels, &err);
1870                     if (err)
1871                         setError(kErrorEncodingError.ptr); 
1872                     break;
1873                 }
1874                 else
1875                 {
1876                     setError(kErrorUnsupportedEncodingFormat.ptr); 
1877                     break;
1878                 }
1879             }
1880             case wav:
1881             {
1882                 version(encodeWAV)
1883                 {
1884                     WAVEncoder.Format wavfmt;
1885                     final switch (options.sampleFormat)
1886                     {
1887                         case AudioSampleFormat.s8:   wavfmt = WAVEncoder.Format.s8; break;
1888                         case AudioSampleFormat.s16:  wavfmt = WAVEncoder.Format.s16le; break;
1889                         case AudioSampleFormat.s24:  wavfmt = WAVEncoder.Format.s24le; break;
1890                         case AudioSampleFormat.fp32: wavfmt = WAVEncoder.Format.fp32le; break;
1891                         case AudioSampleFormat.fp64: wavfmt = WAVEncoder.Format.fp64le; break;
1892                     }
1893                     bool err;
1894                     _wavEncoder = mallocNew!WAVEncoder(_io, userData, isampleRate, numChannels, wavfmt, options.enableDither, &err);
1895                     if (err)
1896                         setError(kErrorEncodingError.ptr); 
1897                     break;
1898                 }
1899                 else
1900                 {
1901                     setError(kErrorUnsupportedEncodingFormat.ptr); 
1902                     break;
1903                 }
1904             }
1905             case unknown:
1906                 setError("Can't encode using 'unknown' coding");
1907                 break;
1908         }
1909     }
1910 
1911     // Finalize, but only if needed.
1912     // Returns: true on success, also use the isError flag to report failure.
1913     bool finalizeEncodingIfNeeded() nothrow @nogc
1914     {
1915         if (_io && (_io.write !is null)) // if we have been encoding something
1916         {
1917             return finalizeEncoding();
1918         }
1919 
1920         if (isError()) // there was an error already, fail.
1921             return false;
1922         else
1923             return true;
1924     }
1925 }
1926 
1927 // AudioStream should be able to go on a smallish 32-bit stack,
1928 // and malloc the rest on the heap when needed.
1929 static assert(AudioStream.sizeof <= 384); 
1930 
1931 private: // not meant to be imported at all
1932 
1933 
1934 
1935 // Internal object for audio-formats
1936 
1937 
1938 // File callbacks
1939 // The file callbacks are using the C stdlib.
1940 
1941 struct FileContext // this is what is passed to I/O when used in file mode
1942 {
1943 nothrow @nogc:
1944     // Used when streaming of writing a file
1945     FILE* file = null;
1946 
1947     // Size of the file in bytes, only used when reading/writing a file.
1948     long fileSize;
1949 
1950     // Initialize this context
1951     void initialize(const(char)[] path, bool forWrite, bool* err) @nogc
1952     {
1953         *err = false;
1954         CString strZ = CString(path);
1955         file = fopen(strZ.storage, forWrite ? "wb".ptr : "rb".ptr);
1956         if (file is null)
1957             *err = true;
1958 
1959         // finds the size of the file
1960         fseek(file, 0, SEEK_END); // TODO check error here
1961         fileSize = ftell(file);
1962         fseek(file, 0, SEEK_SET); // TODO check error here
1963         *err = false;
1964     }
1965 }
1966 
1967 long file_tell(void* userData) nothrow @nogc
1968 {
1969     FileContext* context = cast(FileContext*)userData;
1970     return ftell(context.file);
1971 }
1972 
1973 bool file_seek(long offset, bool relative, void* userData) nothrow @nogc
1974 {
1975     FileContext* context = cast(FileContext*)userData;
1976     assert(offset <= int.max);
1977     int r = fseek(context.file, cast(int)offset, relative ? SEEK_CUR : SEEK_SET); // Limitations: file larger than 2gb not supported
1978     return r == 0;
1979 }
1980 
1981 long file_getFileLength(void* userData) nothrow @nogc
1982 {
1983     FileContext* context = cast(FileContext*)userData;
1984     return context.fileSize;
1985 }
1986 
1987 int file_read(void* outData, int bytes, void* userData) nothrow @nogc
1988 {
1989     FileContext* context = cast(FileContext*)userData;
1990     size_t bytesRead = fread(outData, 1, bytes, context.file);
1991     return cast(int)bytesRead;
1992 }
1993 
1994 int file_write(void* inData, int bytes, void* userData) nothrow @nogc
1995 {
1996     FileContext* context = cast(FileContext*)userData;
1997     size_t bytesWritten = fwrite(inData, 1, bytes, context.file);
1998     return cast(int)bytesWritten;
1999 }
2000 
2001 bool file_skip(int bytes, void* userData) nothrow @nogc
2002 {
2003     FileContext* context = cast(FileContext*)userData;
2004     return (0 == fseek(context.file, bytes, SEEK_CUR));
2005 }
2006 
2007 bool file_flush(void* userData) nothrow @nogc
2008 {
2009     FileContext* context = cast(FileContext*)userData;
2010     return ( fflush(context.file) == 0 );
2011 }
2012 
2013 // Memory read callback
2014 // Using the read buffer instead
2015 
2016 struct MemoryContext
2017 {
2018     bool bufferIsOwned;
2019     bool bufferCanGrow;
2020 
2021     // Buffer
2022     ubyte* buffer = null;
2023 
2024     size_t size;     // current buffer size
2025     size_t cursor;   // where we are in the buffer
2026     size_t capacity; // max buffer size before realloc
2027 
2028     void initializeWithConstantInput(const(ubyte)* data, size_t length) nothrow @nogc
2029     {
2030         // Make a copy of the input buffer, since it could be temporary.
2031         bufferIsOwned = true;
2032         bufferCanGrow = false;
2033 
2034         buffer = mallocDup(data[0..length]).ptr; // Note: the copied slice is made mutable.
2035         size = length;
2036         cursor = 0;
2037         capacity = length;
2038     }
2039 
2040     void initializeWithExternalOutputBuffer(ubyte* data, size_t length) nothrow @nogc
2041     {
2042         bufferIsOwned = false;
2043         bufferCanGrow = false;
2044         buffer = data;
2045         size = 0;
2046         cursor = 0;
2047         capacity = length;
2048     }
2049 
2050     void initializeWithInternalGrowableBuffer() nothrow @nogc
2051     {
2052         bufferIsOwned = true;
2053         bufferCanGrow = true;
2054         buffer = null;
2055         size = 0;
2056         cursor = 0;
2057         capacity = 0;
2058     }
2059 
2060     // caller guarantees the buffer will be freed with `free`.
2061     void disownBuffer() nothrow @nogc
2062     {
2063         assert(bufferIsOwned);
2064         bufferIsOwned = false;
2065         bufferCanGrow = false;
2066     }
2067 
2068     ~this()
2069     {
2070         if (bufferIsOwned)
2071         {
2072             if (buffer !is null)
2073             {
2074                 free(buffer);
2075                 buffer = null;
2076             }
2077         }
2078     }
2079 }
2080 
2081 long memory_tell(void* userData) nothrow @nogc
2082 {
2083     MemoryContext* context = cast(MemoryContext*)userData;
2084     return cast(long)(context.cursor);
2085 }
2086 
2087 bool memory_seek(long offset, bool relative, void* userData) nothrow @nogc
2088 {
2089     MemoryContext* context = cast(MemoryContext*)userData;    
2090     if (relative) offset += context.cursor;
2091     if (offset < 0)
2092         return false;
2093 
2094     bool r = true;
2095     if (offset >= context.size) // can't seek past end of buffer, stick to the end so that read return 0 byte
2096     {
2097         offset = context.size;
2098         r = false;
2099     }
2100     context.cursor = cast(size_t)offset; // Note: memory streams larger than 2gb not supported
2101     return r;
2102 }
2103 
2104 long memory_getFileLength(void* userData) nothrow @nogc
2105 {
2106     MemoryContext* context = cast(MemoryContext*)userData;
2107     return cast(long)(context.size);
2108 }
2109 
2110 int memory_read(void* outData, int bytes, void* userData) nothrow @nogc
2111 {
2112     MemoryContext* context = cast(MemoryContext*)userData;
2113     size_t cursor = context.cursor;
2114     size_t size = context.size;
2115     size_t available = size - cursor;
2116     if (bytes < available)
2117     {
2118         outData[0..bytes] = context.buffer[cursor..cursor + bytes];
2119         context.cursor += bytes;
2120         return bytes;
2121     }
2122     else
2123     {
2124         outData[0..available] = context.buffer[cursor..cursor + available];
2125         context.cursor = context.size;
2126         return cast(int)available;
2127     }
2128 }
2129 
2130 int memory_write_limited(void* inData, int bytes, void* userData) nothrow @nogc
2131 {
2132     MemoryContext* context = cast(MemoryContext*)userData;
2133     size_t cursor = context.cursor;
2134     size_t size = context.size;
2135     size_t available = size - cursor;
2136     ubyte* buffer = context.buffer;
2137     ubyte* source = cast(ubyte*) inData;
2138 
2139     if (cursor + bytes > available)
2140     {
2141         bytes = cast(int)(available - cursor);
2142     }
2143 
2144     buffer[cursor..(cursor + bytes)] = source[0..bytes];
2145     context.cursor += bytes;
2146 
2147     // new size is max(cursor, previous size)
2148     size_t newMaxIndex = context.cursor + bytes;
2149     context.size = context.size < newMaxIndex ? context.size : newMaxIndex;
2150 
2151     return bytes;
2152 }
2153 
2154 int memory_write_append(void* inData, int bytes, void* userData) nothrow @nogc
2155 {
2156     MemoryContext* context = cast(MemoryContext*)userData;
2157     size_t cursor = context.cursor;
2158     size_t available = context.capacity - cursor;
2159     ubyte* source = cast(ubyte*) inData;
2160 
2161     if (cursor + bytes > available)
2162     {
2163         size_t oldSize = context.capacity;
2164         size_t newSize = cursor + bytes;
2165         if (newSize < oldSize * 2 + 1) 
2166             newSize = oldSize * 2 + 1;
2167         context.buffer = cast(ubyte*) realloc(context.buffer, newSize);
2168         context.capacity = newSize;
2169 
2170         assert( cursor + bytes <= newSize );
2171     }
2172     assert(context.buffer !is null);
2173     context.buffer[cursor..(cursor + bytes)] = source[0..bytes];
2174     context.cursor += bytes;
2175 
2176     // new size is max(cursor, previous size)
2177     size_t newMaxIndex = context.cursor + bytes;
2178     context.size = context.size < newMaxIndex ? context.size : newMaxIndex;
2179     return bytes;
2180 }
2181 
2182 bool memory_skip(int bytes, void* userData) nothrow @nogc
2183 {
2184     MemoryContext* context = cast(MemoryContext*)userData;
2185     context.cursor += bytes;
2186     return context.cursor <= context.size;
2187 }
2188 
2189 bool memory_flush(void* userData) nothrow @nogc
2190 {
2191     // do nothing, no flushign to do for memory
2192     return true;
2193 }
2194 
2195 
2196 // Decoder context
2197 struct DecoderContext
2198 {
2199     void* userDataIO;
2200     IOCallbacks* callbacks;
2201 }
2202 
2203 // MP3 decoder read callback
2204 static int mp3ReadDelegate(void[] buf, void* userDataDecoder) @nogc nothrow
2205 {
2206     DecoderContext* context = cast(DecoderContext*) userDataDecoder;
2207 
2208     // read bytes into the buffer, return number of bytes read or 0 for EOF, -1 on error
2209     // will never be called with empty buffer, or buffer more than 128KB
2210 
2211     int bytes = context.callbacks.read(buf.ptr, cast(int)(buf.length), context.userDataIO);
2212     return bytes;
2213 }
2214 
2215 
2216 // FLAC decoder read callbacks
2217 
2218 size_t flac_read(void* pUserData, void* pBufferOut, size_t bytesToRead) @nogc nothrow
2219 {
2220     DecoderContext* context = cast(DecoderContext*) pUserData;
2221     return context.callbacks.read(pBufferOut, cast(int)(bytesToRead), context.userDataIO);
2222 }
2223 
2224 bool flac_seek(void* pUserData, int offset, drflac_seek_origin origin) @nogc nothrow
2225 {
2226     DecoderContext* context = cast(DecoderContext*) pUserData;
2227     if (origin == drflac_seek_origin_start)
2228     {
2229         context.callbacks.seek(offset, false, context.userDataIO);
2230     }
2231     else if (origin == drflac_seek_origin_current)
2232     {
2233         context.callbacks.seek(offset, true, context.userDataIO);
2234     }
2235     return true;
2236 }
2237 
2238 // MP3 decoder read callbacks
2239 
2240 size_t mp3_io_read(void *buf, size_t size, void *user_data) @nogc nothrow
2241 {
2242     DecoderContext* context = cast(DecoderContext*) user_data;
2243     return context.callbacks.read(buf, cast(int)(size), context.userDataIO);
2244 }
2245 
2246 int mp3_io_seek(ulong position, void *user_data) @nogc nothrow
2247 {
2248     DecoderContext* context = cast(DecoderContext*) user_data;
2249     context.callbacks.seek(position, false, context.userDataIO);
2250     return 0; // doesn't detect seeking errors
2251 }