Comments (4)
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.
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.
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.
Awesome work! This solution offers the most flexibility as you say. Thanks!
from miniaudio.
Related Issues (20)
- Android: Build failure of dev branch due to pthread_attr_setinheritsched HOT 2
- WASM duplicate symbol HOT 3
- Emscripten WASM Thread Problem HOT 2
- Question about Attenuation in Miniaudio. HOT 1
- Javascript error after uninitializing miniaudio HOT 4
- "Error: Invalid argument" due to ma_channel_map_is_valid HOT 6
- Does miniaudio support encoding PCM sample data into ADPCM sample data? HOT 1
- Uncaught RuntimeError: memory access out of bounds after starting playing the sound. HOT 8
- DELETED HOT 1
- Miniaudio waiting infinitely when calling ma_engine_uninit HOT 1
- Is there a way to gracefully shut down all threads created by miniaudio when the application exits? HOT 1
- Channel Convert Init Access Violation going from 2 channels to >2 channels HOT 2
- Sound system lags when playing sounds quickly and using delay or reverb HOT 1
- ma_device_uninit crash on Android <= 10 HOT 3
- error when compiling on android HOT 1
- "[ALSA] poll() failed" Bug. HOT 1
- Consider ditching ReadFile() in favor of FILE* fread() HOT 2
- Compile error with gcc: `error: invalid conversion from 'UInt32*' {aka 'long unsigned int*'} to 'ma_uint32*' {aka 'unsigned int*'} [-fpermissive]` HOT 8
- [i386] `miniaudio.h:83477:no such instruction: `lzcntl %eax, %ecx'` HOT 2
- How can I Cache ma_sound's into memory? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from miniaudio.