mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-23 00:34:03 +02:00
150 lines
5.5 KiB
C
150 lines
5.5 KiB
C
/*
|
|
This example shows how to plug in custom backends.
|
|
|
|
To use a custom backend you need to plug in a `ma_device_backend_vtable` pointer into the context config. You can plug in multiple
|
|
custom backends, but for this example we're just using the SDL backend which you can find in the extras folder in the miniaudio
|
|
repository. If your custom backend requires it, you can also plug in a user data pointer which will be passed to the backend callbacks.
|
|
|
|
Custom backends are identified with the `ma_backend_custom` backend type. For the purpose of demonstration, this example only uses the
|
|
`ma_backend_custom` backend type because otherwise the built-in backends would always get chosen first and none of the code for the custom
|
|
backends would actually get hit. By default, the `ma_backend_custom` backend is the second-lowest priority backend, sitting just above
|
|
`ma_backend_null`.
|
|
*/
|
|
#include "../miniaudio.c"
|
|
|
|
/* We're using SDL for this example. To use this in your own program, you need to include miniaudio_sdl2.h after miniaudio.h. */
|
|
#include "../extras/backends/sdl2/miniaudio_sdl2.h"
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
#include <emscripten.h>
|
|
|
|
void main_loop__em()
|
|
{
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
Main program starts here.
|
|
*/
|
|
#define DEVICE_FORMAT ma_format_f32
|
|
#define DEVICE_CHANNELS 2
|
|
#define DEVICE_SAMPLE_RATE 48000
|
|
|
|
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
|
{
|
|
if (pDevice->type == ma_device_type_playback) {
|
|
ma_waveform_read_pcm_frames((ma_waveform*)pDevice->pUserData, pOutput, frameCount, NULL);
|
|
}
|
|
|
|
if (pDevice->type == ma_device_type_duplex) {
|
|
ma_copy_pcm_frames(pOutput, pInput, frameCount, pDevice->playback.format, pDevice->playback.channels);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
ma_result result;
|
|
ma_context context;
|
|
ma_device_config deviceConfig;
|
|
ma_device device;
|
|
ma_waveform_config sineWaveConfig;
|
|
ma_waveform sineWave;
|
|
char name[256];
|
|
|
|
/*
|
|
Here is where we would set up the SDL-specific context-level config. The custom SDL backend allows this to be null, but we're
|
|
defining it here just for the sake of demonstration. Whether or not this is required depends on the backend. If you're not sure,
|
|
check the documentation for the backend.
|
|
*/
|
|
ma_context_config_sdl2 sdl2ContextConfig = ma_context_config_sdl2_init();
|
|
sdl2ContextConfig._unused = 0;
|
|
|
|
/*
|
|
You must include an entry for each backend you're using, even if the config is NULL. This is how miniaudio knows about
|
|
your custom backend.
|
|
|
|
For stock backends, you can just leave the config pointer as NULL and fill out any backend-specific config options in
|
|
the ma_context_config structure. Same with device configs.
|
|
*/
|
|
ma_device_backend_config backends[] =
|
|
{
|
|
{ ma_device_backend_sdl2, &sdl2ContextConfig },
|
|
{ ma_device_backend_wasapi, NULL },
|
|
{ ma_device_backend_pulseaudio, NULL }
|
|
};
|
|
|
|
result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), NULL, &context);
|
|
if (result != MA_SUCCESS) {
|
|
return -1;
|
|
}
|
|
|
|
/* In playback mode we're just going to play a sine wave. */
|
|
sineWaveConfig = ma_waveform_config_init(DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, ma_waveform_type_sine, 0.2, 220);
|
|
ma_waveform_init(&sineWaveConfig, &sineWave);
|
|
|
|
|
|
|
|
/*
|
|
Just like with context configs, we can define some device-level configs as well. It works the same way, except you will pass in
|
|
a backend-specific device-level config. If the backend doesn't require a device-level config, you can set this to NULL.
|
|
*/
|
|
ma_device_config_sdl2 sdl2DeviceConfig = ma_device_config_sdl2_init();
|
|
sdl2DeviceConfig._unused = 0;
|
|
|
|
/*
|
|
Unlike with contexts, if your backend does not require a device-level config, you can just leave it out of this list entirely.
|
|
*/
|
|
ma_device_backend_config pBackendDeviceConfigs[] =
|
|
{
|
|
{ ma_device_backend_sdl2, &sdl2DeviceConfig },
|
|
{ ma_device_backend_wasapi, NULL },
|
|
{ ma_device_backend_pulseaudio, NULL }
|
|
};
|
|
|
|
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
|
deviceConfig.playback.format = DEVICE_FORMAT;
|
|
deviceConfig.playback.channels = DEVICE_CHANNELS;
|
|
deviceConfig.capture.format = DEVICE_FORMAT;
|
|
deviceConfig.capture.channels = DEVICE_CHANNELS;
|
|
deviceConfig.sampleRate = DEVICE_SAMPLE_RATE;
|
|
deviceConfig.dataCallback = data_callback;
|
|
deviceConfig.pUserData = &sineWave;
|
|
deviceConfig.pBackendConfigs = pBackendDeviceConfigs;
|
|
deviceConfig.backendConfigCount = sizeof(pBackendDeviceConfigs) / sizeof(pBackendDeviceConfigs[0]);
|
|
|
|
result = ma_device_init(&context, &deviceConfig, &device);
|
|
if (result != MA_SUCCESS) {
|
|
ma_context_uninit(&context);
|
|
return -1;
|
|
}
|
|
|
|
|
|
ma_device_get_name(&device, ma_device_type_playback, name, sizeof(name), NULL);
|
|
printf("Device Name: %s\n", name);
|
|
|
|
if (ma_device_start(&device) != MA_SUCCESS) {
|
|
ma_device_uninit(&device);
|
|
ma_context_uninit(&context);
|
|
return -5;
|
|
}
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
emscripten_set_main_loop(main_loop__em, 0, 1);
|
|
#else
|
|
printf("Press Enter to quit...\n");
|
|
getchar();
|
|
#endif
|
|
|
|
ma_device_uninit(&device);
|
|
ma_context_uninit(&context);
|
|
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* We put the SDL implementation here just to simplify the compilation process. This way you need only compile custom_backend.c. */
|
|
#include "../extras/backends/sdl2/miniaudio_sdl2.c"
|