implement AudioStream and volume
This commit is contained in:
parent
2111478773
commit
bf9b5580e0
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
|||||||
CC_SDL=`sdl2-config --cflags --libs`
|
CC_SDL=`sdl2-config --cflags --libs`
|
||||||
|
|
||||||
all:
|
all:
|
||||||
cc *.c -o sdlamp -std=c11 $(CC_SDL)
|
cc *.c -o sdlamp -std=c11 $(CC_SDL) -Wall
|
||||||
|
144
sdlamp.c
144
sdlamp.c
@ -1,10 +1,18 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "SDL.h"
|
#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_Window *window = NULL;
|
||||||
static SDL_Renderer *renderer = 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__)
|
#if defined(__clang__) || defined(__GNUC__)
|
||||||
static void panic_and_abort(const char *title, const char *text) __attribute__((noreturn));
|
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);
|
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) {
|
int main(int argc, char **argv) {
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
|
||||||
panic_and_abort("SDL_Init failed", SDL_GetError());
|
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());
|
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_DROPFILE, SDL_ENABLE);
|
||||||
|
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
|
||||||
|
|
||||||
const SDL_Rect rewind_rect = {100, 100, 100, 100};
|
// TODO: Remove temp load
|
||||||
const SDL_Rect pause_rect = {400, 100, 100, 100};
|
open_audio_file("CantinaBand60.wav");
|
||||||
|
|
||||||
SDL_AudioSpec wavspec;
|
const SDL_Rect rewind_rect = {(1024 - 100) / 3, 100, 100, 100};
|
||||||
Uint8 *wavbuf = NULL;
|
const SDL_Rect pause_rect = {((1024 - 100) / 3) * 2 , 100, 100, 100};
|
||||||
Uint32 wavlen = 0;
|
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 paused = SDL_TRUE;
|
||||||
SDL_bool quit = SDL_FALSE;
|
SDL_bool quit = SDL_FALSE;
|
||||||
@ -53,46 +119,54 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
case SDL_MOUSEBUTTONDOWN: {
|
case SDL_MOUSEBUTTONDOWN: {
|
||||||
SDL_Point pt = { e.button.x, e.button.y };
|
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_ClearQueuedAudio(audio_device);
|
||||||
SDL_QueueAudio(audio_device, wavbuf, wavlen);
|
SDL_AudioStreamClear(stream);
|
||||||
} else if (SDL_PointInRect(&pt, &pause_rect)) {
|
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;
|
paused = paused ? SDL_FALSE : SDL_TRUE;
|
||||||
SDL_PauseAudioDevice(audio_device, paused);
|
SDL_PauseAudioDevice(audio_device, paused);
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case SDL_DROPFILE: {
|
||||||
if (audio_device) {
|
open_audio_file(e.drop.file);
|
||||||
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);
|
|
||||||
}
|
|
||||||
SDL_free(e.drop.file);
|
SDL_free(e.drop.file);
|
||||||
break;
|
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_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
@ -100,6 +174,10 @@ int main(int argc, char **argv) {
|
|||||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||||
SDL_RenderFillRect(renderer, &rewind_rect);
|
SDL_RenderFillRect(renderer, &rewind_rect);
|
||||||
SDL_RenderFillRect(renderer, &pause_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);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user