From 6589107006fd4fc06bdb7d02cb4b1eef45395458 Mon Sep 17 00:00:00 2001 From: quou Date: Mon, 3 Jun 2024 21:05:14 +1000 Subject: Basic audio playback with pulseaudio. --- Makefile | 2 +- config.h | 3 +++ library.c | 48 ++++++++++++++++++++++++++++++++- library.h | 13 +++++++++ main.c | 12 ++++++++- plat.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- plat.h | 6 +++++ 7 files changed, 173 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 761b428..4505fe0 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ compiler = gcc linker = gcc cflags = -I./ -g $(includes) $(defines) \ -Wall -Wextra -pedantic -std=c99 -lflags = -lX11 -lm +lflags = -lX11 -lm -lpulse -lpulse-simple -lpthread target = twinkplayer includes = defines = \ diff --git a/config.h b/config.h index e19aa30..33108e8 100644 --- a/config.h +++ b/config.h @@ -5,6 +5,9 @@ #define default_window_w 1280 #define default_window_h 960 +/* For each channel. */ +#define audio_buffer_size (1024 * 4) + #define memory_heap_size (1024 * 1024 * 512) #define memory_size (memory_heap_size + (1024 * 1024 * 8)) #define library_memory_size (1024 * 1024 * 256) diff --git a/library.c b/library.c index 4eb4ab0..cf947cd 100644 --- a/library.c +++ b/library.c @@ -1,3 +1,4 @@ +#include "config.h" #include "library.h" #include "plat.h" #include @@ -103,7 +104,6 @@ void flac_meta( drflac_vorbis_comment_iterator i; drflac_uint32 len; const char* c; - int size; switch (m->type) { case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: drflac_init_vorbis_comment_iterator( @@ -137,5 +137,51 @@ int get_song_meta(const char* path, Song* s) { return 0; } +int sound_mix( + void* uptr, + unsigned char* buf, + int size +) { + Player* p; + drflac* f; + int r; + (void)size; + p = uptr; + f = p->f; + r = drflac_read_pcm_frames_s32( + f, + size / p->channels / 4, + (int*)buf + ); + return r * p->channels * 4; +} + +void init_player(Player* p) { + p->seek = 0; + p->song = 0; + p->play = 0; +} + +void play_song(Player* p, Song* song) { + drflac* f; + int sr, channels; + f = drflac_open_file( + song->path, + 0 + ); + /* todo errors and stuff */ + if (!f) return; + channels = f->channels; + sr = f->sampleRate; + p->f = f; + p->channels = channels; + stop_audio(); + init_audio( + p, + sr, + channels + ); +} + #define DR_FLAC_IMPLEMENTATION #include "dr_flac.h" diff --git a/library.h b/library.h index e94c10a..1397c15 100644 --- a/library.h +++ b/library.h @@ -16,6 +16,17 @@ typedef struct { int cap, cnt; } Library; +typedef struct { + Song* song; + void* f; + int + seek, + samples, + channels, + play + ; +} Player; + void build_library( Arena* a, Library* lib, @@ -23,5 +34,7 @@ void build_library( ); int get_song_meta(const char* path, Song* s); +void play_song(Player* p, Song* song); +void init_player(Player* p); #endif diff --git a/main.c b/main.c index c350331..94f78b5 100644 --- a/main.c +++ b/main.c @@ -5,6 +5,7 @@ #include "memory.h" Library lib; +Player pl; int libtab_msg( UIElement *el, @@ -12,9 +13,9 @@ int libtab_msg( int di, void *dp ) { + Song* song; if (msg == UI_MSG_TABLE_GET_ITEM) { UITableGetItem *m = (UITableGetItem*)dp; - Song* song; song = &lib.songs[lib.indices[m->index]]; m->isSelected = 0; switch (m->column) { @@ -48,6 +49,15 @@ int libtab_msg( ); default: return 0; } + } else if (msg == UI_MSG_LEFT_UP) { + int hit = UITableHitTest( + (UITable*)el, + el->window->cursorX, + el->window->cursorY + ); + song = &lib.songs[lib.indices[hit]]; + init_player(&pl); + play_song(&pl, song); } return 0; } diff --git a/plat.c b/plat.c index c947b71..66dc50b 100644 --- a/plat.c +++ b/plat.c @@ -1,5 +1,6 @@ -#include "plat.h" #include "config.h" +#include "memory.h" +#include "plat.h" #ifdef plat_posix #define _POSIX_SOURCE @@ -10,6 +11,7 @@ #include #include #include +#include extern int fileno(FILE*); @@ -91,11 +93,100 @@ void iter_dir(const char* path, Dir_Iter fn, void* u) { closedir(di); } +pthread_t audio_thread; +pthread_mutex_t audio_mutex; + +#define inline /* erm sir we are using C90 here... */ +#include + +struct { + unsigned char* buf; + pa_simple* dev; + int chan, r; +} audio; + +extern int sound_mix(void*, unsigned char*, int); + +void* audio_worker(void* arg) { + const int s = audio_buffer_size; + int c = 1, as; + unsigned char* buf = audio.buf; + pa_simple* dev = audio.dev; + (void)arg; + while (c) { + lock_audio(); + if (!audio.r) c = 0; + as = sound_mix(arg, buf, s); + if (!as) audio.r = c = 0; + unlock_audio(); + pa_simple_write(dev, buf, as, 0); + } + return 0; +} + +void stop_audio(void) { + lock_audio(); + audio.r = 0; + unlock_audio(); +} + +void wait_audio(void) { + pthread_mutex_destroy(&audio_mutex); + pthread_join(audio_thread, 0); +} + +void init_audio(void* uptr, int sample, int channels) { + int r; + if (audio.dev) { + wait_audio(); + gfree(audio.buf); + } + audio.buf = galloc(audio_buffer_size * channels); + pa_sample_spec sp = { 0 }; + sp.format = PA_SAMPLE_S32LE; + sp.channels = channels; + sp.rate = sample; + audio.dev = pa_simple_new( + 0, + app_name, + PA_STREAM_PLAYBACK, + 0, + "Twink Player audio", + &sp, + 0, + 0, + 0 + ); + audio.r = 0; + if (!audio.dev) { + print_err("Failed to create audio device.\n"); + return; + } + audio.r = 1; + audio.chan = channels; + r = pthread_create( + &audio_thread, + 0, + audio_worker, + uptr + ); + pthread_mutex_init(&audio_mutex, 0); +} + +void lock_audio() { + pthread_mutex_lock(&audio_mutex); +} + +void unlock_audio() { + pthread_mutex_unlock(&audio_mutex); +} + extern int prog_main(void*); int main() { int r; void* mem; + audio.dev = 0; mem = malloc(memory_size); r = prog_main(mem); free(mem); diff --git a/plat.h b/plat.h index f001d70..3119543 100644 --- a/plat.h +++ b/plat.h @@ -11,4 +11,10 @@ void pbreak(Error code); typedef void (*Dir_Iter)(void* uptr, const char* path); void iter_dir(const char* path, Dir_Iter fn, void* u); +void init_audio(void* uptr, int sample, int channels); +void lock_audio(void); +void wait_audio(void); +void unlock_audio(void); +void stop_audio(void); + #endif -- cgit v1.2.3-54-g00ecf