summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJari Vetoniemi <mailroxas@gmail.com>2018-10-31 08:33:00 +0200
committerJari Vetoniemi <mailroxas@gmail.com>2018-10-31 08:33:00 +0200
commite73e63d4eb46b865b8565909b04ad2894bf027f8 (patch)
tree41f5400bf3ee396f9e929ee8e01ebe765dd85690
parentc7e59084ac09028af7fd81c9fc40f9c55fb30857 (diff)
refactor project structure
libasound.c started to become quite large, split the big chunks into pcm.c and mixer.c
-rw-r--r--Makefile2
-rw-r--r--gen-stubs.bash2
-rw-r--r--src/libasound.c173
-rw-r--r--src/mixer.c264
-rw-r--r--src/pcm.c (renamed from libasound.c)460
-rw-r--r--src/stubs.h (renamed from stubs.h)0
-rw-r--r--src/symversioning-hell.h (renamed from symversioning-hell.h)0
-rw-r--r--src/util/defs.h (renamed from dsp/defs.h)0
-rw-r--r--src/util/dsp.c (renamed from dsp/dsp.c)0
-rw-r--r--src/util/dsp.h (renamed from dsp/dsp.h)0
-rw-r--r--src/util/sysex.h (renamed from sysex.h)0
-rw-r--r--src/util/util.h29
12 files changed, 471 insertions, 459 deletions
diff --git a/Makefile b/Makefile
index 0786c76..42b6414 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ libasound.so.2.0.0: private override CPPFLAGS += -DBYTE_ORDER=__BYTE_ORDER -DLIT
libasound.so.2.0.0: private override CFLAGS += -Wno-unused-parameter -Wno-deprecated-declarations
libasound.so.2.0.0: private override LDFLAGS += -Wl,--version-script=libasound.map -Wl,-soname,libasound.so.2
libasound.so.2.0.0: private override LDLIBS += -lsndio
-libasound.so.2.0.0: libasound.c dsp/dsp.c libasound.map stubs.h symversioning-hell.h
+libasound.so.2.0.0: src/libasound.c src/pcm.c src/mixer.c src/util/dsp.c src/util/dsp.h src/util/sysex.h src/util/defs.h src/util/util.h src/stubs.h src/symversioning-hell.h libasound.map
$(LINK.c) -shared $(filter %.c,$^) $(LDLIBS) -o $@
libasound.so.2: libasound.so.2.0.0
diff --git a/gen-stubs.bash b/gen-stubs.bash
index cd5a6cb..0b9886b 100644
--- a/gen-stubs.bash
+++ b/gen-stubs.bash
@@ -76,5 +76,5 @@ preprocess()
cat include/alsa/*.h | preprocess | match | tr -d ';' | while read -r fun; do
name="$(fun_name_for "$fun")"
- grep -Fqs "$name(" libasound.c || printf '%s { WARNX1("stub"); %s }\n' "$fun" "$(return_for "$fun" "$name")"
+ grep -Fqs "$name(" src/{libasound,pcm,mixer}.c || printf '%s { WARNX1("stub"); %s }\n' "$fun" "$(return_for "$fun" "$name")"
done
diff --git a/src/libasound.c b/src/libasound.c
new file mode 100644
index 0000000..b43ae95
--- /dev/null
+++ b/src/libasound.c
@@ -0,0 +1,173 @@
+#include <alsa/asoundlib.h>
+#include <alsa/pcm.h>
+#include <alsa/pcm_plugin.h>
+#include <alsa/pcm_extplug.h>
+#include <alsa/pcm_ioplug.h>
+#include <alsa/control_external.h>
+#include <alsa/mixer_abst.h>
+#include <alsa/use-case.h>
+#include <alsa/topology.h>
+
+#include "util/util.h"
+#include "stubs.h"
+#include "symversioning-hell.h"
+
+struct _snd_config { char noop; } s_snd_config;
+struct _snd_config *snd_config = &s_snd_config;
+
+const char*
+snd_asoundlib_version(void)
+{
+ return "1.1.7";
+}
+
+const char*
+snd_strerror(int errnum)
+{
+ // Do not bother implementing this, just WARN/ERR directly in this lib
+ // Letting applications show useful error messages never works out
+ return "^";
+}
+
+snd_lib_error_handler_t snd_lib_error;
+
+int snd_lib_error_set_handler(snd_lib_error_handler_t handler)
+{
+ snd_lib_error = handler;
+ return 0;
+}
+
+int
+snd_card_load(int card)
+{
+ return 0;
+}
+
+int
+snd_card_next(int *card)
+{
+ if (card) {
+ *card = (*card == -1 ? 0 : -1);
+ return 0;
+ }
+
+ return -1;
+}
+
+int
+snd_card_get_index(const char *name)
+{
+ if (!strcmp(name, "default"))
+ return 0;
+
+ return -1;
+}
+
+int
+snd_card_get_name(int card, char **name)
+{
+ if (name) *name = "default";
+ return 0;
+}
+
+int snd_card_get_longname(int card, char **name)
+{
+ if (name) *name = "default";
+ return 0;
+}
+
+struct device_name_hint { char *name, *ioid; };
+
+int
+snd_device_name_hint(int card, const char *iface, void ***hints)
+{
+ static struct device_name_hint defaults[] = { { .name = "default", .ioid = "Output" }, { .name = "capture", .ioid = "Input" } };
+ static struct device_name_hint *array[] = { &defaults[0], &defaults[1], NULL };
+ *hints = (void**)array;
+ return 0;
+}
+
+char*
+snd_device_name_get_hint(const void *hint, const char *id)
+{
+ const struct device_name_hint *shint = hint;
+
+ if (!strcmp(id, "NAME"))
+ return c_strdup(shint->name);
+ else if (!strcmp(id, "IOID"))
+ return c_strdup(shint->ioid);
+
+ return NULL;
+}
+
+int
+snd_device_name_free_hint(void **hints)
+{
+ return 0;
+}
+
+struct _snd_ctl {
+ char noop;
+};
+
+int
+snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode)
+{
+ if (!(*ctl = calloc(1, sizeof(**ctl)))) {
+ WARNX1("calloc");
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+snd_ctl_close(snd_ctl_t *ctl)
+{
+ free(ctl);
+ return 0;
+}
+
+struct _snd_ctl_card_info {
+ const char *name;
+};
+
+size_t
+snd_ctl_card_info_sizeof(void)
+{
+ return sizeof(snd_ctl_card_info_t);
+}
+
+int
+snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr)
+{
+ if (!(*ptr = calloc(1, sizeof(**ptr))))
+ return -1;
+
+ return 0;
+}
+
+void
+snd_ctl_card_info_free(snd_ctl_card_info_t *obj)
+{
+ free(obj);
+}
+
+int
+snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)
+{
+ info->name = "sndio";
+ return 0;
+}
+
+const char*
+snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj)
+{
+ return obj->name;
+}
+
+const char*
+snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj)
+{
+ return obj->name;
+}
diff --git a/src/mixer.c b/src/mixer.c
new file mode 100644
index 0000000..317f12c
--- /dev/null
+++ b/src/mixer.c
@@ -0,0 +1,264 @@
+#include <alsa/asoundlib.h>
+#include <sndio.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include "util/sysex.h"
+#include "util/util.h"
+
+struct _snd_mixer_elem {
+ snd_mixer_elem_t *next;
+ char name[SYSEX_NAMELEN];
+ unsigned int index, vol;
+};
+
+struct _snd_mixer {
+ struct mio_hdl *hdl;
+ snd_mixer_elem_t *controls;
+};
+
+#define MIXER_MAX_CHANNELS 16
+
+static bool
+onsysex(unsigned char *buf, unsigned len, snd_mixer_elem_t controls[MIXER_MAX_CHANNELS + 1])
+{
+ if (len < SYSEX_SIZE(empty))
+ return false;
+
+ union {
+ struct sysex x;
+ unsigned char buf[sizeof(struct sysex)];
+ } u;
+
+ memcpy(u.buf, buf, len);
+
+ if (u.x.type == SYSEX_TYPE_RT && u.x.id0 == SYSEX_CONTROL && u.x.id1 == SYSEX_MASTER) {
+ if (len == SYSEX_SIZE(master)) {
+ controls[0].vol = u.x.u.master.coarse;
+ snprintf(controls[0].name, sizeof(controls[0].name), "master");
+ }
+ return false;
+ }
+
+ if (u.x.type != SYSEX_TYPE_EDU || u.x.id0 != SYSEX_AUCAT)
+ return false;
+
+ switch (u.x.id1) {
+ case SYSEX_AUCAT_MIXINFO: {
+ unsigned cn = u.x.u.mixinfo.chan;
+ if (cn >= MIXER_MAX_CHANNELS || !memchr(u.x.u.mixinfo.name, '\0', SYSEX_NAMELEN))
+ return false;
+
+ snprintf(controls[cn + 1].name, sizeof(controls[cn + 1].name), "%s", u.x.u.mixinfo.name);
+ break;
+ }
+
+ case SYSEX_AUCAT_DUMPEND:
+ return true;
+ }
+
+ return false;
+}
+
+static void
+oncommon(unsigned char *buf, unsigned len, snd_mixer_elem_t controls[MIXER_MAX_CHANNELS + 1])
+{
+#define MIDI_CMDMASK 0xf0
+#define MIDI_CTL 0xb0
+#define MIDI_CTLVOL 7
+ if ((buf[0] & MIDI_CMDMASK) != MIDI_CTL || buf[1] != MIDI_CTLVOL)
+ return;
+
+#define MIDI_CHANMASK 0x0f
+ unsigned cn = (buf[0] & MIDI_CHANMASK);
+ if (cn >= MIXER_MAX_CHANNELS)
+ return;
+
+ controls[cn + 1].vol = buf[2];
+}
+
+static void
+get_controls(snd_mixer_t *mixer)
+{
+ const unsigned char dumpreq[] = {
+ SYSEX_START,
+ SYSEX_TYPE_EDU,
+ 0,
+ SYSEX_AUCAT,
+ SYSEX_AUCAT_DUMPREQ,
+ SYSEX_END,
+ };
+
+ static snd_mixer_elem_t controls[MIXER_MAX_CHANNELS + 1];
+ memset(controls, 0, sizeof(controls));
+
+ unsigned char buf[0x100];
+ mio_write(mixer->hdl, dumpreq, sizeof(dumpreq));
+ for (int ready = 0; !ready;) {
+ size_t size;
+ if (!(size = mio_read(mixer->hdl, buf, sizeof(buf)))) {
+ WARNX1("mio_read failed");
+ return;
+ }
+
+ static unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
+ static unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
+
+ unsigned char mmsg[0x100];
+ unsigned int mst = 0, midx = 0, mlen = 0;
+ for (unsigned char *p = buf; size > 0; --size, ++p) {
+ if (*p >= 0xf8) {
+ /* clock events */
+ } else if (*p >= 0xf0) {
+ if (mst == SYSEX_START && *p == SYSEX_END && midx < sizeof(mmsg)) {
+ mmsg[midx++] = *p;
+ ready = onsysex(mmsg, midx, controls);
+ continue;
+ }
+
+ mmsg[0] = *p;
+ mlen = common_len[*p & 7];
+ mst = *p;
+ midx = 1;
+ } else if (*p >= 0x80) {
+ mmsg[0] = *p;
+ mlen = voice_len[(*p >> 4) & 7];
+ mst = *p;
+ midx = 1;
+ } else if (mst) {
+ if (midx == sizeof(mmsg))
+ continue;
+
+ if (midx == 0)
+ mmsg[midx++] = mst;
+
+ mmsg[midx++] = *p;
+
+ if (midx == mlen) {
+ oncommon(mmsg, midx, controls);
+ midx = 0;
+ }
+ }
+ }
+ }
+
+ snd_mixer_elem_t **tail = &mixer->controls;
+ for (size_t i = 0; i < ARRAY_SIZE(controls); ++i) {
+ if (!controls[i].name[0])
+ continue;
+
+ *tail = &controls[i];
+ tail = &(*tail)->next;
+ }
+}
+
+int
+snd_mixer_open(snd_mixer_t **mixer, int mode)
+{
+ if (!(*mixer = calloc(1, sizeof(**mixer)))) {
+ WARNX1("calloc");
+ return -1;
+ }
+
+ if (!((*mixer)->hdl = mio_open("snd/0", MIO_OUT | MIO_IN, 0))) {
+ WARNX1("mio_open failed");
+ goto fail;
+ }
+
+ get_controls(*mixer);
+ return 0;
+
+fail:
+ free(*mixer);
+ return -1;
+}
+
+int
+snd_mixer_close(snd_mixer_t *mixer)
+{
+ mio_close(mixer->hdl);
+ free(mixer);
+ return 0;
+}
+
+struct _snd_mixer_selem_id {
+ char noop;
+};
+
+int
+snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr)
+{
+ if (!(*ptr = calloc(1, sizeof(**ptr))))
+ return -1;
+
+ return 0;
+}
+
+void
+snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj)
+{
+ free(obj);
+}
+
+snd_mixer_elem_t*
+snd_mixer_first_elem(snd_mixer_t *mixer)
+{
+ return mixer->controls;
+}
+
+snd_mixer_elem_t*
+snd_mixer_elem_next(snd_mixer_elem_t *elem)
+{
+ return elem->next;
+}
+
+const char*
+snd_mixer_selem_get_name(snd_mixer_elem_t *elem)
+{
+ return elem->name;
+}
+
+int
+snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+{
+ if (value) *value = ((float)elem->vol / (float)0x7f) * 100;
+ return 0;
+}
+
+int
+snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
+{
+ if (value) *value = (long)elem->vol - 0x7f;
+ return 0;
+}
+
+int
+snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, long *min, long *max)
+{
+ if (max) *max = 0;
+ if (min) *min = -127;
+ return 0;
+}
+
+int
+snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem)
+{
+ return true;
+}
+
+int
+snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem)
+{
+ return true;
+}
+
+int
+snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem)
+{
+ return true;
+}
+
+int
+snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem)
+{
+ return true;
+}
diff --git a/libasound.c b/src/pcm.c
index c39f4b6..ad77c06 100644
--- a/libasound.c
+++ b/src/pcm.c
@@ -1,138 +1,10 @@
#include <alsa/asoundlib.h>
-#include <alsa/pcm.h>
-#include <alsa/pcm_plugin.h>
-#include <alsa/pcm_extplug.h>
-#include <alsa/pcm_ioplug.h>
-#include <alsa/control_external.h>
-#include <alsa/mixer_abst.h>
-#include <alsa/use-case.h>
-#include <alsa/topology.h>
-
#include <sndio.h>
+#include <poll.h>
#include <stdbool.h>
#include <assert.h>
-#include <err.h>
-#include <poll.h>
-
-#include "dsp/dsp.h"
-#include "sysex.h"
-
-#define WARN1(x) do { warn("asound: %s %s", __func__, x); } while (0)
-#define WARN(x, ...) do { warn("asound: %s " x, __func__, ##__VA_ARGS__); } while (0)
-#define WARNX1(x) do { warnx("asound: %s %s", __func__, x); } while (0)
-#define WARNX(x, ...) do { warnx("asound: %s " x, __func__, ##__VA_ARGS__); } while (0)
-#define ERRX1(x, y) do { errx(x, "asound: %s %s", __func__, y); } while (0)
-#define ERRX(x, y, ...) do { errx(x, "asound: %s " y, __func__, ##__VA_ARGS__); } while (0)
-#define ERR(x, y, ...) do { err(x, "asound: %s " y, __func__, ##__VA_ARGS__); } while (0)
-
-#include "stubs.h"
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-const char*
-snd_asoundlib_version(void)
-{
- return "1.1.7";
-}
-
-const char*
-snd_strerror(int errnum)
-{
- // Do not bother implementing this, just WARN/ERR directly in this lib
- // Letting applications show useful error messages never works out
- return "^";
-}
-
-snd_lib_error_handler_t snd_lib_error;
-
-int snd_lib_error_set_handler(snd_lib_error_handler_t handler)
-{
- snd_lib_error = handler;
- return 0;
-}
-
-struct _snd_config { char noop; } s_snd_config;
-struct _snd_config *snd_config = &s_snd_config;
-
-int
-snd_card_load(int card)
-{
- return 0;
-}
-
-int
-snd_card_next(int *card)
-{
- if (card) {
- *card = (*card == -1 ? 0 : -1);
- return 0;
- }
- return -1;
-}
-
-int
-snd_card_get_index(const char *name)
-{
- if (!strcmp(name, "default"))
- return 0;
- return -1;
-}
-
-int
-snd_card_get_name(int card, char **name)
-{
- if (name) *name = "default";
- return 0;
-}
-
-int snd_card_get_longname(int card, char **name)
-{
- if (name) *name = "default";
- return 0;
-}
-
-struct _snd_pcm_hint { char *name, *ioid; };
-
-int
-snd_device_name_hint(int card, const char *iface, void ***hints)
-{
- static struct _snd_pcm_hint defaults[] = { { .name = "default", .ioid = "Output" }, { .name = "capture", .ioid = "Input" } };
- static struct _snd_pcm_hint *array[] = { &defaults[0], &defaults[1], NULL };
- *hints = (void**)array;
- return 0;
-}
-
-static char*
-c_strdup(const char *str)
-{
- size_t len = strlen(str);
-
- char *copy;
- if (!(copy = calloc(1, len + 1)))
- return NULL;
-
- memcpy(copy, str, len);
- return copy;
-}
-
-char*
-snd_device_name_get_hint(const void *hint, const char *id)
-{
- const struct _snd_pcm_hint *shint = hint;
-
- if (!strcmp(id, "NAME"))
- return c_strdup(shint->name);
- else if (!strcmp(id, "IOID"))
- return c_strdup(shint->ioid);
-
- return NULL;
-}
-
-int
-snd_device_name_free_hint(void **hints)
-{
- return 0;
-}
+#include "util/dsp.h"
+#include "util/util.h"
struct _snd_pcm_hw_params {
struct sio_cap cap;
@@ -1036,329 +908,3 @@ snd_pcm_get_chmap(snd_pcm_t *pcm)
return map;
}
-
-struct _snd_ctl {
- char noop;
-};
-
-int
-snd_ctl_open(snd_ctl_t **ctl, const char *name, int mode)
-{
- if (!(*ctl = calloc(1, sizeof(**ctl)))) {
- WARNX1("calloc");
- return -1;
- }
-
- return 0;
-}
-
-int
-snd_ctl_close(snd_ctl_t *ctl)
-{
- free(ctl);
- return 0;
-}
-
-struct _snd_ctl_card_info {
- const char *name;
-};
-
-size_t
-snd_ctl_card_info_sizeof(void)
-{
- return sizeof(snd_ctl_card_info_t);
-}
-
-int
-snd_ctl_card_info_malloc(snd_ctl_card_info_t **ptr)
-{
- if (!(*ptr = calloc(1, sizeof(**ptr))))
- return -1;
-
- return 0;
-}
-
-void
-snd_ctl_card_info_free(snd_ctl_card_info_t *obj)
-{
- free(obj);
-}
-
-int
-snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)
-{
- info->name = "sndio";
- return 0;
-}
-
-const char*
-snd_ctl_card_info_get_name(const snd_ctl_card_info_t *obj)
-{
- return obj->name;
-}
-
-const char*
-snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj)
-{
- return obj->name;
-}
-
-struct _snd_mixer_elem {
- snd_mixer_elem_t *next;
- char name[SYSEX_NAMELEN];
- unsigned int index, vol;
-};
-
-struct _snd_mixer {
- struct mio_hdl *hdl;
- snd_mixer_elem_t *controls;
-};
-
-#define MIXER_MAX_CHANNELS 16
-
-static bool
-onsysex(unsigned char *buf, unsigned len, snd_mixer_elem_t controls[MIXER_MAX_CHANNELS + 1])
-{
- if (len < SYSEX_SIZE(empty))
- return false;
-
- union {
- struct sysex x;
- unsigned char buf[sizeof(struct sysex)];
- } u;
-
- memcpy(u.buf, buf, len);
-
- if (u.x.type == SYSEX_TYPE_RT && u.x.id0 == SYSEX_CONTROL && u.x.id1 == SYSEX_MASTER) {
- if (len == SYSEX_SIZE(master)) {
- controls[0].vol = u.x.u.master.coarse;
- snprintf(controls[0].name, sizeof(controls[0].name), "master");
- }
- return false;
- }
-
- if (u.x.type != SYSEX_TYPE_EDU || u.x.id0 != SYSEX_AUCAT)
- return false;
-
- switch (u.x.id1) {
- case SYSEX_AUCAT_MIXINFO: {
- unsigned cn = u.x.u.mixinfo.chan;
- if (cn >= MIXER_MAX_CHANNELS || !memchr(u.x.u.mixinfo.name, '\0', SYSEX_NAMELEN))
- return false;
-
- snprintf(controls[cn + 1].name, sizeof(controls[cn + 1].name), "%s", u.x.u.mixinfo.name);
- break;
- }
-
- case SYSEX_AUCAT_DUMPEND:
- return true;
- }
-
- return false;
-}
-
-static void
-oncommon(unsigned char *buf, unsigned len, snd_mixer_elem_t controls[MIXER_MAX_CHANNELS + 1])
-{
-#define MIDI_CMDMASK 0xf0
-#define MIDI_CTL 0xb0
-#define MIDI_CTLVOL 7
- if ((buf[0] & MIDI_CMDMASK) != MIDI_CTL || buf[1] != MIDI_CTLVOL)
- return;
-
-#define MIDI_CHANMASK 0x0f
- unsigned cn = (buf[0] & MIDI_CHANMASK);
- if (cn >= MIXER_MAX_CHANNELS)
- return;
-
- controls[cn + 1].vol = buf[2];
-}
-
-static void
-get_controls(snd_mixer_t *mixer)
-{
- const unsigned char dumpreq[] = {
- SYSEX_START,
- SYSEX_TYPE_EDU,
- 0,
- SYSEX_AUCAT,
- SYSEX_AUCAT_DUMPREQ,
- SYSEX_END,
- };
-
- static snd_mixer_elem_t controls[MIXER_MAX_CHANNELS + 1];
- memset(controls, 0, sizeof(controls));
-
- unsigned char buf[0x100];
- mio_write(mixer->hdl, dumpreq, sizeof(dumpreq));
- for (int ready = 0; !ready;) {
- size_t size;
- if (!(size = mio_read(mixer->hdl, buf, sizeof(buf)))) {
- WARNX1("mio_read failed");
- return;
- }
-
- static unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
- static unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
-
- unsigned char mmsg[0x100];
- unsigned int mst = 0, midx = 0, mlen = 0;
- for (unsigned char *p = buf; size > 0; --size, ++p) {
- if (*p >= 0xf8) {
- /* clock events */
- } else if (*p >= 0xf0) {
- if (mst == SYSEX_START && *p == SYSEX_END && midx < sizeof(mmsg)) {
- mmsg[midx++] = *p;
- ready = onsysex(mmsg, midx, controls);
- continue;
- }
-
- mmsg[0] = *p;
- mlen = common_len[*p & 7];
- mst = *p;
- midx = 1;
- } else if (*p >= 0x80) {
- mmsg[0] = *p;
- mlen = voice_len[(*p >> 4) & 7];
- mst = *p;
- midx = 1;
- } else if (mst) {
- if (midx == sizeof(mmsg))
- continue;
-
- if (midx == 0)
- mmsg[midx++] = mst;
-
- mmsg[midx++] = *p;
-
- if (midx == mlen) {
- oncommon(mmsg, midx, controls);
- midx = 0;
- }
- }
- }
- }
-
- snd_mixer_elem_t **tail = &mixer->controls;
- for (size_t i = 0; i < ARRAY_SIZE(controls); ++i) {
- if (!controls[i].name[0])
- continue;
-
- *tail = &controls[i];
- tail = &(*tail)->next;
- }
-}
-
-int
-snd_mixer_open(snd_mixer_t **mixer, int mode)
-{
- if (!(*mixer = calloc(1, sizeof(**mixer)))) {
- WARNX1("calloc");
- return -1;
- }
-
- if (!((*mixer)->hdl = mio_open("snd/0", MIO_OUT | MIO_IN, 0))) {
- WARNX1("mio_open failed");
- goto fail;
- }
-
- get_controls(*mixer);
- return 0;
-
-fail:
- free(*mixer);
- return -1;
-}
-
-int
-snd_mixer_close(snd_mixer_t *mixer)
-{
- mio_close(mixer->hdl);
- free(mixer);
- return 0;
-}
-
-struct _snd_mixer_selem_id {
- char noop;
-};
-
-int
-snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr)
-{
- if (!(*ptr = calloc(1, sizeof(**ptr))))
- return -1;
-
- return 0;
-}
-
-void
-snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj)
-{
- free(obj);
-}
-
-snd_mixer_elem_t*
-snd_mixer_first_elem(snd_mixer_t *mixer)
-{
- return mixer->controls;
-}
-
-snd_mixer_elem_t*
-snd_mixer_elem_next(snd_mixer_elem_t *elem)
-{
- return elem->next;
-}
-
-const char*
-snd_mixer_selem_get_name(snd_mixer_elem_t *elem)
-{
- return elem->name;
-}
-
-int
-snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
-{
- if (value) *value = ((float)elem->vol / (float)0x7f) * 100;
- return 0;
-}
-
-int
-snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
-{
- if (value) *value = (long)elem->vol - 0x7f;
- return 0;
-}
-
-int
-snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem, long *min, long *max)
-{
- if (max) *max = 0;
- if (min) *min = -127;
- return 0;
-}
-
-int
-snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem)
-{
- return true;
-}
-
-int
-snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem)
-{
- return true;
-}
-
-int
-snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem)
-{
- return true;
-}
-
-int
-snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem)
-{
- return true;
-}
-
-#include "symversioning-hell.h"
diff --git a/stubs.h b/src/stubs.h
index f52e19e..f52e19e 100644
--- a/stubs.h
+++ b/src/stubs.h
diff --git a/symversioning-hell.h b/src/symversioning-hell.h
index f3e9b35..f3e9b35 100644
--- a/symversioning-hell.h
+++ b/src/symversioning-hell.h
diff --git a/dsp/defs.h b/src/util/defs.h
index 6cfc877..6cfc877 100644
--- a/dsp/defs.h
+++ b/src/util/defs.h
diff --git a/dsp/dsp.c b/src/util/dsp.c
index 62510b9..62510b9 100644
--- a/dsp/dsp.c
+++ b/src/util/dsp.c
diff --git a/dsp/dsp.h b/src/util/dsp.h
index d057d37..d057d37 100644
--- a/dsp/dsp.h
+++ b/src/util/dsp.h
diff --git a/sysex.h b/src/util/sysex.h
index 245cd2a..245cd2a 100644
--- a/sysex.h
+++ b/src/util/sysex.h
diff --git a/src/util/util.h b/src/util/util.h
new file mode 100644
index 0000000..9e118c2
--- /dev/null
+++ b/src/util/util.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <err.h>
+
+#define WARN1(x) do { warn("asound: %s %s", __func__, x); } while (0)
+#define WARN(x, ...) do { warn("asound: %s " x, __func__, ##__VA_ARGS__); } while (0)
+#define WARNX1(x) do { warnx("asound: %s %s", __func__, x); } while (0)
+#define WARNX(x, ...) do { warnx("asound: %s " x, __func__, ##__VA_ARGS__); } while (0)
+#define ERRX1(x, y) do { errx(x, "asound: %s %s", __func__, y); } while (0)
+#define ERRX(x, y, ...) do { errx(x, "asound: %s " y, __func__, ##__VA_ARGS__); } while (0)
+#define ERR(x, y, ...) do { err(x, "asound: %s " y, __func__, ##__VA_ARGS__); } while (0)
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+static inline char*
+c_strdup(const char *str)
+{
+ size_t len = strlen(str);
+
+ char *copy;
+ if (!(copy = calloc(1, len + 1)))
+ return NULL;
+
+ memcpy(copy, str, len);
+ return copy;
+}