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