Explorar el Código

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.
Ryan C. Gordon hace 4 meses
padre
commit
1fbb8e1824

+ 1 - 1
examples/CMakeLists.txt

@@ -139,7 +139,7 @@ add_sdl_example_executable(renderer-debug-text SOURCES renderer/18-debug-text/de
 add_sdl_example_executable(audio-simple-playback SOURCES audio/01-simple-playback/simple-playback.c)
 add_sdl_example_executable(audio-simple-playback SOURCES audio/01-simple-playback/simple-playback.c)
 add_sdl_example_executable(audio-simple-playback-callback SOURCES audio/02-simple-playback-callback/simple-playback-callback.c)
 add_sdl_example_executable(audio-simple-playback-callback SOURCES audio/02-simple-playback-callback/simple-playback-callback.c)
 add_sdl_example_executable(audio-load-wav SOURCES audio/03-load-wav/load-wav.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav)
 add_sdl_example_executable(audio-load-wav SOURCES audio/03-load-wav/load-wav.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav)
-add_sdl_example_executable(audio-multiple-streams SOURCES audio/04-multiple-streams/multiple-streams.c)
+add_sdl_example_executable(audio-multiple-streams SOURCES audio/04-multiple-streams/multiple-streams.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav ${CMAKE_CURRENT_SOURCE_DIR}/../test/sword.wav)
 add_sdl_example_executable(input-joystick-polling SOURCES input/01-joystick-polling/joystick-polling.c)
 add_sdl_example_executable(input-joystick-polling SOURCES input/01-joystick-polling/joystick-polling.c)
 add_sdl_example_executable(input-joystick-events SOURCES input/02-joystick-events/joystick-events.c)
 add_sdl_example_executable(input-joystick-events SOURCES input/02-joystick-events/joystick-events.c)
 add_sdl_example_executable(camera-read-and-draw SOURCES camera/01-read-and-draw/read-and-draw.c)
 add_sdl_example_executable(camera-read-and-draw SOURCES camera/01-read-and-draw/read-and-draw.c)

+ 3 - 5
examples/audio/04-multiple-streams/README.txt

@@ -1,5 +1,3 @@
-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
-streams mixing into a single playback device.
-
-Drag several files while one is still playing!
+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.

+ 58 - 74
examples/audio/04-multiple-streams/multiple-streams.c

@@ -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.
  * streams mixing into a single playback device.
  *
  *
  * This code is public domain. Feel free to use it for any purpose!
  * This code is public domain. Feel free to use it for any purpose!
@@ -14,12 +14,50 @@
 static SDL_Window *window = NULL;
 static SDL_Window *window = NULL;
 static SDL_Renderer *renderer = NULL;
 static SDL_Renderer *renderer = NULL;
 static SDL_AudioDeviceID audio_device = 0;
 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. */
 /* This function runs once at startup. */
 SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 {
 {
+
     SDL_SetAppMetadata("Example Audio Multiple Streams", "1.0", "com.example.audio-multiple-streams");
     SDL_SetAppMetadata("Example Audio Multiple Streams", "1.0", "com.example.audio-multiple-streams");
 
 
     if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
     if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
@@ -39,57 +77,13 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
         return SDL_APP_FAILURE;
         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]);
+    if (!init_sound("sample.wav", &sounds[0])) {
+        return SDL_APP_FAILURE;
+    } else if (!init_sound("sword.wav", &sounds[1])) {
+        return SDL_APP_FAILURE;
     }
     }
 
 
-    SDL_free(wav_data);
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
 }
 }
 
 
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
 /* This function runs when a new event (mouse input, keypresses, etc) occurs. */
@@ -97,8 +91,6 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
 {
 {
     if (event->type == SDL_EVENT_QUIT) {
     if (event->type == SDL_EVENT_QUIT) {
         return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
         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! */
     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. */
 /* This function runs once per frame, and is the heart of the program. */
 SDL_AppResult SDL_AppIterate(void *appstate)
 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;
     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_SetRenderDrawColor(renderer, 0, 0, 0, 255);
     SDL_RenderClear(renderer);
     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);
     SDL_RenderPresent(renderer);
 
 
     return SDL_APP_CONTINUE;  /* carry on with the program! */
     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);
     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. */
     /* SDL will clean up the window/renderer for us. */
 }
 }

+ 8 - 0
test/LICENSE.txt

@@ -34,6 +34,14 @@ Thanks to Will for permitting us to distribute this sample with SDL!
 
 
 
 
 
 
+This directory contains sword.wav:
+
+  sword04.wav by Erdie
+  Original: https://freesound.org/s/27858/
+  License: https://creativecommons.org/licenses/by/4.0/
+
+
+
 The .bmp files used by testaudio.c were made by AlDraw:
 The .bmp files used by testaudio.c were made by AlDraw:
 
 
 https://linktr.ee/AlexDraw
 https://linktr.ee/AlexDraw

BIN
test/sword.wav