sdlamp/sdlamp.c

247 lines
8.8 KiB
C
Raw Permalink Normal View History

2023-01-11 22:57:19 +00:00
#include <stdio.h>
#include "SDL.h"
2023-01-19 20:03:57 +00:00
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_events.h"
#include "SDL_mouse.h"
#define KB(x) (1024 * (x))
2023-01-11 22:57:19 +00:00
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
2023-01-19 20:03:57 +00:00
static SDL_AudioDeviceID audio_device = 0;
static SDL_AudioStream *stream = NULL;
static float volume_slider_value = 1.0f;
2023-01-20 23:50:34 +00:00
static float balance_slider_value = 0.5f;
2023-01-11 22:57:19 +00:00
#if defined(__clang__) || defined(__GNUC__)
static void panic_and_abort(const char *title, const char *text) __attribute__((noreturn));
#endif
static void panic_and_abort(const char *title, const char *text) {
fprintf(stderr, "PANIC: %s ... %s\n", title, text);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, text, window);
SDL_Quit();
exit(1);
}
2023-01-19 20:03:57 +00:00
// TODO: Refactor this nonsense into a struct
static Uint8 *wavbuf = NULL;
static Uint32 wavlen = 0;
static Uint32 wavpos = 0;
static SDL_AudioSpec wavspec;
2023-01-20 23:50:34 +00:00
static void stop_audio(void) {
if (stream) {
SDL_FreeAudioStream(stream);
stream = NULL;
}
if (wavbuf) {
SDL_FreeWAV(wavbuf);
wavbuf = NULL;
}
wavlen = 0;
wavpos = 0;
}
2023-01-19 20:03:57 +00:00
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);
2023-01-20 23:50:34 +00:00
stop_audio();
2023-01-19 20:03:57 +00:00
return SDL_FALSE;
}
2023-01-20 23:50:34 +00:00
if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "AudioStreamPut failed!", SDL_GetError(), window);
stop_audio();
return SDL_FALSE;
2023-01-19 20:03:57 +00:00
}
2023-01-20 23:50:34 +00:00
if (SDL_AudioStreamFlush(stream) == -1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "AudioStreamFlush failed!", SDL_GetError(), window);
stop_audio();
return SDL_FALSE;
}
2023-01-19 20:03:57 +00:00
return SDL_TRUE;
}
2023-01-11 22:57:19 +00:00
int main(int argc, char **argv) {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
panic_and_abort("SDL_Init failed", SDL_GetError());
}
window = SDL_CreateWindow("sdlamp", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 768, 0);
if (!window) {
panic_and_abort("SDL_CreateWindow failed", SDL_GetError());
}
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_PRESENTVSYNC);
if (!renderer) {
panic_and_abort("SDL_CreateRenderer failed", SDL_GetError());
}
2023-01-19 20:03:57 +00:00
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
2023-01-11 22:57:19 +00:00
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
2023-01-19 20:03:57 +00:00
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
2023-01-11 22:57:19 +00:00
2023-01-19 20:03:57 +00:00
// TODO: Remove temp load
open_audio_file("CantinaBand60.wav");
2023-01-11 22:57:19 +00:00
2023-01-19 20:03:57 +00:00
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
};
2023-01-20 23:50:34 +00:00
const SDL_Rect balance_rect = {(1024 - 500) / 2, 300, 500, 20};
SDL_Rect balance_knob = {
(balance_rect.x + (balance_rect.w / 2)) - balance_knob.w,
balance_rect.y,
20,
balance_rect.h
};
2023-01-11 22:57:19 +00:00
SDL_bool paused = SDL_TRUE;
SDL_bool quit = SDL_FALSE;
while (!quit) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT:
quit = SDL_TRUE;
break;
case SDL_MOUSEBUTTONDOWN: {
SDL_Point pt = { e.button.x, e.button.y };
2023-01-19 20:03:57 +00:00
if (SDL_PointInRect(&pt, &rewind_rect)) { // Pressed the "rewind" button
2023-01-11 22:57:19 +00:00
SDL_ClearQueuedAudio(audio_device);
2023-01-19 20:03:57 +00:00
SDL_AudioStreamClear(stream);
2023-01-20 23:50:34 +00:00
if (SDL_AudioStreamPut(stream, wavbuf, wavlen) == -1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "AudioStreamPut failed!", SDL_GetError(), window);
stop_audio();
}
if (SDL_AudioStreamFlush(stream) == -1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "AudioStreamPut failed!", SDL_GetError(), window);
stop_audio();
2023-01-19 20:03:57 +00:00
}
} else if (SDL_PointInRect(&pt, &pause_rect)) { // Pressed the "pause" button
2023-01-11 22:57:19 +00:00
paused = paused ? SDL_FALSE : SDL_TRUE;
SDL_PauseAudioDevice(audio_device, paused);
}
break;
}
2023-01-19 20:03:57 +00:00
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);
2023-01-20 23:50:34 +00:00
} else if (SDL_PointInRect(&pt, &balance_rect) && (e.motion.state & SDL_BUTTON_LMASK)) { // left mouse pressed inside the "balance" slider
const float fx = (float)(pt.x - balance_rect.x);
balance_slider_value = (fx / (float)balance_rect.w);
balance_knob.x = pt.x - (balance_knob.w / 2);
balance_knob.x = SDL_max(balance_knob.x, balance_rect.x);
balance_knob.x = SDL_min(balance_knob.x, (balance_rect.x + balance_rect.w) - balance_knob.w);
2023-01-11 22:57:19 +00:00
}
2023-01-19 20:03:57 +00:00
break;
}
2023-01-11 22:57:19 +00:00
2023-01-19 20:03:57 +00:00
case SDL_DROPFILE: {
open_audio_file(e.drop.file);
2023-01-11 22:57:19 +00:00
SDL_free(e.drop.file);
break;
}
}
}
2023-01-19 20:03:57 +00:00
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)];
2023-01-20 23:50:34 +00:00
const int num_converted_bytes = SDL_AudioStreamGet(stream, converted_buffer, new_bytes);
if (num_converted_bytes > 0) {
const int num_samples = (num_converted_bytes / sizeof(float));
float *samples = (float*)converted_buffer;
// volume changes
if (volume_slider_value != 1.0f) {
for (size_t i = 0; i < num_samples; ++i) {
samples[i] *= volume_slider_value;
}
}
// balance changes
if (balance_slider_value != 0.5f) {
for (size_t i = 0; i < num_samples; i += 2) {
// first sample is left, second is right
samples[i] *= (1.0f - balance_slider_value);
samples[i + 1] *= balance_slider_value;
}
}
SDL_QueueAudio(audio_device, converted_buffer, new_bytes);
2023-01-19 20:03:57 +00:00
}
}
}
2023-01-11 22:57:19 +00:00
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderFillRect(renderer, &rewind_rect);
SDL_RenderFillRect(renderer, &pause_rect);
2023-01-19 20:03:57 +00:00
SDL_RenderFillRect(renderer, &volume_rect);
2023-01-20 23:50:34 +00:00
SDL_RenderFillRect(renderer, &balance_rect);
2023-01-19 20:03:57 +00:00
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderFillRect(renderer, &volume_knob);
2023-01-20 23:50:34 +00:00
SDL_RenderFillRect(renderer, &balance_knob);
2023-01-11 22:57:19 +00:00
SDL_RenderPresent(renderer);
}
SDL_FreeWAV(wavbuf);
SDL_CloseAudioDevice(audio_device);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}