Commit Diff


commit - 2111478773eaafe335d429d99f43336efcb717ee
commit + bf9b5580e07bc389a86112016d9e30dac233d625
blob - c9414902f73f956416328f5c54fec3285ab37491
blob + c5344d657e31ccd32ad40fcb70348ae6934671b2
--- Makefile
+++ 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
blob - 1769b9df0d43e7d354a6c6cd4bcd2904e4996fd0
blob + 68402d33e0f048cc3fd11ca09b6ea123ada82493
--- sdlamp.c
+++ sdlamp.c
@@ -1,10 +1,18 @@
 #include <stdio.h>
 
 #include "SDL.h"
+#include "SDL_audio.h"
+#include "SDL_error.h"
+#include "SDL_events.h"
+#include "SDL_mouse.h"
 
-static SDL_AudioDeviceID audio_device = 0;
+#define KB(x) (1024 * (x))
+
 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 c
     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,7 +174,11 @@ 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);
     }