From bf9b5580e07bc389a86112016d9e30dac233d625 Mon Sep 17 00:00:00 2001 From: Evan Burkey Date: Thu, 19 Jan 2023 12:03:57 -0800 Subject: [PATCH] implement AudioStream and volume --- Makefile | 2 +- sdlamp.c | 144 ++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 112 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index c941490..c5344d6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ CC_SDL=`sdl2-config --cflags --libs` all: - cc *.c -o sdlamp -std=c11 $(CC_SDL) + cc *.c -o sdlamp -std=c11 $(CC_SDL) -Wall diff --git a/sdlamp.c b/sdlamp.c index 1769b9d..68402d3 100644 --- a/sdlamp.c +++ b/sdlamp.c @@ -1,10 +1,18 @@ #include #include "SDL.h" +#include "SDL_audio.h" +#include "SDL_error.h" +#include "SDL_events.h" +#include "SDL_mouse.h" + +#define KB(x) (1024 * (x)) -static SDL_AudioDeviceID audio_device = 0; static SDL_Window *window = NULL; static SDL_Renderer *renderer = NULL; +static SDL_AudioDeviceID audio_device = 0; +static SDL_AudioStream *stream = NULL; +static float volume_slider_value = 1.0f; #if defined(__clang__) || defined(__GNUC__) static void panic_and_abort(const char *title, const char *text) __attribute__((noreturn)); @@ -16,6 +24,44 @@ static void panic_and_abort(const char *title, const char *text) { exit(1); } +// TODO: Refactor this nonsense into a struct +static Uint8 *wavbuf = NULL; +static Uint32 wavlen = 0; +static Uint32 wavpos = 0; +static SDL_AudioSpec wavspec; + +static SDL_bool open_audio_file(const char *fname) { + SDL_FreeAudioStream(stream); + stream = NULL; + SDL_FreeWAV(wavbuf); + wavbuf = NULL; + wavlen = 0; + wavpos = 0; + + if (SDL_LoadWAV(fname, &wavspec, &wavbuf, &wavlen) == NULL) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load wav file!", SDL_GetError(), window); + return SDL_FALSE; + } + + stream = SDL_NewAudioStream(wavspec.format, wavspec.channels, wavspec.freq, AUDIO_F32, 2, 48000); + if (!stream) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create audiostream!", SDL_GetError(), window); + SDL_FreeWAV(wavbuf); + wavbuf = NULL; + wavlen = 0; + wavpos = 0; + return SDL_FALSE; + } + + if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) { // FIXME: graceful handling + panic_and_abort("Audio stream put failed", SDL_GetError()); + } + + SDL_AudioStreamFlush(stream); // FIXME: error handling + + return SDL_TRUE; +} + int main(int argc, char **argv) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) { panic_and_abort("SDL_Init failed", SDL_GetError()); @@ -31,15 +77,35 @@ int main(int argc, char **argv) { panic_and_abort("SDL_CreateRenderer failed", SDL_GetError()); } - // Enable dropfile events + SDL_AudioSpec desired; + SDL_zero(desired); + desired.freq = 48000; + desired.format = AUDIO_F32; + desired.channels = 2; + desired.samples = 4096; + desired.callback = NULL; + + audio_device = SDL_OpenAudioDevice(NULL, 0, &desired, NULL, 0); + if (audio_device == 0) { + panic_and_abort("Couldn't load audio device!", SDL_GetError()); + } + + // Enable events SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); - const SDL_Rect rewind_rect = {100, 100, 100, 100}; - const SDL_Rect pause_rect = {400, 100, 100, 100}; + // TODO: Remove temp load + open_audio_file("CantinaBand60.wav"); - SDL_AudioSpec wavspec; - Uint8 *wavbuf = NULL; - Uint32 wavlen = 0; + const SDL_Rect rewind_rect = {(1024 - 100) / 3, 100, 100, 100}; + const SDL_Rect pause_rect = {((1024 - 100) / 3) * 2 , 100, 100, 100}; + const SDL_Rect volume_rect = {(1024 - 500) / 2, 400, 500, 20}; + SDL_Rect volume_knob = { + (volume_rect.x + volume_rect.w) - volume_knob.w, + volume_rect.y, + 20, + volume_rect.h + }; SDL_bool paused = SDL_TRUE; SDL_bool quit = SDL_FALSE; @@ -53,46 +119,54 @@ int main(int argc, char **argv) { case SDL_MOUSEBUTTONDOWN: { SDL_Point pt = { e.button.x, e.button.y }; - if (SDL_PointInRect(&pt, &rewind_rect)) { + if (SDL_PointInRect(&pt, &rewind_rect)) { // Pressed the "rewind" button SDL_ClearQueuedAudio(audio_device); - SDL_QueueAudio(audio_device, wavbuf, wavlen); - } else if (SDL_PointInRect(&pt, &pause_rect)) { + SDL_AudioStreamClear(stream); + if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) { // FIXME: graceful handling + panic_and_abort("Audio stream put failed", SDL_GetError()); + } + SDL_AudioStreamFlush(stream); + } else if (SDL_PointInRect(&pt, &pause_rect)) { // Pressed the "pause" button paused = paused ? SDL_FALSE : SDL_TRUE; SDL_PauseAudioDevice(audio_device, paused); } break; } + case SDL_MOUSEMOTION: { + SDL_Point pt = { e.motion.x, e.motion.y }; + if (SDL_PointInRect(&pt, &volume_rect) && (e.motion.state & SDL_BUTTON_LMASK)) { // left mouse pressed inside the "volume" slider + const float fx = (float)(pt.x - volume_rect.x); + volume_slider_value = (fx / (float)volume_rect.w); + volume_knob.x = pt.x - (volume_knob.w / 2); + volume_knob.x = SDL_max(volume_knob.x, volume_rect.x); + volume_knob.x = SDL_min(volume_knob.x, (volume_rect.x + volume_rect.w) - volume_knob.w); + } + break; + } + case SDL_DROPFILE: { - if (audio_device) { - SDL_CloseAudioDevice(audio_device); - audio_device = 0; - } - - SDL_FreeWAV(wavbuf); - wavbuf = NULL; - wavlen = 0; - - if (SDL_LoadWAV(e.drop.file, &wavspec, &wavbuf, &wavlen) == NULL) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load wav file!", SDL_GetError(), window); - } - - audio_device = SDL_OpenAudioDevice(NULL, 0, &wavspec, NULL, 0); - if (audio_device == 0) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't load audio device!", SDL_GetError(), window); - SDL_free(wavbuf); - wavbuf = NULL; - wavlen = 0; - } else { - SDL_QueueAudio(audio_device, wavbuf, wavlen); - SDL_PauseAudioDevice(audio_device, 0); - } + open_audio_file(e.drop.file); SDL_free(e.drop.file); break; } } } + if (SDL_GetQueuedAudioSize(audio_device) < KB(8)) { + const int bytes_remaining = SDL_AudioStreamAvailable(stream); + if (bytes_remaining > 0) { + const int new_bytes = SDL_min(bytes_remaining, KB(32)); + static Uint8 converted_buffer[KB(32)]; + SDL_AudioStreamGet(stream, converted_buffer, new_bytes); // FIXME: Error checking + const int num_samples = (new_bytes / sizeof(float)); + float *samples = (float*)converted_buffer; + for (size_t i = 0; i < num_samples; ++i) { + samples[i] *= volume_slider_value; + } + SDL_QueueAudio(audio_device, converted_buffer, new_bytes); + } + } SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); @@ -100,6 +174,10 @@ int main(int argc, char **argv) { SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderFillRect(renderer, &rewind_rect); SDL_RenderFillRect(renderer, &pause_rect); + SDL_RenderFillRect(renderer, &volume_rect); + + SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); + SDL_RenderFillRect(renderer, &volume_knob); SDL_RenderPresent(renderer); }