Documentation HomeProgramming ManualExamplesCustom BackendCustom DecoderCustom Decoder EngineData Source ChainingDuplex EffectEngine AdvancedEngine EffectsEngine Hello WorldEngine SdlEngine SteamaudioHilo InteropNode GraphResource ManagerResource Manager AdvancedSimple CaptureSimple DuplexSimple EnumerationSimple LoopbackSimple LoopingSimple MixingSimple PlaybackSimple Playback SineSimple Playback SineSimple SpatializationAPI Reference |
Custom DecoderDemonstrates how to implement a custom decoder. This example implements two custom decoders: A custom decoder must implement a data source. In this example, the libvorbis data source is called ma_libvorbis and the Opus data source is called ma_libopus. These two objects are compatible with the ma_data_source APIs and can be taken straight from this example and used in real code. The custom decoding data sources (ma_libvorbis and ma_libopus in this example) are connected to the decoder via the decoder config (ma_decoder_config). You need to implement a vtable for each of your custom decoders. See ma_decoding_backend_vtable for the functions you need to implement. The onInitFile, onInitFileW and onInitMemory functions are optional. /* For now these need to be declared before miniaudio.c due to some compatibility issues with the old MINIAUDIO_IMPLEMENTATION system. This will change from version 0.12. */ #include "../extras/decoders/libvorbis/miniaudio_libvorbis.c" #include "../extras/decoders/libopus/miniaudio_libopus.c" #include "../miniaudio.c" #include <stdio.h> void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { ma_data_source* pDataSource = (ma_data_source*)pDevice->pUserData; if (pDataSource == NULL) { return; } ma_data_source_read_pcm_frames(pDataSource, pOutput, frameCount, NULL); (void)pInput; } int main(int argc, char** argv) { ma_result result; ma_decoder_config decoderConfig; ma_decoder decoder; ma_device_config deviceConfig; ma_device device; ma_format format; ma_uint32 channels; ma_uint32 sampleRate; /* Add your custom backend vtables here. The order in the array defines the order of priority. The vtables will be passed in via the decoder config. */ const ma_decoding_backend_vtable* pCustomBackendVTables[] = { ma_decoding_backend_libvorbis, ma_decoding_backend_libopus }; if (argc < 2) { printf("No input file.\n"); return -1; } /* Initialize the decoder. */ decoderConfig = ma_decoder_config_init_default(); decoderConfig.pCustomBackendUserData = NULL; /* None of our decoders require user data, so this can be set to null. */ decoderConfig.ppCustomBackendVTables = pCustomBackendVTables; decoderConfig.customBackendCount = sizeof(pCustomBackendVTables) / sizeof(pCustomBackendVTables[0]); result = ma_decoder_init_file(argv[1], &decoderConfig, &decoder); if (result != MA_SUCCESS) { printf("Failed to initialize decoder."); return -1; } ma_data_source_set_looping(&decoder, MA_TRUE); /* Initialize the device. */ result = ma_data_source_get_data_format(&decoder, &format, &channels, &sampleRate, NULL, 0); if (result != MA_SUCCESS) { printf("Failed to retrieve decoder data format."); ma_decoder_uninit(&decoder); return -1; } deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig.playback.format = format; deviceConfig.playback.channels = channels; deviceConfig.sampleRate = sampleRate; deviceConfig.dataCallback = data_callback; deviceConfig.pUserData = &decoder; if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) { printf("Failed to open playback device.\n"); ma_decoder_uninit(&decoder); return -1; } if (ma_device_start(&device) != MA_SUCCESS) { printf("Failed to start playback device.\n"); ma_device_uninit(&device); ma_decoder_uninit(&decoder); return -1; } printf("Press Enter to quit..."); getchar(); ma_device_uninit(&device); ma_decoder_uninit(&decoder); return 0; } |
![]() |