aboutsummaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'gtk')
-rw-r--r--gtk/Makefile.am17
-rw-r--r--gtk/configure.ac23
-rw-r--r--gtk/soundout/alsaout.c152
-rw-r--r--gtk/soundout/alsaout.h9
-rw-r--r--gtk/soundout/jackout.c127
-rw-r--r--gtk/soundout/jackout.h9
-rw-r--r--gtk/soundout/ossout.c8
-rw-r--r--gtk/soundout/pulseout.c133
-rw-r--r--gtk/soundout/pulseout.h9
-rw-r--r--gtk/soundout/soundout.c14
-rw-r--r--gtk/soundout/soundout.h16
11 files changed, 32 insertions, 485 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 43a767d..2375b28 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -19,15 +19,22 @@ FMDSP_SRC=../fmdsp/fmdsp.c \
../fmdsp/font_fmdsp_small.c \
../fmdsp/fmdsp_platform_unix.c
-SOUNDOUT_SRC=soundout/soundout.c \
- soundout/pulseout.c \
- soundout/jackout.c \
- soundout/alsaout.c
+SOUNDOUT_SRC=../soundout/soundout.c
+
+if ENABLE_JACK
+SOUNDOUT_SRC+=../soundout/jackout.c
+endif
+if ENABLE_PULSE
+SOUNDOUT_SRC+=../soundout/pulseout.c
+endif
+if ENABLE_ALSA
+SOUNDOUT_SRC+=../soundout/alsaout.c
+endif
#fmplayer_CFLAGS=$(CFLAGS)
#CFLAGS=
fmplayer_CPPFLAGS=-Wall -Wextra -pedantic \
- -I.. -Isoundout \
+ -I.. -I../soundout \
$(GTK3_CFLAGS) $(JACK_CFLAGS) $(PULSE_CFLAGS) $(ALSA_CFLAGS) $(SNDFILE_CFLAGS)
fmplayer_LDADD=$(GTK3_LIBS) $(JACK_LIBS) $(PULSE_LIBS) $(ALSA_LIBS) $(SNDFILE_LIBS) -lm -lpthread
diff --git a/gtk/configure.ac b/gtk/configure.ac
index 8a61ac1..fc79c8c 100644
--- a/gtk/configure.ac
+++ b/gtk/configure.ac
@@ -6,12 +6,29 @@ AC_PROG_RANLIB
AM_PROG_AR
AM_PROG_AS
-PKG_CHECK_MODULES([JACK], [jack soxr])
-PKG_CHECK_MODULES([PULSE], [libpulse])
-PKG_CHECK_MODULES([ALSA], [alsa])
+PKG_CHECK_MODULES([JACK], [jack soxr], [jack_found=yes], [jack_found=no])
+PKG_CHECK_MODULES([PULSE], [libpulse], [pulse_found=yes], [pulse_found=no])
+PKG_CHECK_MODULES([ALSA], [alsa], [alsa_found=yes], [alsa_found=no])
PKG_CHECK_MODULES([GTK3], [gtk+-3.0 cairo])
PKG_CHECK_MODULES([SNDFILE], [sndfile])
+AS_IF([test "x$jack_found" = "xno" -a "x$pulse_found" = "xno" -a "x$alsa_found" = "xno"], [
+ AC_MSG_ERROR([No audio output backend found])
+])
+
+AM_CONDITIONAL([ENABLE_JACK], [test "x$jack_found" = "xyes"])
+AS_IF([test "x$jack_found" = "xyes"], [
+ AC_DEFINE([ENABLE_JACK])
+])
+AM_CONDITIONAL([ENABLE_PULSE], [test "x$pulse_found" = "xyes"])
+AS_IF([test "x$pulse_found" = "xyes"], [
+ AC_DEFINE([ENABLE_PULSE])
+])
+AM_CONDITIONAL([ENABLE_ALSA], [test "x$alsa_found" = "xyes"])
+AS_IF([test "x$alsa_found" = "xyes"], [
+ AC_DEFINE([ENABLE_ALSA])
+])
+
AC_ARG_ENABLE([neon], AS_HELP_STRING([--enable-neon], [Enable NEON optimized functions for SSG sinc filtering and fmdsp palette lookup. Tested on Cortex-A53 (Raspberry PI 3)]))
AM_CONDITIONAL([ENABLE_NEON], [test "x$enable_neon" = "xyes"])
AS_IF([test "x$enable_neon" = "xyes"], [
diff --git a/gtk/soundout/alsaout.c b/gtk/soundout/alsaout.c
deleted file mode 100644
index 5c5e667..0000000
--- a/gtk/soundout/alsaout.c
+++ /dev/null
@@ -1,152 +0,0 @@
-#include "alsaout.h"
-#include <stdbool.h>
-#include <stdatomic.h>
-#include <stdlib.h>
-#include <sys/eventfd.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <poll.h>
-#include <asoundlib.h>
-
-enum {
- BUF_FRAMES = 1024,
-};
-
-struct alsaout_state {
- struct sound_state ss;
- sound_callback cbfunc;
- void *userptr;
- snd_pcm_t *apcm;
- int fd_event;
- int fds_space;
- struct pollfd *fds;
- bool paused;
- bool terminate;
- atomic_flag cb_flag;
- bool thread_valid;
- pthread_t alsa_thread;
- int16_t buf[BUF_FRAMES*2];
-};
-
-static void *alsaout_thread(void *ptr) {
- struct alsaout_state *as = ptr;
- for (;;) {
- as->fds[0] = (struct pollfd) {
- .fd = as->fd_event,
- .events = POLLIN,
- };
- int fd_cnt = 1;
- fd_cnt += snd_pcm_poll_descriptors(
- as->apcm, as->fds + 1, as->fds_space - 1
- );
- int err = poll(as->fds, fd_cnt, -1);
- if (err <= 0) {
- continue;
- }
- if (as->terminate) return 0;
- if (as->fds[0].revents) {
- uint64_t eventdata;
- read(as->fd_event, &eventdata, sizeof(eventdata));
- }
- unsigned short event;
- if (snd_pcm_poll_descriptors_revents(
- as->apcm, as->fds + 1, fd_cnt - 1, &event) < 0) continue;
- if (!event) continue;
- snd_pcm_sframes_t frames = snd_pcm_avail_update(as->apcm);
- if (frames <= 0) continue;
- while (frames) {
- snd_pcm_sframes_t genframes = frames;
- if (genframes > BUF_FRAMES) genframes = BUF_FRAMES;
- while (atomic_flag_test_and_set_explicit(
- &as->cb_flag, memory_order_acquire));
- if (as->paused) {
- atomic_flag_clear_explicit(&as->cb_flag, memory_order_release);
- break;
- }
- as->cbfunc(as->userptr, as->buf, genframes);
- atomic_flag_clear_explicit(&as->cb_flag, memory_order_release);
- frames -= genframes;
- if (snd_pcm_state(as->apcm) == SND_PCM_STATE_XRUN) {
- err = snd_pcm_prepare(as->apcm);
- }
- snd_pcm_sframes_t written = snd_pcm_writei(as->apcm, as->buf, genframes);
- if (written < 0) {
- snd_pcm_prepare(as->apcm);
- }
- }
- }
-}
-
-static void alsaout_pause(struct sound_state *ss, int pause, int flush) {
- struct alsaout_state *as = (struct alsaout_state *)ss;
-
- while (atomic_flag_test_and_set_explicit(
- &as->cb_flag, memory_order_acquire));
- as->paused = pause;
- snd_pcm_pause(as->apcm, pause);
- atomic_flag_clear_explicit(&as->cb_flag, memory_order_release);
- uint64_t event = 1;
- write(as->fd_event, &event, sizeof(event));
-}
-
-static void alsaout_free(struct sound_state *ss) {
- if (!ss) return;
- struct alsaout_state *as = (struct alsaout_state *)ss;
- if (as->thread_valid) {
- as->terminate = true;
- uint64_t event = 1;
- write(as->fd_event, &event, sizeof(event));
- pthread_join(as->alsa_thread, 0);
- }
- if (as->fd_event != -1) {
- close(as->fd_event);
- }
- if (as->fds) free(as->fds);
- if (as->apcm) {
- snd_pcm_close(as->apcm);
- }
- free(as);
-}
-
-struct sound_state *alsaout_init(
- const char *clientname, unsigned srate,
- sound_callback cbfunc, void *userptr) {
- (void)clientname;
- struct alsaout_state *as = malloc(sizeof(*as));
- if (!as) goto err;
- *as = (struct alsaout_state) {
- .ss = {
- .pause = alsaout_pause,
- .free = alsaout_free,
- .apiname = "ALSA",
- },
- .cbfunc = cbfunc,
- .userptr = userptr,
- .fd_event = -1,
- .cb_flag = ATOMIC_FLAG_INIT,
- .paused = true,
- };
- if (snd_pcm_open(&as->apcm, "default", SND_PCM_STREAM_PLAYBACK, 0)) {
- goto err;
- }
- as->fd_event = eventfd(0, EFD_CLOEXEC);
- if (as->fd_event < 0) goto err;
- as->fds_space = snd_pcm_poll_descriptors_count(as->apcm) + 1;
- as->fds = malloc(sizeof(*as->fds) * as->fds_space);
- if (!as->fds) goto err;
- if (snd_pcm_set_params(
- as->apcm,
- SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 2, srate, 1,
- 1000*1000/60)) {
- goto err;
- }
- if (pthread_create(&as->alsa_thread, 0, alsaout_thread, as)) {
- goto err;
- }
- as->thread_valid = true;
- return as;
-
-err:
- alsaout_free(&as->ss);
- return 0;
-}
diff --git a/gtk/soundout/alsaout.h b/gtk/soundout/alsaout.h
deleted file mode 100644
index cd79c27..0000000
--- a/gtk/soundout/alsaout.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef MYON_ALSAOUT_H_INCLUDED
-#define MYON_ALSAOUT_H_INCLUDED
-
-#include "soundout.h"
-
-struct sound_state *alsaout_init(const char *clientname, unsigned srate, sound_callback cbfunc, void *userptr);
-
-#endif // MYON_ALSAOUT_H_INCLUDED
-
diff --git a/gtk/soundout/jackout.c b/gtk/soundout/jackout.c
deleted file mode 100644
index 54e7f16..0000000
--- a/gtk/soundout/jackout.c
+++ /dev/null
@@ -1,127 +0,0 @@
-#include "jackout.h"
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <jack/jack.h>
-#include <soxr.h>
-
-typedef jack_default_audio_sample_t sample_t;
-
-enum {
- RFRAMES = 1024,
- JFRAMES = 2048,
-};
-
-struct jackout_state {
- struct sound_state ss;
- sound_callback cbfunc;
- void *userptr;
- jack_client_t *jc;
- jack_port_t *jp[2];
- soxr_t soxr;
- bool paused;
- int16_t rbuf[RFRAMES*2];
- float jbuf[JFRAMES*2];
-};
-
-static size_t soxr_cb(void *ptr, soxr_in_t *data, size_t nframes) {
- struct jackout_state *js = ptr;
- if (nframes > RFRAMES) nframes = RFRAMES;
- for (size_t i = 0; i < RFRAMES*2; i++) {
- js->rbuf[i] = 0;
- }
- js->cbfunc(js->userptr, js->rbuf, nframes);
- *data = js->rbuf;
- return nframes;
-}
-
-static int jack_cb(jack_nframes_t nframes, void *arg) {
- struct jackout_state *js = arg;
- sample_t *out[2];
- for (int i = 0; i < 2; i++) out[i] = jack_port_get_buffer(js->jp[i], nframes);
- jack_nframes_t outi = 0;
- while (nframes) {
- jack_nframes_t pframes = nframes < JFRAMES ? nframes : JFRAMES;
- pframes = soxr_output(js->soxr, js->jbuf, pframes);
- for (jack_nframes_t j = 0; j < pframes; j++) {
- out[0][outi] = js->jbuf[j*2+0];
- out[1][outi] = js->jbuf[j*2+1];
- outi++;
- }
- nframes -= pframes;
- }
- return 0;
-}
-
-static void jackout_pause(struct sound_state *ss, int pause, int flush) {
- struct jackout_state *js = (struct jackout_state *)ss;
- // TODO
- if (js->paused && !pause) {
- if (flush) {
- soxr_clear(js->soxr);
- soxr_set_input_fn(js->soxr, soxr_cb, js, RFRAMES);
- }
- jack_activate(js->jc);
- jack_connect(js->jc, jack_port_name(js->jp[0]), "system:playback_1");
- jack_connect(js->jc, jack_port_name(js->jp[1]), "system:playback_2");
- } else if (!js->paused && pause) {
- jack_deactivate(js->jc);
- }
- js->paused = pause;
-}
-
-static void jackout_free(struct sound_state *ss) {
- struct jackout_state *js = (struct jackout_state *)ss;
- if (js) {
- if (js->jc) {
- for (int i = 0; i < 2; i++) {
- if (js->jp[i]) jack_port_unregister(js->jc, js->jp[i]);
- }
- jack_client_close(js->jc);
- }
- if (js->soxr) soxr_delete(js->soxr);
- free(js);
- }
-}
-
-struct sound_state *jackout_init(
- const char *clientname, unsigned srate,
- sound_callback cbfunc, void *userptr) {
- struct jackout_state *js = malloc(sizeof(*js));
- if (!js) goto err;
- *js = (struct jackout_state){
- .ss = {
- .pause = jackout_pause,
- .free = jackout_free,
- .apiname = "JACK Audio",
- },
- .cbfunc = cbfunc,
- .userptr = userptr,
- .paused = true,
- };
- js->jc = jack_client_open(clientname, 0, 0);
- if (!js->jc) goto err;
- for (int i = 0; i < 2; i++) {
- js->jp[i] = jack_port_register(
- js->jc, i ? "right" : "left", JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsOutput | JackPortIsTerminal, 0);
- if (!js->jp[i]) goto err;
- }
- soxr_io_spec_t iospec = {
- .itype = SOXR_INT16_I,
- .otype = SOXR_FLOAT32_I,
- .scale = 1.0,
- };
- js->soxr = soxr_create(
- srate, jack_get_sample_rate(js->jc),
- 2, 0, &iospec, 0, 0
- );
- if (!js->soxr) goto err;
- soxr_set_input_fn(js->soxr, soxr_cb, js, RFRAMES);
- if (jack_set_process_callback(js->jc, jack_cb, js)) goto err;
-
- return &js->ss;
-err:
- jackout_free(&js->ss);
- return 0;
-}
diff --git a/gtk/soundout/jackout.h b/gtk/soundout/jackout.h
deleted file mode 100644
index 4b72f2e..0000000
--- a/gtk/soundout/jackout.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef MYON_JACKOUT_H_INCLUDED
-#define MYON_JACKOUT_H_INCLUDED
-
-#include "soundout.h"
-
-struct sound_state *jackout_init(const char *clientname, unsigned srate, sound_callback cbfunc, void *userptr);
-
-#endif // MYON_JACKOUT_H_INCLUDED
-
diff --git a/gtk/soundout/ossout.c b/gtk/soundout/ossout.c
deleted file mode 100644
index 1083f20..0000000
--- a/gtk/soundout/ossout.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <sys/stat.h>
-#include <fcntl.h>
-
-struct ossout_state {
- struct sound_state ss;
-};
-
-struct sound_state *ossout_init(
diff --git a/gtk/soundout/pulseout.c b/gtk/soundout/pulseout.c
deleted file mode 100644
index 9dbcd6c..0000000
--- a/gtk/soundout/pulseout.c
+++ /dev/null
@@ -1,133 +0,0 @@
-#include "pulseout.h"
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <pulse/thread-mainloop.h>
-#include <pulse/stream.h>
-
-struct pulseout_state {
- struct sound_state ss;
- bool paused;
- bool flush;
- unsigned srate;
- sound_callback cbfunc;
- void *userptr;
- pa_threaded_mainloop *pa_tm;
- pa_context *pa_c;
- pa_stream *pa_s;
- bool pa_status_changed;
-};
-
-static void pulseout_pause(struct sound_state *ss, int pause, int flush) {
- //return;
- struct pulseout_state *ps = (struct pulseout_state *)ss;
- if (ps->paused != !!pause) {
- if (pause) {
- pa_threaded_mainloop_lock(ps->pa_tm);
- }
- ps->paused = pause;
- if (!pause) {
- if (flush) ps->flush = true;
- pa_threaded_mainloop_unlock(ps->pa_tm);
- }
- }
-}
-
-static void pulseout_free(struct sound_state *ss) {
- struct pulseout_state *ps = (struct pulseout_state *)ss;
- if (ps) {
- if (ps->pa_tm) {
- if (ps->paused) pa_threaded_mainloop_unlock(ps->pa_tm);
- pa_threaded_mainloop_stop(ps->pa_tm);
- if (ps->pa_s) {
- pa_stream_disconnect(ps->pa_s);
- pa_stream_unref(ps->pa_s);
- }
- if (ps->pa_c) pa_context_unref(ps->pa_c);
- pa_threaded_mainloop_free(ps->pa_tm);
- }
- free(ps);
- }
-}
-
-static void pulseout_cb(pa_stream *p, size_t bytes, void *userdata) {
- struct pulseout_state *ps = userdata;
- int16_t *buf;
- pa_stream_begin_write(p, (void **)&buf, &bytes);
- size_t nframes = bytes / (2 * sizeof(int16_t));
- if (!ps->paused) {
- ps->cbfunc(ps->userptr, buf, nframes);
- } else {
- for (size_t i = 0; i < nframes; i++) {
- buf[i*2+0] = 0;
- buf[i*2+1] = 0;
- }
- }
- pa_seek_mode_t smode =
- ps->flush ? PA_SEEK_RELATIVE_ON_READ : PA_SEEK_RELATIVE;
- pa_stream_write(p, buf, nframes * 2 * sizeof(int16_t), 0, 0, smode);
- ps->flush = false;
-}
-
-static void pa_c_cb(pa_context *pa_c, void *userdata) {
- struct pulseout_state *ps = userdata;
- ps->pa_status_changed = true;
- pa_threaded_mainloop_signal(ps->pa_tm, 0);
-}
-
-struct sound_state *pulseout_init(
- const char *clientname, unsigned srate,
- sound_callback cbfunc, void *userptr) {
- struct pulseout_state *ps = malloc(sizeof(*ps));
- if (!ps) goto err;
- *ps = (struct pulseout_state){
- .ss = {
- .pause = pulseout_pause,
- .free = pulseout_free,
- .apiname = "PulseAudio",
- },
- .cbfunc = cbfunc,
- .userptr = userptr,
- .paused = false,
- .srate = srate,
- };
- ps->pa_tm = pa_threaded_mainloop_new();
- if (!ps->pa_tm) goto err;
- ps->pa_c = pa_context_new(
- pa_threaded_mainloop_get_api(ps->pa_tm), clientname
- );
- if (!ps->pa_c) goto err;
- if (pa_context_connect(ps->pa_c, 0, 0, 0) < 0) goto err;
- pa_context_set_state_callback(ps->pa_c, pa_c_cb, ps);
- if (pa_threaded_mainloop_start(ps->pa_tm) < 0) goto err;
- pa_threaded_mainloop_lock(ps->pa_tm);
- ps->paused = true;
- for (;;) {
- while (!ps->pa_status_changed) {
- pa_threaded_mainloop_wait(ps->pa_tm);
- }
- ps->pa_status_changed = false;
- pa_context_state_t state = pa_context_get_state(ps->pa_c);
- if (state == PA_CONTEXT_CONNECTING ||
- state == PA_CONTEXT_AUTHORIZING ||
- state == PA_CONTEXT_SETTING_NAME) continue;
- else if (state == PA_CONTEXT_READY) break;
- else goto err;
- }
- pa_sample_spec ss = {
- .format = PA_SAMPLE_S16NE,
- .rate = ps->srate,
- .channels = 2,
- };
- ps->pa_s = pa_stream_new(
- ps->pa_c,
- "stereoout", &ss, 0
- );
- if (!ps->pa_s) goto err;
- pa_stream_set_write_callback(ps->pa_s, pulseout_cb, ps);
- if (pa_stream_connect_playback(ps->pa_s, 0, 0, 0, 0, 0) < 0) goto err;
- return &ps->ss;
-err:
- pulseout_free(&ps->ss);
- return 0;
-}
diff --git a/gtk/soundout/pulseout.h b/gtk/soundout/pulseout.h
deleted file mode 100644
index d9fbb20..0000000
--- a/gtk/soundout/pulseout.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef MYON_PULSEOUT_H_INCLUDED
-#define MYON_PULSEOUT_H_INCLUDED
-
-#include "soundout.h"
-
-struct sound_state *pulseout_init(const char *clientname, unsigned srate, sound_callback cbfunc, void *userptr);
-
-#endif // MYON_PULSEOUT_H_INCLUDED
-
diff --git a/gtk/soundout/soundout.c b/gtk/soundout/soundout.c
deleted file mode 100644
index 56134be..0000000
--- a/gtk/soundout/soundout.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "soundout.h"
-#include "jackout.h"
-#include "pulseout.h"
-#include "alsaout.h"
-
-struct sound_state *sound_init(const char *clientname, unsigned srate, sound_callback cbfunc, void *userptr) {
- struct sound_state *ss = 0;
- //ss = jackout_init(clientname, srate, cbfunc, userptr);
- if (ss) return ss;
- //ss = pulseout_init(clientname, srate, cbfunc, userptr);
- if (ss) return ss;
- ss = alsaout_init(clientname, srate, cbfunc, userptr);
- return ss;
-}
diff --git a/gtk/soundout/soundout.h b/gtk/soundout/soundout.h
deleted file mode 100644
index aea926f..0000000
--- a/gtk/soundout/soundout.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef MYON_SOUNDOUT_H_INCLUDED
-#define MYON_SOUNDOUT_H_INCLUDED
-
-#include <stdint.h>
-
-typedef void (*sound_callback)(void *userptr, int16_t *buf, unsigned frames);
-
-struct sound_state {
- void (*pause)(struct sound_state *state, int pause, int flush);
- void (*free)(struct sound_state *state);
- const char *apiname;
-};
-
-struct sound_state *sound_init(const char *clientname, unsigned srate, sound_callback cbfunc, void *userptr);
-
-#endif // MYON_SOUNDOUT_H_INCLUDED