Giter VIP home page Giter VIP logo

Comments (4)

mackron avatar mackron commented on June 16, 2024 2

So good news and bad news on this one. The good news is that I've implemented a solution for this. The bad news is that it's in the dev-0.12 branch which means it won't be released for a while. The reason for this is that I've made some API breaking changes so I don't want to release it in the 0.11.x cycle and break anyone's builds.

The main change is that you can now configure backend priorities explicitly. I've also removed the extension-checking logic for determining backend prioritization. Now the encodingFormat member of ma_decoder_config is put to better use in determining an appropriate decoding backend. Decoding backends now report the encoding format they support (ma_encoding_format_unknown if they support multiple formats) which miniaudio will use in determining which backend to skip over. This combined with being able to explicitly specify priorities should give you a lot of flexibility. I've tested on my end with the resource manager, and it will now load from the Vorbis backend first before attempting anything, so long as the libvorbis decoder is at the top of the priority list, or encodingFormat is set to ma_encoding_format_vorbis.

Rather than typing everything out again, here's a copy and paste of the release notes I've written up:


You can now customize the priority of stock decoding backends, with the ability to plug in your own custom decoders, with total control over prioritization of everything. By default, the same prioritization as before will be used, but if you want to configure it, you can do so via the decoder config:

const ma_decoding_backend_vtable* ppDecodingBackends[] =
{
    // These are custom backends.
    ma_decoding_backend_libvorbis,
    ma_decoding_backend_libopus,

    // These are stock backends. Any of these that you want to support must be explicitly
    // listed when specifying a custom list of decoding backends.
    ma_decoding_backend_wav,
    ma_decoding_backend_flac,
    ma_decoding_backend_mp3
};

ma_decoder_config decoderConfig = ma_decoder_config_init_default();
decoderConfig.ppBackendVTables = ppDecodingBackends;
decoderConfig.backendCount     = sizeof(ppDecodingBackends) / sizeof(ppDecodingBackends[0]);

Note that when specifying your list of backends, you must list every backend that you want to support, including stock ones. By default, when ppBackendVTables is set to NULL, miniaudio will use a default list of stock backends. You can rearrange this list however you like, including mixing up the order. This is a valid priority order, for example.

const ma_decoding_backend_vtable* ppDecodingBackends[] =
{
    ma_decoding_backend_wav,        // Most of our files are .wav, so make that the highest priority.
    ma_decoding_backend_libvorbis,  // Our music is mostly Vorbis...
    ma_decoding_backend_mp3         // ... But we also support MP3.
};

Notice with the example above that we've excluded flac and libopus. In this case, FLAC files and Opus files will not be supported when trying to load files. Also note how we've mixed up the libvorbis decoder, which is a custom decoder, within the stock decoders. You configure this prioritization however you like.

Previously when miniaudio initialized a decoder from a file path it would use the file extension as a hint to determine which of the stock backends to try first. This logic has been removed, but there are tools to allow you to achieve the same effect. Decoding backends now implement a new callback called onGetEncodingFormat. This is used to determine the encoding format the decoder supports (if it supports more than one, ma_encoding_format_unknown is used). This combined with the encodingFormat member of ma_decoder_config allows miniaudio to quickly skip over any decoding backend that cannot possibly decode that file. You can use it like this:

decoderConfig.encodingFormat = ma_encoding_format_from_path(pFilePath);

The ma_encoding_format_from_path() function uses the file extension to determine the encoding format. If the extension is not recognized by miniaudio, ma_encoding_format_unknown will be used in which case miniaudio will use it's standard prioritization rules as explained above. You do not need to use ma_encoding_format_from_path() if you don't want to. If, for example, you know that the file will be a wav file, you could just use ma_encoding_format_wav directly.

If you don't like the decoderConfig.encodingFormat system, another option is to simply specify only a single decoding backend in your backend list:

const ma_decoding_backend_vtable* ppDecodingBackends[] =
{
    ma_decoding_backend_wav,        // All of our files are .wav
};

For authors of custom backends, you should implement the new onGetEncodingFormat callback. See the miniaudio_libvorbis.h and miniaudio_libopus.h files in the extras folder for an example. If you're unsure, just have it return ma_encoding_format_unknown.

from miniaudio.

mackron avatar mackron commented on June 16, 2024 1

Yeah this an annoying one. The whole trial and error thing is an obvious source of inefficiency, and you can probably see in the code the various things I've got in there to try an improve it, like the encoding format hint, and the extension checks for the file version, so I understand the concern and happy to try to come up with some solutions. I'm not entirely sure off the top of my head how best to address this though. Regarding early aborting, I'm not sure because I actually wrap around a library called minimp3 so I can't claim to be an expert on the details of how to properly and reliably check if it's an MP3.

So I assume you're only getting this when trying to load Vorbis files since MP3 is the second lowest in priority, ahead of only Vorbis? It's annoying, but one thing you could do in the immediate term is disable the built-in Vorbis decoder which uses stb_vorbis, and instead plug in a custom Vorbis decoder that uses libvorbisfile. The backend code for this is here https://github.com/mackron/miniaudio/blob/master/extras/miniaudio_libvorbis.h, and the custom_decoder example shows how you can plug it in. The downside of course is having to deal with an external dependency in libvorbis.

I'll have to have more of a think about this and report back.

from miniaudio.

MrBrixican avatar MrBrixican commented on June 16, 2024

Thank you for your consideration and response! This library is fantastic and your hard work shows! Definitely one of the best I've had the pleasure of using.

I'm currently getting this issue with my qoa and the example libvorbis backends (using minivorbis to make it a bit more convenient, haha). They both don't implement onInitMemory vtable method, so they unfortunately get processed after mp3 regardless. It's something I'm considering looking into implementing, just hadn't yet because the callback based decoder was so fast (great job btw).

I'll let you know if I come across another potential solution!

from miniaudio.

MrBrixican avatar MrBrixican commented on June 16, 2024

Awesome work! This solution offers the most flexibility as you say. Thanks!

from miniaudio.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.