summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--config.h3
-rw-r--r--library.c48
-rw-r--r--library.h13
-rw-r--r--main.c12
-rw-r--r--plat.c93
-rw-r--r--plat.h6
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 <string.h>
@@ -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 <stdlib.h>
#include <dirent.h>
#include <string.h>
+#include <pthread.h>
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 <pulse/simple.h>
+
+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