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 }