MP3Decoder.this

Creates a mp3 decoder out of two functions: a reader and a seeker. Both must work together for things to work.

A reader works like fread - it gives you a buffer and you fill it as much as you can, and return the number of bytes filled. A seeker works like fseek, it tells you a position in the file to go to and you do it, then return 0. If you return non-zero, the library will treat that as an I/O error. You can forward directly to those C functions if you like. Or, you can refer to a memory buffer, or even a network stream. It is all up to you.

Please note that you are responsible for closing the file when you are done with it. This means *after* the mp3 decoder is no longer used. The api will not help you determine this.

Also note that the delegates are NOT scope - they are held on to by this class. It is your responsibility to get lifetimes right; the delegates need to remain valid throughout the use of the decoder object. As a particular warning, a std.stdio.File has a RAII destructor that will trigger when it goes out of scope - not at the end of its referenced lifetime. Meaning the object will be copied for your delegates, but the file will be closed when the function returns, making it useless! I recommend you encapsulate all this in an additional object.

arsd.simpleaudio's playMp3 function does this encapsulation for you.

class MP3Decoder
this
(
int delegate
(
ubyte[] buf
)
reader
,
int delegate
(
ulong where
)
seeker
)

Meta

History

It used to take the reader as scope, but that changed on November 20, 2022. It also used to not take the seeker argument, but this is now required.

The reader used to take void[] buf, but now takes ubyte[] buf. This is a simple change in your signature, otherwise they work the same. ubyte is more appropriate since it is looking for file bytes, not random untyped data.

I realize these are all breaking changes, but the fix is easy and the new functionality, the seek function among others, is worth it. To me anyway, and I hope for you too.