From 153b2ebd48052079de6679df5ae5d7c2043da322 Mon Sep 17 00:00:00 2001 From: David Reid Date: Sat, 1 Jan 2022 13:21:30 +1000 Subject: [PATCH] Add example for using the engine with SDL. --- examples/engine_sdl.c | 137 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 examples/engine_sdl.c diff --git a/examples/engine_sdl.c b/examples/engine_sdl.c new file mode 100644 index 00000000..391588b1 --- /dev/null +++ b/examples/engine_sdl.c @@ -0,0 +1,137 @@ +/* +Shows how to use the high level engine API with SDL. + +By default, miniaudio's engine API will initialize a device internally which will be used for audio +output. You can instead use the engine independently of a device. To show this off, this example +will use SDL for audio output instead of miniaudio. + +This example will load sound specified on the command line and rotate it around the listener's +head. +*/ +#define MA_NO_DEVICE_IO /* <-- Disables the `ma_device` API. We don't need that in this example since SDL will be doing that part for us. */ +#define MINIAUDIO_IMPLEMENTATION +#include "../miniaudio.h" + +#define SDL_MAIN_HANDLED +#include /* Change this to your include location. Might be . */ + +#define CHANNELS 2 /* Must be stereo for this example. */ +#define SAMPLE_RATE 48000 + +static ma_engine g_engine; +static ma_sound g_sound; /* This example will play only a single sound at once, so we only need one `ma_sound` object. */ + +void data_callback(void* pUserData, ma_uint8* pBuffer, int bufferSizeInBytes) +{ + /* Reading is just a matter of reading straight from the engine. */ + ma_uint32 bufferSizeInFrames = (ma_uint32)bufferSizeInBytes / ma_get_bytes_per_frame(ma_format_f32, ma_engine_get_channels(&g_engine)); + ma_engine_read_pcm_frames(&g_engine, pBuffer, bufferSizeInFrames, NULL); +} + +int main(int argc, char** argv) +{ + ma_result result; + ma_engine_config engineConfig; + SDL_AudioSpec desiredSpec; + SDL_AudioSpec obtainedSpec; + SDL_AudioDeviceID deviceID; + + if (argc < 2) { + printf("No input file."); + return -1; + } + + /* + We'll initialize the engine first for the purpose of the example, but since the engine and SDL + are independent of each other you can initialize them in any order. You need only make sure the + channel count and sample rates are consistent between the two. + + When initializing the engine it's important to make sure we don't initialize a device + internally because we want SDL to be dealing with that for us instead. + */ + engineConfig = ma_engine_config_init(); + engineConfig.noDevice = MA_TRUE; /* <-- Make sure this is set so that no device is created (we'll deal with that ourselves). */ + engineConfig.channels = CHANNELS; + engineConfig.sampleRate = SAMPLE_RATE; + + result = ma_engine_init(&engineConfig, &g_engine); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio engine."); + return -1; + } + + /* Now load our sound. */ + result = ma_sound_init_from_file(&g_engine, argv[1], 0, NULL, NULL, &g_sound); + if (result != MA_SUCCESS) { + printf("Failed to initialize sound."); + return -1; + } + + /* Loop the sound so we can continuously hear it. */ + ma_sound_set_looping(&g_sound, MA_TRUE); + + /* + The sound will not be started by default, so start it now. We won't hear anything until the SDL + audio device has been opened and started. + */ + ma_sound_start(&g_sound); + + + /* + Now that we have the engine and sound we can initialize SDL. This could have also been done + first before the engine and sound. + */ + if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) { + printf("Failed to initialize SDL sub-system."); + return -1; + } + + MA_ZERO_OBJECT(&desiredSpec); + desiredSpec.freq = ma_engine_get_sample_rate(&g_engine); + desiredSpec.format = AUDIO_F32; + desiredSpec.channels = ma_engine_get_channels(&g_engine); + desiredSpec.samples = 512; + desiredSpec.callback = data_callback; + desiredSpec.userdata = NULL; + + deviceID = SDL_OpenAudioDevice(NULL, 0, &desiredSpec, &obtainedSpec, SDL_AUDIO_ALLOW_ANY_CHANGE); + if (deviceID == 0) { + printf("Failed to open SDL audio device."); + return -1; + } + + /* Start playback. */ + SDL_PauseAudioDevice(deviceID, 0); + +#if 1 + { + /* + We'll move the sound around the listener which we'll leave at the origin. We'll then get + the direction to the listener and update the binaural node appropriately. + */ + float stepAngle = 0.002f; + float angle = 0; + float distance = 2; + + for (;;) { + double x = ma_cosd(angle) - ma_sind(angle); + double y = ma_sind(angle) + ma_cosd(angle); + + ma_sound_set_position(&g_sound, (float)x * distance, 0, (float)y * distance); + + angle += stepAngle; + ma_sleep(1); + } + } +#else + printf("Press Enter to quit..."); + getchar(); +#endif + + ma_sound_uninit(&g_sound); + ma_engine_uninit(&g_engine); + SDL_CloseAudioDevice(deviceID); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + + return 0; +} \ No newline at end of file