From 46b52167dfc20072a74cdb502dab2544f8c9d598 Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Wed, 7 Mar 2001 12:36:05 +0000 Subject: [PATCH] Exported ERR macros. Completed scopes architecture. Added defaults for {pcm,ctl,rawmidi,seq}type configuration. Fixed bogus dlclose. Implemented ncurses levelmeter (temporarily placed in src/pcm/scopes) --- include/header.h | 9 + include/local.h | 9 - include/pcm.h | 30 ++ src/control/control.c | 52 +-- src/pcm/Makefile.am | 2 +- src/pcm/pcm.c | 51 ++- src/pcm/pcm_meter.c | 692 +++++++++++++++++++++++++----------- src/pcm/pcm_meter.h | 42 --- src/pcm/scopes/Makefile.am | 7 + src/pcm/scopes/configure.in | 9 + src/pcm/scopes/cvscompile | 11 + src/pcm/scopes/level.c | 269 ++++++++++++++ src/rawmidi/rawmidi.c | 49 ++- src/seq/seq.c | 49 ++- 14 files changed, 928 insertions(+), 353 deletions(-) create mode 100644 src/pcm/scopes/Makefile.am create mode 100644 src/pcm/scopes/configure.in create mode 100644 src/pcm/scopes/cvscompile create mode 100644 src/pcm/scopes/level.c diff --git a/include/header.h b/include/header.h index 946755ed..e0a2ae2a 100644 --- a/include/header.h +++ b/include/header.h @@ -33,8 +33,17 @@ #include #include #include +#include #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) #endif +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) +#define SNDERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__) +#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__) +#else +#define SNDERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args) +#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args) +#endif + diff --git a/include/local.h b/include/local.h index 28e7653a..7cad3f45 100644 --- a/include/local.h +++ b/include/local.h @@ -42,15 +42,6 @@ #define _snd_hwdep_info sndrv_hwdep_info #include "asoundlib.h" -#include - -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) -#define SNDERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__) -#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__) -#else -#define SNDERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args) -#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args) -#endif enum _snd_set_mode { SND_CHANGE, diff --git a/include/pcm.h b/include/pcm.h index 7d2157e1..8ae73336 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -209,6 +209,8 @@ typedef struct _snd_pcm_channel_area { unsigned int step; /* samples distance in bits */ } snd_pcm_channel_area_t; +typedef struct _snd_pcm_scope snd_pcm_scope_t; + #ifdef __cplusplus extern "C" { #endif @@ -331,6 +333,34 @@ ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames); int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes); ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int samples); +/* meter */ +typedef struct _snd_pcm_scope_ops { + int (*enable)(snd_pcm_scope_t *scope); + void (*disable)(snd_pcm_scope_t *scope); + void (*start)(snd_pcm_scope_t *scope); + void (*stop)(snd_pcm_scope_t *scope); + void (*update)(snd_pcm_scope_t *scope); + void (*reset)(snd_pcm_scope_t *scope); + void (*close)(snd_pcm_scope_t *scope); +} snd_pcm_scope_ops_t; + +snd_pcm_uframes_t snd_pcm_meter_get_bufsize(snd_pcm_t *pcm); +unsigned int snd_pcm_meter_get_channels(snd_pcm_t *pcm); +unsigned int snd_pcm_meter_get_rate(snd_pcm_t *pcm); +snd_pcm_uframes_t snd_pcm_meter_get_now(snd_pcm_t *pcm); +snd_pcm_uframes_t snd_pcm_meter_get_boundary(snd_pcm_t *pcm); +int snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_scope_t *scope); +snd_pcm_scope_t *snd_pcm_meter_search_scope(snd_pcm_t *pcm, const char *name); +int snd_pcm_scope_malloc(snd_pcm_scope_t **ptr); +void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, snd_pcm_scope_ops_t *val); +void snd_pcm_scope_set_name(snd_pcm_scope_t *scope, const char *val); +const char *snd_pcm_scope_get_name(snd_pcm_scope_t *scope); +void *snd_pcm_scope_get_callback_private(snd_pcm_scope_t *scope); +void snd_pcm_scope_set_callback_private(snd_pcm_scope_t *scope, void *val); +int snd_pcm_scope_s16_open(snd_pcm_t *pcm, const char *name, + snd_pcm_scope_t **scopep); +int16_t *snd_pcm_scope_s16_get_channel_buffer(snd_pcm_scope_t *scope, + unsigned int channel); /* misc */ diff --git a/src/control/control.c b/src/control/control.c index ef80066c..292563e3 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -197,6 +197,7 @@ int snd_ctl_wait(snd_ctl_t *ctl, int timeout) int snd_ctl_open(snd_ctl_t **ctlp, const char *name) { const char *str; + char buf[256]; int err; snd_config_t *ctl_conf, *conf, *type_conf; snd_config_iterator_t i, next; @@ -229,36 +230,45 @@ int snd_ctl_open(snd_ctl_t **ctlp, const char *name) if (err < 0) return err; err = snd_config_searchv(snd_config, &type_conf, "ctltype", str, 0); - snd_config_for_each(i, next, type_conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id = snd_config_get_id(n); - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "lib") == 0) { - err = snd_config_get_string(n, &lib); - if (err < 0) - return -EINVAL; - continue; - } - if (strcmp(id, "open") == 0) { - err = snd_config_get_string(n, &open); - if (err < 0) - return -EINVAL; - continue; + if (err >= 0) { + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) + return -EINVAL; + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open); + if (err < 0) + return -EINVAL; + continue; + } + SNDERR("Unknown field %s", id); return -EINVAL; } } - if (!open) - return -EINVAL; + if (!open) { + open = buf; + snprintf(buf, sizeof(buf), "_snd_ctl_%s_open", str); + } if (!lib) lib = "libasound.so"; h = dlopen(lib, RTLD_NOW); - if (!h) + if (!h) { + SNDERR("Cannot open shared library %s", lib); return -ENOENT; + } open_func = dlsym(h, open); - dlclose(h); - if (!open_func) + if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open, lib); + dlclose(h); return -ENXIO; + } return open_func(ctlp, name, ctl_conf); } diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am index bcf317d9..47fccb76 100644 --- a/src/pcm/Makefile.am +++ b/src/pcm/Makefile.am @@ -8,7 +8,7 @@ libpcm_la_SOURCES = atomic.c mask.c interval.c \ pcm_shm.c pcm_file.c pcm_share.c pcm_null.c pcm_meter.c \ pcm_params.c noinst_HEADERS = atomic.h pcm_local.h pcm_plugin.h mask.h mask_inline.h \ - interval.h interval_inline.h plugin_ops.h pcm_meter.h + interval.h interval_inline.h plugin_ops.h all: libpcm.la diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 6c29456b..1effe000 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -555,8 +555,9 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode) { const char *str; + char buf[256]; int err; - snd_config_t *pcm_conf, *conf, *type_conf; + snd_config_t *pcm_conf, *conf, *type_conf = NULL; snd_config_iterator_t i, next; const char *lib = NULL, *open = NULL; int (*open_func)(snd_pcm_t **pcmp, const char *name, snd_config_t *conf, @@ -638,37 +639,35 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name, return err; } err = snd_config_searchv(snd_config, &type_conf, "pcmtype", str, 0); - if (err < 0) { - SNDERR("Unknown PCM type %s", str); - return err; - } - snd_config_for_each(i, next, type_conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id = snd_config_get_id(n); - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "lib") == 0) { - err = snd_config_get_string(n, &lib); - if (err < 0) { - SNDERR("Invalid type for %s", id); - return -EINVAL; + if (err >= 0) { + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; } - continue; - } - if (strcmp(id, "open") == 0) { - err = snd_config_get_string(n, &open); - if (err < 0) { - SNDERR("Invalid type for %s", id); - return -EINVAL; + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; } - continue; SNDERR("Unknown field %s", id); return -EINVAL; } } if (!open) { - SNDERR("open is not defined"); - return -EINVAL; + open = buf; + snprintf(buf, sizeof(buf), "_snd_pcm_%s_open", str); } if (!lib) lib = "libasound.so"; @@ -678,9 +677,9 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name, return -ENOENT; } open_func = dlsym(h, open); - dlclose(h); if (!open_func) { SNDERR("symbol %s is not defined inside %s", open, lib); + dlclose(h); return -ENXIO; } return open_func(pcmp, name, pcm_conf, stream, mode); diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index ffd73018..ef8ea0d1 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -20,189 +20,41 @@ #include #include -#include "pcm_meter.h" +#include +#include +#include +#include "list.h" +#include "pcm_local.h" +#include "pcm_plugin.h" #define FREQUENCY 50 -typedef struct _snd_pcm_meter_s16 { - snd_pcm_adpcm_state_t *adpcm_states; - unsigned int index; - snd_pcm_uframes_t old; -} snd_pcm_meter_s16_t; - -int s16_open(snd_pcm_meter_scope_t *scope) -{ - snd_pcm_meter_t *meter = scope->pcm->private_data; - snd_pcm_t *spcm = meter->slave; - snd_pcm_channel_area_t *a; - unsigned int c; - snd_pcm_meter_s16_t *s16; - int index; - if (spcm->format == SND_PCM_FORMAT_S16 && - spcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) { - meter->buf16 = (int16_t *) meter->buf; - return -EINVAL; - } - switch (spcm->format) { - case SND_PCM_FORMAT_A_LAW: - case SND_PCM_FORMAT_MU_LAW: - case SND_PCM_FORMAT_IMA_ADPCM: - index = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, SND_PCM_FORMAT_S16); - break; - case SND_PCM_FORMAT_S8: - case SND_PCM_FORMAT_S16_LE: - case SND_PCM_FORMAT_S16_BE: - case SND_PCM_FORMAT_S24_LE: - case SND_PCM_FORMAT_S24_BE: - case SND_PCM_FORMAT_S32_LE: - case SND_PCM_FORMAT_S32_BE: - case SND_PCM_FORMAT_U8: - case SND_PCM_FORMAT_U16_LE: - case SND_PCM_FORMAT_U16_BE: - case SND_PCM_FORMAT_U24_LE: - case SND_PCM_FORMAT_U24_BE: - case SND_PCM_FORMAT_U32_LE: - case SND_PCM_FORMAT_U32_BE: - index = snd_pcm_linear_convert_index(spcm->format, SND_PCM_FORMAT_S16); - break; - default: - return -EINVAL; - } - s16 = calloc(1, sizeof(*s16)); - if (!s16) - return -ENOMEM; - s16->index = index; - if (spcm->format == SND_PCM_FORMAT_IMA_ADPCM) { - s16->adpcm_states = calloc(spcm->channels, sizeof(*s16->adpcm_states)); - if (!s16->adpcm_states) { - free(s16); - return -ENOMEM; - } - } - meter->buf16 = malloc(meter->buf_size * 2 * spcm->channels); - if (!meter->buf16) { - if (s16->adpcm_states) - free(s16->adpcm_states); - free(s16); - return -ENOMEM; - } - a = calloc(spcm->channels, sizeof(*a)); - if (!a) { - free(meter->buf16); - if (s16->adpcm_states) - free(s16->adpcm_states); - free(s16); - return -ENOMEM; - } - meter->buf16_areas = a; - for (c = 0; c < spcm->channels; c++, a++) { - a->addr = meter->buf16 + c * meter->buf_size; - a->first = 0; - a->step = 16; - } - scope->private_data = s16; - return 0; -} - -void s16_close(snd_pcm_meter_scope_t *scope) -{ - snd_pcm_meter_t *meter = scope->pcm->private_data; - snd_pcm_meter_s16_t *s16 = scope->private_data; - if (s16->adpcm_states) - free(s16->adpcm_states); - free(s16); - free(meter->buf16); - meter->buf16 = NULL; - free(meter->buf16_areas); -} - -void s16_start(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) -{ -} - -void s16_stop(snd_pcm_meter_scope_t *scope ATTRIBUTE_UNUSED) -{ -} - -void s16_update(snd_pcm_meter_scope_t *scope) -{ - snd_pcm_meter_t *meter = scope->pcm->private_data; - snd_pcm_meter_s16_t *s16 = scope->private_data; - snd_pcm_t *spcm = meter->slave; - snd_pcm_sframes_t size; - snd_pcm_uframes_t offset; - size = meter->now - s16->old; - if (size < 0) - size += spcm->boundary; - offset = s16->old % meter->buf_size; - while (size > 0) { - snd_pcm_uframes_t frames = size; - snd_pcm_uframes_t cont = meter->buf_size - offset; - if (frames > cont) - frames = cont; - switch (spcm->format) { - case SND_PCM_FORMAT_A_LAW: - snd_pcm_alaw_decode(meter->buf16_areas, offset, - meter->buf_areas, offset, - spcm->channels, frames, - s16->index); - break; - case SND_PCM_FORMAT_MU_LAW: - snd_pcm_mulaw_decode(meter->buf16_areas, offset, - meter->buf_areas, offset, - spcm->channels, frames, - s16->index); - break; - case SND_PCM_FORMAT_IMA_ADPCM: - snd_pcm_adpcm_decode(meter->buf16_areas, offset, - meter->buf_areas, offset, - spcm->channels, frames, - s16->index, - s16->adpcm_states); - break; - default: - snd_pcm_linear_convert(meter->buf16_areas, offset, - meter->buf_areas, offset, - spcm->channels, frames, - s16->index); - break; - } - if (frames == cont) - offset = 0; - else - offset += frames; - size -= frames; - } - s16->old = meter->now; -} - -void s16_reset(snd_pcm_meter_scope_t *scope) -{ - snd_pcm_meter_t *meter = scope->pcm->private_data; - snd_pcm_meter_s16_t *s16 = scope->private_data; - s16->old = meter->now; -} - -snd_pcm_meter_scope_t s16_scope = { - name: "s16", - open: s16_open, - start: s16_start, - stop: s16_stop, - update: s16_update, - reset: s16_reset, - close: s16_close, - pcm: NULL, - active: 0, - list: { 0, 0 }, - private_data: NULL, +struct _snd_pcm_scope { + int enabled; + const char *name; + snd_pcm_scope_ops_t *ops; + void *private_data; + struct list_head list; }; -void snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_meter_scope_t *scope) -{ - snd_pcm_meter_t *meter = pcm->private_data; - scope->pcm = pcm; - list_add_tail(&scope->list, &meter->scopes); -} +typedef struct _snd_pcm_meter { + snd_pcm_t *slave; + int close_slave; + snd_pcm_uframes_t rptr; + snd_pcm_uframes_t buf_size; + snd_pcm_channel_area_t *buf_areas; + snd_pcm_uframes_t now; + unsigned char *buf; + struct list_head scopes; + int closed; + int running; + atomic_t reset; + pthread_t thread; + pthread_mutex_t update_mutex; + pthread_mutex_t running_mutex; + pthread_cond_t running_cond; + struct timespec delay; +} snd_pcm_meter_t; void snd_pcm_meter_add_frames(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas, @@ -284,18 +136,59 @@ static int snd_pcm_meter_update_scope(snd_pcm_t *pcm) return reset; } +int snd_pcm_scope_remove(snd_pcm_scope_t *scope) +{ + if (scope->name) + free((void *)scope->name); + scope->ops->close(scope); + list_del(&scope->list); + free(scope); + return 0; +} + +int snd_pcm_scope_enable(snd_pcm_scope_t *scope) +{ + int err; + assert(!scope->enabled); + err = scope->ops->enable(scope); + scope->enabled = (err >= 0); + return err; +} + +int snd_pcm_scope_disable(snd_pcm_scope_t *scope) +{ + assert(scope->enabled); + scope->ops->disable(scope); + scope->enabled = 0; + return 0; +} + +snd_pcm_scope_t *snd_pcm_meter_search_scope(snd_pcm_t *pcm, const char *name) +{ + snd_pcm_meter_t *meter; + struct list_head *pos; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + list_for_each(pos, &meter->scopes) { + snd_pcm_scope_t *scope; + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->name && strcmp(scope->name, name) == 0) + return scope; + } + return NULL; +} + static void *snd_pcm_meter_thread(void *data) { snd_pcm_t *pcm = data; snd_pcm_meter_t *meter = pcm->private_data; snd_pcm_t *spcm = meter->slave; struct list_head *pos; - snd_pcm_meter_scope_t *scope; - int err, reset; + snd_pcm_scope_t *scope; + int reset; list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_meter_scope_t, list); - err = scope->open(scope); - scope->active = (err >= 0); + scope = list_entry(pos, snd_pcm_scope_t, list); + snd_pcm_scope_enable(scope); } while (!meter->closed) { snd_pcm_sframes_t now; @@ -309,8 +202,8 @@ static void *snd_pcm_meter_thread(void *data) spcm->stream != SND_PCM_STREAM_PLAYBACK)) { if (meter->running) { list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_meter_scope_t, list); - scope->stop(scope); + scope = list_entry(pos, snd_pcm_scope_t, list); + scope->ops->stop(scope); } meter->running = 0; } @@ -341,45 +234,50 @@ static void *snd_pcm_meter_thread(void *data) } if (reset) { list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_meter_scope_t, list); - if (scope->active) - scope->reset(scope); + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + scope->ops->reset(scope); } continue; } if (!meter->running) { list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_meter_scope_t, list); - if (scope->active) - scope->start(scope); + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + scope->ops->start(scope); } meter->running = 1; } list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_meter_scope_t, list); - if (scope->active) - scope->update(scope); + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + scope->ops->update(scope); } nanosleep(&meter->delay, NULL); } list_for_each(pos, &meter->scopes) { - scope = list_entry(pos, snd_pcm_meter_scope_t, list); - if (scope->active) - scope->close(scope); + scope = list_entry(pos, snd_pcm_scope_t, list); + if (scope->enabled) + snd_pcm_scope_disable(scope); } return NULL; } - static int snd_pcm_meter_close(snd_pcm_t *pcm) { snd_pcm_meter_t *meter = pcm->private_data; + struct list_head *pos, *npos; int err = 0; pthread_mutex_destroy(&meter->update_mutex); pthread_mutex_destroy(&meter->running_mutex); pthread_cond_destroy(&meter->running_cond); if (meter->close_slave) err = snd_pcm_close(meter->slave); + list_for_each_safe(pos, npos, &meter->scopes) { + snd_pcm_scope_t *scope; + scope = list_entry(pos, snd_pcm_scope_t, list); + snd_pcm_scope_remove(scope); + } free(meter); return err; } @@ -735,21 +633,89 @@ int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequenc pthread_mutex_init(&meter->update_mutex, NULL); pthread_mutex_init(&meter->running_mutex, NULL); pthread_cond_init(&meter->running_cond, NULL); -#if 1 - snd_pcm_meter_add_scope(pcm, &s16_scope); -#endif return 0; } + +int snd_pcm_meter_add_scope_conf(snd_pcm_t *pcm, const char *name, + snd_config_t *conf) +{ + char buf[256]; + snd_config_iterator_t i, next; + const char *lib = NULL, *open = NULL, *str = NULL; + snd_config_t *c, *type_conf; + int (*open_func)(snd_pcm_t *pcm, const char *name, + snd_config_t *conf); + void *h; + int err; + err = snd_config_search(conf, "type", &c); + if (err < 0) { + SNDERR("type is not defined"); + return err; + } + err = snd_config_get_string(c, &str); + if (err < 0) { + SNDERR("Invalid type for %s", snd_config_get_id(c)); + return err; + } + err = snd_config_searchv(snd_config, &type_conf, "scopetype", str, 0); + if (err >= 0) { + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + } + if (!open) { + open = buf; + snprintf(buf, sizeof(buf), "_snd_pcm_scope_%s_open", str); + } + if (!lib) + lib = "libasound.so"; + h = dlopen(lib, RTLD_NOW); + if (!h) { + SNDERR("Cannot open shared library %s", lib); + return -ENOENT; + } + open_func = dlsym(h, open); + if (!open_func) { + SNDERR("symbol %s is not defined inside %s", open, lib); + dlclose(h); + return -ENXIO; + } + return open_func(pcm, name, conf); +} + + int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, - snd_config_t *conf, - snd_pcm_stream_t stream, int mode) + snd_config_t *conf, + snd_pcm_stream_t stream, int mode) { snd_config_iterator_t i, next; const char *sname = NULL; int err; snd_pcm_t *spcm; long frequency = -1; + snd_config_t *scopes = NULL; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id = snd_config_get_id(n); @@ -773,6 +739,14 @@ int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, } continue; } + if (strcmp(id, "scope") == 0) { + if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + scopes = n; + continue; + } SNDERR("Unknown field %s", id); return -EINVAL; } @@ -792,5 +766,315 @@ int _snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, err = snd_pcm_meter_open(pcmp, name, frequency < 0 ? FREQUENCY : frequency, spcm, 1); if (err < 0) snd_pcm_close(spcm); - return err; + if (!scopes) + return 0; + snd_config_for_each(i, next, scopes) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + err = snd_pcm_meter_add_scope_conf(*pcmp, id, n); + if (err < 0) { + snd_pcm_close(*pcmp); + return -EINVAL; + } + } + return 0; +} + +int snd_pcm_meter_add_scope(snd_pcm_t *pcm, snd_pcm_scope_t *scope) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + list_add_tail(&scope->list, &meter->scopes); + return 0; +} + +snd_pcm_uframes_t snd_pcm_meter_get_bufsize(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + return meter->buf_size; +} + +unsigned int snd_pcm_meter_get_channels(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->slave->setup); + return meter->slave->channels; +} + +unsigned int snd_pcm_meter_get_rate(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->slave->setup); + return meter->slave->rate; +} + +snd_pcm_uframes_t snd_pcm_meter_get_now(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->slave->setup); + return meter->now; +} + +snd_pcm_uframes_t snd_pcm_meter_get_boundary(snd_pcm_t *pcm) +{ + snd_pcm_meter_t *meter; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + assert(meter->slave->setup); + return meter->slave->boundary; +} + +void snd_pcm_scope_set_name(snd_pcm_scope_t *scope, const char *val) +{ + scope->name = val; +} + +const char *snd_pcm_scope_get_name(snd_pcm_scope_t *scope) +{ + return scope->name; +} + +void snd_pcm_scope_set_ops(snd_pcm_scope_t *scope, snd_pcm_scope_ops_t *val) +{ + scope->ops = val; +} + +void *snd_pcm_scope_get_callback_private(snd_pcm_scope_t *scope) +{ + return scope->private_data; +} + +void snd_pcm_scope_set_callback_private(snd_pcm_scope_t *scope, void *val) +{ + scope->private_data = val; } + +typedef struct _snd_pcm_scope_s16 { + snd_pcm_t *pcm; + snd_pcm_adpcm_state_t *adpcm_states; + unsigned int index; + snd_pcm_uframes_t old; + int16_t *buf; + snd_pcm_channel_area_t *buf_areas; +} snd_pcm_scope_s16_t; + +static int s16_enable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + snd_pcm_meter_t *meter = s16->pcm->private_data; + snd_pcm_t *spcm = meter->slave; + snd_pcm_channel_area_t *a; + unsigned int c; + int index; + if (spcm->format == SND_PCM_FORMAT_S16 && + spcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED) { + s16->buf = (int16_t *) meter->buf; + return -EINVAL; + } + switch (spcm->format) { + case SND_PCM_FORMAT_A_LAW: + case SND_PCM_FORMAT_MU_LAW: + case SND_PCM_FORMAT_IMA_ADPCM: + index = snd_pcm_linear_put_index(SND_PCM_FORMAT_S16, SND_PCM_FORMAT_S16); + break; + case SND_PCM_FORMAT_S8: + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S16_BE: + case SND_PCM_FORMAT_S24_LE: + case SND_PCM_FORMAT_S24_BE: + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_U8: + case SND_PCM_FORMAT_U16_LE: + case SND_PCM_FORMAT_U16_BE: + case SND_PCM_FORMAT_U24_LE: + case SND_PCM_FORMAT_U24_BE: + case SND_PCM_FORMAT_U32_LE: + case SND_PCM_FORMAT_U32_BE: + index = snd_pcm_linear_convert_index(spcm->format, SND_PCM_FORMAT_S16); + break; + default: + return -EINVAL; + } + s16->index = index; + if (spcm->format == SND_PCM_FORMAT_IMA_ADPCM) { + s16->adpcm_states = calloc(spcm->channels, sizeof(*s16->adpcm_states)); + if (!s16->adpcm_states) + return -ENOMEM; + } + s16->buf = malloc(meter->buf_size * 2 * spcm->channels); + if (!s16->buf) { + if (s16->adpcm_states) + free(s16->adpcm_states); + return -ENOMEM; + } + a = calloc(spcm->channels, sizeof(*a)); + if (!a) { + free(s16->buf); + if (s16->adpcm_states) + free(s16->adpcm_states); + return -ENOMEM; + } + s16->buf_areas = a; + for (c = 0; c < spcm->channels; c++, a++) { + a->addr = s16->buf + c * meter->buf_size; + a->first = 0; + a->step = 16; + } + return 0; +} + +static void s16_disable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + if (s16->adpcm_states) { + free(s16->adpcm_states); + s16->adpcm_states = NULL; + } + free(s16->buf); + s16->buf = NULL; + free(s16->buf_areas); + s16->buf_areas = 0; +} + +static void s16_close(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + free(s16); +} + +static void s16_start(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED) +{ +} + +static void s16_stop(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED) +{ +} + +static void s16_update(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + snd_pcm_meter_t *meter = s16->pcm->private_data; + snd_pcm_t *spcm = meter->slave; + snd_pcm_sframes_t size; + snd_pcm_uframes_t offset; + size = meter->now - s16->old; + if (size < 0) + size += spcm->boundary; + offset = s16->old % meter->buf_size; + while (size > 0) { + snd_pcm_uframes_t frames = size; + snd_pcm_uframes_t cont = meter->buf_size - offset; + if (frames > cont) + frames = cont; + switch (spcm->format) { + case SND_PCM_FORMAT_A_LAW: + snd_pcm_alaw_decode(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index); + break; + case SND_PCM_FORMAT_MU_LAW: + snd_pcm_mulaw_decode(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index); + break; + case SND_PCM_FORMAT_IMA_ADPCM: + snd_pcm_adpcm_decode(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index, + s16->adpcm_states); + break; + default: + snd_pcm_linear_convert(s16->buf_areas, offset, + meter->buf_areas, offset, + spcm->channels, frames, + s16->index); + break; + } + if (frames == cont) + offset = 0; + else + offset += frames; + size -= frames; + } + s16->old = meter->now; +} + +static void s16_reset(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_s16_t *s16 = scope->private_data; + snd_pcm_meter_t *meter = s16->pcm->private_data; + s16->old = meter->now; +} + +snd_pcm_scope_ops_t s16_ops = { + enable: s16_enable, + disable: s16_disable, + close: s16_close, + start: s16_start, + stop: s16_stop, + update: s16_update, + reset: s16_reset, +}; + +int snd_pcm_scope_s16_open(snd_pcm_t *pcm, const char *name, + snd_pcm_scope_t **scopep) +{ + snd_pcm_meter_t *meter; + snd_pcm_scope_t *scope; + snd_pcm_scope_s16_t *s16; + assert(pcm->type == SND_PCM_TYPE_METER); + meter = pcm->private_data; + scope = calloc(1, sizeof(*scope)); + if (!scope) + return -ENOMEM; + s16 = calloc(1, sizeof(*s16)); + if (!s16) { + free(scope); + return -ENOMEM; + } + if (name) + scope->name = strdup(name); + s16->pcm = pcm; + scope->ops = &s16_ops; + scope->private_data = s16; + list_add_tail(&scope->list, &meter->scopes); + *scopep = scope; + return 0; +} + +int16_t *snd_pcm_scope_s16_get_channel_buffer(snd_pcm_scope_t *scope, + unsigned int channel) +{ + snd_pcm_scope_s16_t *s16; + snd_pcm_meter_t *meter; + assert(scope->ops == &s16_ops); + s16 = scope->private_data; + meter = s16->pcm->private_data; + assert(meter->slave->setup); + assert(s16->buf_areas); + assert(channel < meter->slave->channels); + return s16->buf_areas[channel].addr; +} + +int snd_pcm_scope_malloc(snd_pcm_scope_t **ptr) +{ + assert(ptr); + *ptr = calloc(1, sizeof(snd_pcm_scope_t)); + if (!*ptr) + return -ENOMEM; + return 0; +} + diff --git a/src/pcm/pcm_meter.h b/src/pcm/pcm_meter.h index bc1efa05..aef020fd 100644 --- a/src/pcm/pcm_meter.h +++ b/src/pcm/pcm_meter.h @@ -18,46 +18,4 @@ * */ -#include -#include -#include "list.h" -#include "pcm_local.h" -#include "pcm_plugin.h" - -typedef struct _snd_pcm_meter_scope snd_pcm_meter_scope_t; - -struct _snd_pcm_meter_scope { - snd_pcm_t *pcm; - int active; - char *name; - int (*open)(snd_pcm_meter_scope_t *scope); - void (*start)(snd_pcm_meter_scope_t *scope); - void (*stop)(snd_pcm_meter_scope_t *scope); - void (*update)(snd_pcm_meter_scope_t *scope); - void (*reset)(snd_pcm_meter_scope_t *scope); - void (*close)(snd_pcm_meter_scope_t *scope); - void *private_data; - struct list_head list; -}; - -typedef struct _snd_pcm_meter { - snd_pcm_t *slave; - int close_slave; - snd_pcm_uframes_t rptr; - snd_pcm_uframes_t buf_size; - snd_pcm_channel_area_t *buf_areas; - snd_pcm_uframes_t now; - unsigned char *buf; - struct list_head scopes; - int closed; - int running; - atomic_t reset; - pthread_t thread; - pthread_mutex_t update_mutex; - pthread_mutex_t running_mutex; - pthread_cond_t running_cond; - int16_t *buf16; - snd_pcm_channel_area_t *buf16_areas; - struct timespec delay; -} snd_pcm_meter_t; diff --git a/src/pcm/scopes/Makefile.am b/src/pcm/scopes/Makefile.am new file mode 100644 index 00000000..634d180a --- /dev/null +++ b/src/pcm/scopes/Makefile.am @@ -0,0 +1,7 @@ + +CFLAGS = -g -O2 -W -Wall + +lib_LTLIBRARIES = liblevel.la + +liblevel_la_SOURCES = level.c +liblevel_la_LIBADD = -lncurses diff --git a/src/pcm/scopes/configure.in b/src/pcm/scopes/configure.in new file mode 100644 index 00000000..3e816156 --- /dev/null +++ b/src/pcm/scopes/configure.in @@ -0,0 +1,9 @@ +AC_INIT(level.c) +AM_INIT_AUTOMAKE(scopes, 0.9) + +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_LIBTOOL + +AC_OUTPUT(Makefile) diff --git a/src/pcm/scopes/cvscompile b/src/pcm/scopes/cvscompile new file mode 100644 index 00000000..aa130d4f --- /dev/null +++ b/src/pcm/scopes/cvscompile @@ -0,0 +1,11 @@ +#!/bin/bash + +aclocal $ACLOCAL_FLAGS +automake --foreign --add-missing +autoconf +export CFLAGS='-O2 -Wall -W -pipe -g' +echo "CFLAGS=$CFLAGS" +echo "./configure $@" +./configure $@ +unset CFLAGS +make diff --git a/src/pcm/scopes/level.c b/src/pcm/scopes/level.c new file mode 100644 index 00000000..750a28ef --- /dev/null +++ b/src/pcm/scopes/level.c @@ -0,0 +1,269 @@ +/* + * PCM - Meter level plugin (ncurses) + * Copyright (c) 2001 by Abramo Bagnara + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include + +#define BAR_WIDTH 70 +/* milliseconds to go from 32767 to 0 */ +#define DECAY_MS 400 +/* milliseconds for peak to disappear */ +#define PEAK_MS 800 + +typedef struct _snd_pcm_scope_level_channel { + int16_t level; + int16_t peak; + unsigned int peak_age; +} snd_pcm_scope_level_channel_t; + +typedef struct _snd_pcm_scope_level { + snd_pcm_t *pcm; + snd_pcm_scope_t *s16; + snd_pcm_scope_level_channel_t *channels; + snd_pcm_uframes_t old; + int top; + WINDOW *win; + unsigned int bar_width; + unsigned int decay_ms; + unsigned int peak_ms; +} snd_pcm_scope_level_t; + +static int level_enable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + int y, x; + level->channels = calloc(snd_pcm_meter_get_channels(level->pcm), sizeof(*level->channels)); + if (!level->channels) { + free(level); + return -ENOMEM; + } + snd_pcm_scope_set_callback_private(scope, level); + level->win = initscr(); + winsdelln(level->win, snd_pcm_meter_get_channels(level->pcm)); + getyx(level->win, y, x); + level->top = y; + return 0; +} + +static void level_disable(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + endwin(); + free(level->channels); +} + +static void level_close(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + free(level); +} + +static void level_start(snd_pcm_scope_t *scope ATTRIBUTE_UNUSED) +{ +} + +static void level_stop(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + unsigned int c; + for (c = 0; c < snd_pcm_meter_get_channels(level->pcm); c++) { + move(level->top + c, 0); + clrtoeol(); + } + move(level->top, 0); + refresh(); +} + +static void level_update(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + snd_pcm_t *pcm = level->pcm; + snd_pcm_sframes_t size; + snd_pcm_uframes_t size1, size2; + snd_pcm_uframes_t offset, cont; + unsigned int c, channels; + unsigned int ms; + static char bar[256] = { [0 ... 255] = '#' }; + int max_decay; + size = snd_pcm_meter_get_now(pcm) - level->old; + if (size < 0) + size += snd_pcm_meter_get_boundary(pcm); + offset = level->old % snd_pcm_meter_get_bufsize(pcm); + cont = snd_pcm_meter_get_bufsize(pcm) - offset; + size1 = size; + if (size1 > cont) + size1 = cont; + size2 = size - size1; + ms = size * 1000 / snd_pcm_meter_get_rate(pcm); + max_decay = 32768 * ms / level->decay_ms; + channels = snd_pcm_meter_get_channels(pcm); + for (c = 0; c < channels; c++) { + int16_t *ptr; + int s, lev = 0; + snd_pcm_uframes_t n; + snd_pcm_scope_level_channel_t *l; + unsigned int lev_pos, peak_pos; + l = &level->channels[c]; + ptr = snd_pcm_scope_s16_get_channel_buffer(level->s16, c) + offset; + for (n = size1; n > 0; n--) { + s = *ptr; + if (s < 0) + s = -s; + if (s > lev) + lev = s; + ptr++; + } + ptr = snd_pcm_scope_s16_get_channel_buffer(level->s16, c); + for (n = size2; n > 0; n--) { + s = *ptr; + if (s < 0) + s = -s; + if (s > lev) + lev = s; + ptr++; + } + l->level = lev; + l->peak_age += ms; + if (l->peak_age >= level->peak_ms || + lev >= l->peak) { + l->peak = lev; + l->peak_age = 0; + } + if (lev < l->level - max_decay) + lev = l->level - max_decay; + move(level->top + c, 0); + lev_pos = lev * level->bar_width / 32768; + peak_pos = l->peak * level->bar_width / 32768; + addnstr(bar, lev_pos); + clrtoeol(); + mvaddch(level->top + c, peak_pos - 1, '#'); + } + move(level->top, 0); + refresh(); + level->old = snd_pcm_meter_get_now(pcm); +} + +static void level_reset(snd_pcm_scope_t *scope) +{ + snd_pcm_scope_level_t *level = snd_pcm_scope_get_callback_private(scope); + snd_pcm_t *pcm = level->pcm; + memset(level->channels, 0, snd_pcm_meter_get_channels(pcm) * sizeof(*level->channels)); + level->old = snd_pcm_meter_get_now(pcm); +} + +snd_pcm_scope_ops_t level_ops = { + enable: level_enable, + disable: level_disable, + close: level_close, + start: level_start, + stop: level_stop, + update: level_update, + reset: level_reset, +}; + +int snd_pcm_scope_level_open(snd_pcm_t *pcm, const char *name, + unsigned int bar_width, unsigned int decay_ms, + unsigned int peak_ms, + snd_pcm_scope_t **scopep) +{ + snd_pcm_scope_t *scope, *s16; + snd_pcm_scope_level_t *level; + int err = snd_pcm_scope_malloc(&scope); + if (err < 0) + return err; + level = calloc(1, sizeof(*level)); + if (!level) { + free(scope); + return -ENOMEM; + } + level->pcm = pcm; + level->bar_width = bar_width; + level->decay_ms = decay_ms; + level->peak_ms = peak_ms; + s16 = snd_pcm_meter_search_scope(pcm, "s16"); + if (!s16) { + err = snd_pcm_scope_s16_open(pcm, "s16", &s16); + if (err < 0) { + free(scope); + free(level); + return err; + } + } + level->s16 = s16; + snd_pcm_scope_set_ops(scope, &level_ops); + snd_pcm_scope_set_callback_private(scope, level); + if (name) + snd_pcm_scope_set_name(scope, strdup(name)); + snd_pcm_meter_add_scope(pcm, scope); + *scopep = scope; + return 0; +} + +int _snd_pcm_scope_level_open(snd_pcm_t *pcm, const char *name, + snd_config_t *conf) +{ + snd_config_iterator_t i, next; + snd_pcm_scope_t *scope; + long bar_width = -1, decay_ms = -1, peak_ms = -1; + int err; + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "type") == 0) + continue; + if (strcmp(id, "bar_width") == 0) { + err = snd_config_get_integer(n, &bar_width); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "decay_ms") == 0) { + err = snd_config_get_integer(n, &decay_ms); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + if (strcmp(id, "peak_ms") == 0) { + err = snd_config_get_integer(n, &peak_ms); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (bar_width < 0) + bar_width = BAR_WIDTH; + if (decay_ms < 0) + decay_ms = DECAY_MS; + if (peak_ms < 0) + peak_ms = PEAK_MS; + return snd_pcm_scope_level_open(pcm, name, bar_width, decay_ms, peak_ms, + &scope); +} diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c index 7fe4e547..8223755a 100644 --- a/src/rawmidi/rawmidi.c +++ b/src/rawmidi/rawmidi.c @@ -169,6 +169,7 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, const char *name, int mode) { const char *str; + char buf[256]; int err; snd_config_t *rawmidi_conf, *conf, *type_conf; snd_config_iterator_t i, next; @@ -208,37 +209,35 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, return err; } err = snd_config_searchv(snd_config, &type_conf, "rawmiditype", str, 0); - if (err < 0) { - SNDERR("Unknown RAWMIDI type %s", str); - return err; - } - snd_config_for_each(i, next, type_conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id = snd_config_get_id(n); - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "lib") == 0) { - err = snd_config_get_string(n, &lib); - if (err < 0) { - SNDERR("Invalid type for %s", id); - return -EINVAL; + if (err >= 0) { + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; } - continue; - } - if (strcmp(id, "open") == 0) { - err = snd_config_get_string(n, &open); - if (err < 0) { - SNDERR("Invalid type for %s", id); - return -EINVAL; + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; } - continue; SNDERR("Unknown field %s", id); return -EINVAL; } } if (!open) { - SNDERR("open is not defined"); - return -EINVAL; + open = buf; + snprintf(buf, sizeof(buf), "_snd_rawmidi_%s_open", str); } if (!lib) lib = "libasound.so"; @@ -248,9 +247,9 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, return -ENOENT; } open_func = dlsym(h, open); - dlclose(h); if (!open_func) { SNDERR("symbol %s is not defined inside %s", open, lib); + dlclose(h); return -ENXIO; } err = open_func(inputp, outputp, name, rawmidi_conf, mode); diff --git a/src/seq/seq.c b/src/seq/seq.c index b7e03284..f281b4a7 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -40,6 +40,7 @@ int snd_seq_open(snd_seq_t **seqp, const char *name, int streams, int mode) { const char *str; + char buf[256]; int err; snd_config_t *seq_conf, *conf, *type_conf; snd_config_iterator_t i, next; @@ -73,37 +74,35 @@ int snd_seq_open(snd_seq_t **seqp, const char *name, return err; } err = snd_config_searchv(snd_config, &type_conf, "seqtype", str, 0); - if (err < 0) { - SNDERR("Unknown SEQ type %s", str); - return err; - } - snd_config_for_each(i, next, type_conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id = snd_config_get_id(n); - if (strcmp(id, "comment") == 0) - continue; - if (strcmp(id, "lib") == 0) { - err = snd_config_get_string(n, &lib); - if (err < 0) { - SNDERR("Invalid type for %s", id); - return -EINVAL; + if (err >= 0) { + snd_config_for_each(i, next, type_conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + if (strcmp(id, "comment") == 0) + continue; + if (strcmp(id, "lib") == 0) { + err = snd_config_get_string(n, &lib); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; } - continue; - } - if (strcmp(id, "open") == 0) { - err = snd_config_get_string(n, &open); - if (err < 0) { - SNDERR("Invalid type for %s", id); - return -EINVAL; + if (strcmp(id, "open") == 0) { + err = snd_config_get_string(n, &open); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + continue; } - continue; SNDERR("Unknown field %s", id); return -EINVAL; } } if (!open) { - SNDERR("open is not defined"); - return -EINVAL; + open = buf; + snprintf(buf, sizeof(buf), "_snd_seq_%s_open", str); } if (!lib) lib = "libasound.so"; @@ -113,9 +112,9 @@ int snd_seq_open(snd_seq_t **seqp, const char *name, return -ENOENT; } open_func = dlsym(h, open); - dlclose(h); if (!open_func) { SNDERR("symbol %s is not defined inside %s", open, lib); + dlclose(h); return -ENXIO; } return open_func(seqp, name, seq_conf, streams, mode); -- 2.47.1