examples/audio/04-multiple-streams: Remove drag-and-drop support.

I'm going to reuse that code for an actual drag/drop example later, but for
simplicity and accessibility of the examples, this is just going to load two
wavs and loop them, so you get the music with a sword-clinking sound mixed
over it.
This commit is contained in:
Ryan C. Gordon 2024-12-10 20:51:54 -05:00
parent e6e468d0c4
commit 1fbb8e1824
No known key found for this signature in database
GPG key ID: FA148B892AB48044
5 changed files with 71 additions and 81 deletions

View file

@ -1,6 +1,6 @@
/*
* This example code loads .wav files dropped onto the app window, puts
* them in an audio stream and binds them for playback. This shows several
* This example code loads two .wav files, puts them an audio streams and
* binds them for playback, repeating both sounds on loop. This shows several
* streams mixing into a single playback device.
*
* This code is public domain. Feel free to use it for any purpose!
@ -14,12 +14,50 @@
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_AudioDeviceID audio_device = 0;
static SDL_AudioStream **streams = NULL;
static int num_streams = 0;
/* things that are playing sound (the audiostream itself, plus the original data, so we can refill to loop. */
typedef struct Sound {
Uint8 *wav_data;
Uint32 wav_data_len;
SDL_AudioStream *stream;
} Sound;
static Sound sounds[2];
static bool init_sound(const char *fname, Sound *sound)
{
bool retval = false;
SDL_AudioSpec spec;
char *wav_path = NULL;
/* Load the .wav files from wherever the app is being run from. */
SDL_asprintf(&wav_path, "%s%s", SDL_GetBasePath(), fname); /* allocate a string of the full file path */
if (!SDL_LoadWAV(wav_path, &spec, &sound->wav_data, &sound->wav_data_len)) {
SDL_Log("Couldn't load .wav file: %s", SDL_GetError());
return false;
}
/* Create an audio stream. Set the source format to the wav's format (what
we'll input), leave the dest format NULL here (it'll change to what the
device wants once we bind it). */
sound->stream = SDL_CreateAudioStream(&spec, NULL);
if (!sound->stream) {
SDL_Log("Couldn't create audio stream: %s", SDL_GetError());
} else if (!SDL_BindAudioStream(audio_device, sound->stream)) { /* once bound, it'll start playing when there is data available! */
SDL_Log("Failed to bind '%s' stream to device: %s", fname, SDL_GetError());
} else {
retval = true; /* success! */
}
SDL_free(wav_path); /* done with this string. */
return retval;
}
/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
SDL_SetAppMetadata("Example Audio Multiple Streams", "1.0", "com.example.audio-multiple-streams");
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
@ -39,66 +77,20 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
return SDL_APP_FAILURE;
}
if (!init_sound("sample.wav", &sounds[0])) {
return SDL_APP_FAILURE;
} else if (!init_sound("sword.wav", &sounds[1])) {
return SDL_APP_FAILURE;
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
static void load_wav_file(const char *fname)
{
int idx;
SDL_AudioSpec spec;
Uint8 *wav_data = NULL;
Uint32 wav_data_len = 0;
/* Find an unused element in the streams array... */
for (idx = 0; idx < num_streams; idx++) {
if (streams[idx] == NULL) {
break;
}
}
/* No space? Grow the array. */
if (idx == num_streams) {
void *ptr = SDL_realloc(streams, (num_streams + 1) * sizeof (*streams));
if (!ptr) {
SDL_Log("Out of memory!");
return; // oh well.
}
streams = (SDL_AudioStream **) ptr;
streams[idx] = NULL;
num_streams++;
}
/* Load the new .wav file */
if (!SDL_LoadWAV(fname, &spec, &wav_data, &wav_data_len)) {
SDL_Log("Failed to load '%s': %s", fname, SDL_GetError());
return; // oh well.
}
/* Create an audio stream. Set the source format to the wav's format (what
we'll input), leave the dest format NULL here (it'll change to what the
device wants once we bind it). */
streams[idx] = SDL_CreateAudioStream(&spec, NULL);
if (!streams[idx]) {
SDL_Log("Couldn't create audio stream: %s", SDL_GetError());
} else if (!SDL_BindAudioStream(audio_device, streams[idx])) { /* once bound, it'll start playing when there is data available! */
SDL_Log("Failed to bind '%s' stream to device: %s", fname, SDL_GetError());
} else if (!SDL_PutAudioStreamData(streams[idx], wav_data, (int) wav_data_len)) {
SDL_Log("Failed to put '%s' data into stream: %s", fname, SDL_GetError());
} else {
/* tell SDL we won't be sending more data to this stream, so don't hold back for resampling. */
SDL_FlushAudioStream(streams[idx]);
}
SDL_free(wav_data);
}
/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
if (event->type == SDL_EVENT_QUIT) {
return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
} else if (event->type == SDL_EVENT_DROP_FILE) {
load_wav_file(event->drop.data);
}
return SDL_APP_CONTINUE; /* carry on with the program! */
}
@ -106,26 +98,20 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate)
{
int winw = 640, winh = 480;
const char *text = "--> Drag and drop .wav files here <--";
float x, y;
int i;
/* see if any streams have finished; destroy them if so. */
for (i = 0; i < num_streams; i++) {
if (streams[i] && (SDL_GetAudioStreamAvailable(streams[i]) == 0)) {
SDL_DestroyAudioStream(streams[i]);
streams[i] = NULL;
for (i = 0; i < SDL_arraysize(sounds); i++) {
/* If less than a full copy of the audio is queued for playback, put another copy in there.
This is overkill, but easy when lots of RAM is cheap. One could be more careful and
queue less at a time, as long as the stream doesn't run dry. */
if (SDL_GetAudioStreamAvailable(sounds[i].stream) < sounds[i].wav_data_len) {
SDL_PutAudioStreamData(sounds[i].stream, sounds[i].wav_data, (int) sounds[i].wav_data_len);
}
}
/* just blank the screen. */
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_GetWindowSize(window, &winw, &winh);
x = (((float) winw) - (SDL_strlen(text) * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE)) / 2.0f;
y = (((float) winh) - SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) / 2.0f;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDebugText(renderer, x, y, text);
SDL_RenderPresent(renderer);
return SDL_APP_CONTINUE; /* carry on with the program! */
@ -138,14 +124,12 @@ void SDL_AppQuit(void *appstate, SDL_AppResult result)
SDL_CloseAudioDevice(audio_device);
/* see if any streams have finished; destroy them if so. */
for (i = 0; i < num_streams; i++) {
if (streams[i]) {
SDL_DestroyAudioStream(streams[i]);
for (i = 0; i < SDL_arraysize(sounds); i++) {
if (sounds[i].stream) {
SDL_DestroyAudioStream(sounds[i].stream);
}
SDL_free(sounds[i].wav_data);
}
SDL_free(streams);
/* SDL will clean up the window/renderer for us. */
}