int snd_hctl_nonblock(snd_hctl_t *hctl, int nonblock);
int snd_hctl_poll_descriptors_count(snd_hctl_t *hctl);
int snd_hctl_poll_descriptors(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int space);
+int snd_hctl_poll_descriptors_revents(snd_hctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
unsigned int snd_hctl_get_count(snd_hctl_t *hctl);
int snd_hctl_set_compare(snd_hctl_t *hctl, snd_hctl_compare_t hsort);
snd_hctl_elem_t *snd_hctl_first_elem(snd_hctl_t *hctl);
#include <alsa/asoundlib.h>
+/*
+ * Abbreviations:
+ *
+ * FLVOL - Front Left Volume (0-1000)
+ * FCLVOL - Front Center Left Volume (0-1000)
+ * FCVOL - Front Center Volume (0-1000)
+ * FCRVOL - Front Center Right Volume (0-1000)
+ * FRVOL - Front Right Volume (0-1000)
+ * FSLVOL - Front Side Left Volume (0-1000)
+ * FSRVOL - Front Side Right Volume (0-1000)
+ * RSLVOL - Rear Side Left Volume (0-1000)
+ * RSRVOL - Rear Side Right Volume (0-1000)
+ * RLVOL - Rear Left Volume (0-1000)
+ * RCVOL - Rear Center Volume (0-1000)
+ * RRVOL - Rear Right Volume (0-1000)
+ * LFEVOL - Low Frequency Effects (Subwoofer) Volume (0-1000)
+ * OVRVOL - Overhead Volume (0-1000)
+ */
+
/** Ordinary Mixer I/O type */
enum sndo_mixer_io_type {
* playback section
*/
- /** Master volume - left (0-1000) */
- SNDO_MIO_MASTER_LVOL = 0,
- /** Master volume - right (0-1000) */
- SNDO_MIO_MASTER_RVOL,
- /** Master volume - left surround (0-1000) */
- SNDO_MIO_MASTER_LSVOL = 0,
- /** Master volume - right surround (0-1000) */
- SNDO_MIO_MASTER_RSVOL,
- /** Master volume - center (0-1000) */
- SNDO_MIO_MASTER_CVOL = 0,
- /** Master volume - LFE (0-1000) */
+ /* Master */
+ SNDO_MIO_MASTER_FLVOL = 0 * 0x40,
+ SNDO_MIO_MASTER_FCLVOL,
+ SNDO_MIO_MASTER_FCVOL,
+ SNDO_MIO_MASTER_FCRVOL,
+ SNDO_MIO_MASTER_FRVOL,
+ SNDO_MIO_MASTER_FSLVOL,
+ SNDO_MIO_MASTER_FSRVOL,
+ SNDO_MIO_MASTER_RSLVOL,
+ SNDO_MIO_MASTER_RSRVOL,
+ SNDO_MIO_MASTER_RLVOL,
+ SNDO_MIO_MASTER_RCVOL,
+ SNDO_MIO_MASTER_RRVOL,
SNDO_MIO_MASTER_LFEVOL,
- /** Master volume - left mute (0 = off, 1 = on) */
- SNDO_MIO_MASTER_LMUTE,
- /** Master volume - right mute (0 = off, 1 = on) */
- SNDO_MIO_MASTER_RMUTE,
- /** Master volume - left surround mute (0 = off, 1 = on) */
- SNDO_MIO_MASTER_LSMUTE,
- /** Master volume - right surround mute (0 = off, 1 = on) */
- SNDO_MIO_MASTER_RSMUTE,
- /** Master volume - center mute (0 = off, 1 = on) */
- SNDO_MIO_MASTER_CMUTE,
- /** Master volume - LFE mute (0 = off, 1 = on) */
- SNDO_MIO_MASTER_LFEMUTE,
-
- /** PCM volume - left (0-1000) */
- SNDO_MIO_PCM_LVOL = 0,
- /** PCM volume - right (0-1000) */
- SNDO_MIO_PCM_RVOL,
- /** PCM volume - left surround (0-1000) */
- SNDO_MIO_PCM_LSVOL = 0,
- /** PCM volume - right surround (0-1000) */
- SNDO_MIO_PCM_RSVOL,
- /** PCM volume - center (0-1000) */
- SNDO_MIO_PCM_CVOL = 0,
- /** PCM volume - LFE (0-1000) */
+ SNDO_MIO_MASTER_OVRVOL,
+
+ /* PCM */
+ SNDO_MIO_PCM_FLVOL = 1 * 0x40,
+ SNDO_MIO_PCM_FCLVOL,
+ SNDO_MIO_PCM_FCVOL,
+ SNDO_MIO_PCM_FCRVOL,
+ SNDO_MIO_PCM_FRVOL,
+ SNDO_MIO_PCM_FSLVOL,
+ SNDO_MIO_PCM_FSRVOL,
+ SNDO_MIO_PCM_RSLVOL,
+ SNDO_MIO_PCM_RSRVOL,
+ SNDO_MIO_PCM_RLVOL,
+ SNDO_MIO_PCM_RCVOL,
+ SNDO_MIO_PCM_RRVOL,
SNDO_MIO_PCM_LFEVOL,
- /** PCM volume - left mute (0 = off, 1 = on) */
- SNDO_MIO_PCM_LMUTE,
- /** PCM volume - right mute (0 = off, 1 = on) */
- SNDO_MIO_PCM_RMUTE,
- /** PCM volume - left surround mute (0 = off, 1 = on) */
- SNDO_MIO_PCM_LSMUTE,
- /** PCM volume - right surround mute (0 = off, 1 = on) */
- SNDO_MIO_PCM_RSMUTE,
- /** PCM volume - center mute (0 = off, 1 = on) */
- SNDO_MIO_PCM_CMUTE,
- /** PCM volume - LFE mute (0 = off, 1 = on) */
- SNDO_MIO_PCM_LFEMUTE,
-
- /** LINE volume - left (0-1000) */
- SNDO_MIO_LINE_LVOL = 0,
- /** LINE volume - right (0-1000) */
- SNDO_MIO_LINE_RVOL,
- /** LINE volume - left surround (0-1000) */
- SNDO_MIO_LINE_LSVOL = 0,
- /** LINE volume - right surround (0-1000) */
- SNDO_MIO_LINE_RSVOL,
- /** LINE volume - center (0-1000) */
- SNDO_MIO_LINE_CVOL = 0,
- /** LINE volume - LFE (0-1000) */
+ SNDO_MIO_PCM_OVRVOL,
+
+ /* LINE */
+ SNDO_MIO_LINE_FLVOL = 2 * 0x40,
+ SNDO_MIO_LINE_FCLVOL,
+ SNDO_MIO_LINE_FCVOL,
+ SNDO_MIO_LINE_FCRVOL,
+ SNDO_MIO_LINE_FRVOL,
+ SNDO_MIO_LINE_FSLVOL,
+ SNDO_MIO_LINE_FSRVOL,
+ SNDO_MIO_LINE_RSLVOL,
+ SNDO_MIO_LINE_RSRVOL,
+ SNDO_MIO_LINE_RLVOL,
+ SNDO_MIO_LINE_RCVOL,
+ SNDO_MIO_LINE_RRVOL,
SNDO_MIO_LINE_LFEVOL,
- /** LINE volume - left mute (0 = off, 1 = on) */
- SNDO_MIO_LINE_LMUTE,
- /** LINE volume - right mute (0 = off, 1 = on) */
- SNDO_MIO_LINE_RMUTE,
- /** LINE volume - left surround mute (0 = off, 1 = on) */
- SNDO_MIO_LINE_LSMUTE,
- /** LINE volume - right surround mute (0 = off, 1 = on) */
- SNDO_MIO_LINE_RSMUTE,
- /** LINE volume - center mute (0 = off, 1 = on) */
- SNDO_MIO_LINE_CMUTE,
- /** LINE volume - LFE mute (0 = off, 1 = on) */
- SNDO_MIO_LINE_LFEMUTE,
-
- /** MIC volume - left (0-1000) */
- SNDO_MIO_MIC_LVOL = 0,
- /** MIC volume - right (0-1000) */
- SNDO_MIO_MIC_RVOL,
- /** MIC volume - left surround (0-1000) */
- SNDO_MIO_MIC_LSVOL = 0,
- /** MIC volume - right surround (0-1000) */
- SNDO_MIO_MIC_RSVOL,
- /** MIC volume - center (0-1000) */
- SNDO_MIO_MIC_CVOL = 0,
- /** MIC volume - LFE (0-1000) */
+ SNDO_MIO_LINE_OVRVOL,
+
+ /* MIC */
+ SNDO_MIO_MIC_FLVOL = 3 * 0x40,
+ SNDO_MIO_MIC_FCLVOL,
+ SNDO_MIO_MIC_FCVOL,
+ SNDO_MIO_MIC_FCRVOL,
+ SNDO_MIO_MIC_FRVOL,
+ SNDO_MIO_MIC_FSLVOL,
+ SNDO_MIO_MIC_FSRVOL,
+ SNDO_MIO_MIC_RSLVOL,
+ SNDO_MIO_MIC_RSRVOL,
+ SNDO_MIO_MIC_RLVOL,
+ SNDO_MIO_MIC_RCVOL,
+ SNDO_MIO_MIC_RRVOL,
SNDO_MIO_MIC_LFEVOL,
- /** MIC volume - left mute (0 = off, 1 = on) */
- SNDO_MIO_MIC_LMUTE,
- /** MIC volume - right mute (0 = off, 1 = on) */
- SNDO_MIO_MIC_RMUTE,
- /** MIC volume - left surround mute (0 = off, 1 = on) */
- SNDO_MIO_MIC_LSMUTE,
- /** MIC volume - right surround mute (0 = off, 1 = on) */
- SNDO_MIO_MIC_RSMUTE,
- /** MIC volume - center mute (0 = off, 1 = on) */
- SNDO_MIO_MIC_CMUTE,
- /** MIC volume - LFE mute (0 = off, 1 = on) */
- SNDO_MIO_MIC_LFEMUTE,
-
- /** CD volume - left (0-1000) */
- SNDO_MIO_CD_LVOL = 0,
- /** CD volume - right (0-1000) */
- SNDO_MIO_CD_RVOL,
- /** CD volume - left surround (0-1000) */
- SNDO_MIO_CD_LSVOL = 0,
- /** CD volume - right surround (0-1000) */
- SNDO_MIO_CD_RSVOL,
- /** CD volume - center (0-1000) */
- SNDO_MIO_CD_CVOL = 0,
- /** CD volume - LFE (0-1000) */
+ SNDO_MIO_MIC_OVRVOL,
+
+ /* CD */
+ SNDO_MIO_CD_FLVOL = 4 * 0x40,
+ SNDO_MIO_CD_FCLVOL,
+ SNDO_MIO_CD_FCVOL,
+ SNDO_MIO_CD_FCRVOL,
+ SNDO_MIO_CD_FRVOL,
+ SNDO_MIO_CD_FSLVOL,
+ SNDO_MIO_CD_FSRVOL,
+ SNDO_MIO_CD_RSLVOL,
+ SNDO_MIO_CD_RSRVOL,
+ SNDO_MIO_CD_RLVOL,
+ SNDO_MIO_CD_RCVOL,
+ SNDO_MIO_CD_RRVOL,
SNDO_MIO_CD_LFEVOL,
- /** CD volume - left mute (0 = off, 1 = on) */
- SNDO_MIO_CD_LMUTE,
- /** CD volume - right mute (0 = off, 1 = on) */
- SNDO_MIO_CD_RMUTE,
- /** CD volume - left surround mute (0 = off, 1 = on) */
- SNDO_MIO_CD_LSMUTE,
- /** CD volume - right surround mute (0 = off, 1 = on) */
- SNDO_MIO_CD_RSMUTE,
- /** CD volume - center mute (0 = off, 1 = on) */
- SNDO_MIO_CD_CMUTE,
- /** CD volume - LFE mute (0 = off, 1 = on) */
- SNDO_MIO_CD_LFEMUTE,
+ SNDO_MIO_CD_OVRVOL,
+
+ /* AUX */
+ SNDO_MIO_AUX_FLVOL = 5 * 0x40,
+ SNDO_MIO_AUX_FCLVOL,
+ SNDO_MIO_AUX_FCVOL,
+ SNDO_MIO_AUX_FCRVOL,
+ SNDO_MIO_AUX_FRVOL,
+ SNDO_MIO_AUX_FSLVOL,
+ SNDO_MIO_AUX_FSRVOL,
+ SNDO_MIO_AUX_RSLVOL,
+ SNDO_MIO_AUX_RSRVOL,
+ SNDO_MIO_AUX_RLVOL,
+ SNDO_MIO_AUX_RCVOL,
+ SNDO_MIO_AUX_RRVOL,
+ SNDO_MIO_AUX_LFEVOL,
+ SNDO_MIO_AUX_OVRVOL,
/*
* capture section
*/
- /** capture gain - left (0-1000) */
- SNDO_MIO_CGAIN_LVOL = 0x1000,
- /** capture gain - right (0-1000) */
- SNDO_MIO_CGAIN_RVOL,
- /** capture gain - left surround (0-1000) */
- SNDO_MIO_CGAIN_LSVOL,
- /** capture gain - right surround (0-1000) */
- SNDO_MIO_CGAIN_RSVOL,
- /** capture gain - center (0-1000) */
- SNDO_MIO_CGAIN_CVOL,
- /** capture gain - LFE (0-1000) */
- SNDO_MIO_CGAIN_LFEVOL,
-
- /** capture source - MIC exclusive switch (0 = off, 1 = on) */
- SNDO_MIO_CSOURCE_MIC = 0x1100,
- /** capture source - LINE exclusive switch (0 = off, 1 = on) */
+ /* capture gain */
+ SNDO_MIO_CGAIN_FL = 0x8000,
+ SNDO_MIO_CGAIN_FCL,
+ SNDO_MIO_CGAIN_FC,
+ SNDO_MIO_CGAIN_FCR,
+ SNDO_MIO_CGAIN_FR,
+ SNDO_MIO_CGAIN_FSL,
+ SNDO_MIO_CGAIN_FSR,
+ SNDO_MIO_CGAIN_RSL,
+ SNDO_MIO_CGAIN_RSR,
+ SNDO_MIO_CGAIN_RL,
+ SNDO_MIO_CGAIN_RC,
+ SNDO_MIO_CGAIN_RR,
+ SNDO_MIO_CGAIN_LFE,
+ SNDO_MIO_CGAIN_OVR,
+
+ /* capture source (0 = off, 1 = on) */
+ SNDO_MIO_CSOURCE_MIC = 0x8100,
SNDO_MIO_CSOURCE_LINE,
- /** capture source - CD exclusive switch (0 = off, 1 = on) */
SNDO_MIO_CSOURCE_CD,
- /** capture source - AUX exclusive switch (0 = off, 1 = on) */
SNDO_MIO_CSOURCE_AUX,
- /** capture source - MIX exclusive switch (0 = off, 1 = on) */
- SNDO_MIO_CSOURCE_MIX
+ SNDO_MIO_CSOURCE_MIX,
+
+ /* misc */
+ SNDO_MIO_STEREO = 0x8200, /* (0 = off, 1 = on) standard stereo source, might be converted to use all outputs */
};
typedef struct sndo_mixer sndo_mixer_t;
int sndo_mixer_poll_descriptors_count(sndo_mixer_t *mixer);
int sndo_mixer_poll_descriptors(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int space);
int sndo_mixer_poll_descriptors_revents(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
+int sndo_mixer_io_get_name(enum sndo_mixer_io_type type, char **name);
int sndo_mixer_io_get(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
-int sndo_mixer_io_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int val);
+int sndo_mixer_io_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
+int sndo_mixer_io_try_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
+int sndo_mixer_io_get_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
+int sndo_mixer_io_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
+int sndo_mixer_io_try_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val);
int sndo_mixer_io_change(sndo_mixer_t *mixer, enum sndo_mixer_io_type *changed, int changed_array_size);
/** \} */
sndo_*;
alsa_lisp_*;
} ALSA_0.9.6;
+
+ALSA_0.9.8 {
+ global:
+
+ snd_hctl_poll_descriptors_revents;
+} ALSA_0.9.7;
static void princ_cons(snd_output_t *out, struct alisp_object * p);
static void princ_object(snd_output_t *out, struct alisp_object * p);
static struct alisp_object * eval(struct alisp_instance *instance, struct alisp_object * p);
+static struct alisp_object * eval_cons1(struct alisp_instance *instance, struct alisp_object * p1, struct alisp_object * p2);
/* functions */
static struct alisp_object *F_eval(struct alisp_instance *instance, struct alisp_object *);
return instance->thistoken;
got_id:
- case '_': case '+': case '*': case '/': case '%':
+ case '!': case '_': case '+': case '*': case '/': case '%':
case '<': case '>': case '=': case '&':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
- /* Identifier: [-/+*%<>=&a-zA-Z_][-/+*%<>=&a-zA-Z_0-9]* */
+ /* Identifier: [!-/+*%<>=&a-zA-Z_][-/+*%<>=&a-zA-Z_0-9]* */
p = instance->token_buffer;
do {
if (p - instance->token_buffer >= instance->token_buffer_max) {
}
*p++ = c;
c = xgetc(instance);
- } while (isalnum(c) || strchr("_-+*/%<>=&", c) != NULL);
+ } while (isalnum(c) || strchr("!_-+*/%<>=&", c) != NULL);
xungetc(instance, c);
*p = '\0';
return instance->thistoken = ALISP_IDENTIFIER;
return &alsa_lisp_nil;
}
+/*
+ * Syntax: (!= expr1 expr2)
+ */
+static struct alisp_object * F_numneq(struct alisp_instance *instance, struct alisp_object * args)
+{
+ struct alisp_object * p;
+
+ p = F_numeq(instance, args);
+ if (p == &alsa_lisp_nil)
+ return &alsa_lisp_t;
+ return &alsa_lisp_nil;
+}
+
/*
* Syntax: (exfun name)
* Test, if a function exists
{
struct alisp_object * p1, * p2;
- p1 = car(args);
+ p1 = eval(instance, car(args));
if (p1->type != ALISP_OBJ_STRING && p1->type != ALISP_OBJ_IDENTIFIER)
return &alsa_lisp_nil;
p2 = get_object(instance, p1);
return new_integer(instance, res);
}
+/*
+ * Syntax: (call function args...)
+ */
+struct alisp_object * F_call(struct alisp_instance *instance, struct alisp_object * args)
+{
+ struct alisp_object * p = eval(instance, car(args));
+
+ if (p->type != ALISP_OBJ_IDENTIFIER && p->type != ALISP_OBJ_STRING) {
+ lisp_warn(instance, "expected an function name");
+ return &alsa_lisp_nil;
+ }
+ return eval_cons1(instance, p, cdr(args));
+}
+
/*
* Syntax: (int value)
* 'value' can be integer or float type
{
struct alisp_object * p = eval(instance, car(args));
- if (p->type == ALISP_INTEGER)
+ if (p->type == ALISP_OBJ_INTEGER)
return p;
- if (p->type == ALISP_FLOAT)
+ if (p->type == ALISP_OBJ_FLOAT)
return new_integer(instance, floor(p->value.f));
lisp_warn(instance, "expected an integer or float for integer conversion");
{
struct alisp_object * p = eval(instance, car(args));
- if (p->type == ALISP_FLOAT)
+ if (p->type == ALISP_OBJ_FLOAT)
return p;
- if (p->type == ALISP_INTEGER)
+ if (p->type == ALISP_OBJ_INTEGER)
return new_float(instance, p->value.i);
lisp_warn(instance, "expected an integer or float for integer conversion");
{
struct alisp_object * p = eval(instance, car(args));
- if (p->type == ALISP_STRING)
+ if (p->type == ALISP_OBJ_STRING)
return p;
- if (p->type == ALISP_INTEGER || p->type == ALISP_FLOAT) {
+ if (p->type == ALISP_OBJ_INTEGER || p->type == ALISP_OBJ_FLOAT) {
char buf[64];
if (p->type == ALISP_INTEGER) {
snprintf(buf, sizeof(buf), "%ld", p->value.i);
};
static struct intrinsic intrinsics[] = {
+ { "!=", F_numneq },
{ "%", F_mod },
{ "&dump-memory", F_dump_memory },
{ "&dump-objects", F_dump_objects },
{ "assoc", F_assoc },
{ "assq", F_assq },
{ "atom", F_atom },
+ { "call", F_call },
{ "car", F_car },
{ "cdr", F_cdr },
{ "cond", F_cond },
((struct intrinsic *)p2)->name);
}
-static struct alisp_object * eval_cons(struct alisp_instance *instance, struct alisp_object * p)
+static struct alisp_object * eval_cons1(struct alisp_instance *instance, struct alisp_object * p1, struct alisp_object * p2)
{
- struct alisp_object * p1 = car(p), * p2 = cdr(p), * p3;
+ struct alisp_object * p3;
+ struct intrinsic key, *item;
- if (p1 != &alsa_lisp_nil && p1->type == ALISP_OBJ_IDENTIFIER) {
- struct intrinsic key, *item;
+ key.name = p1->value.id;
+ if ((item = bsearch(&key, intrinsics,
+ sizeof intrinsics / sizeof intrinsics[0],
+ sizeof intrinsics[0], compar)) != NULL)
+ return item->func(instance, p2);
- if (!strcmp(p1->value.id, "lambda"))
- return p;
+ if ((item = bsearch(&key, snd_intrinsics,
+ sizeof snd_intrinsics / sizeof snd_intrinsics[0],
+ sizeof snd_intrinsics[0], compar)) != NULL)
+ return item->func(instance, p2);
- auto_garbage_collect(instance);
+ if ((p3 = get_object(instance, p1)) != &alsa_lisp_nil)
+ return eval_func(instance, p3, p2);
+ else
+ lisp_warn(instance, "function `%s' is undefined", p1->value.id);
- key.name = p1->value.id;
- if ((item = bsearch(&key, intrinsics,
- sizeof intrinsics / sizeof intrinsics[0],
- sizeof intrinsics[0], compar)) != NULL)
- return item->func(instance, p2);
+ return &alsa_lisp_nil;
+}
- if ((item = bsearch(&key, snd_intrinsics,
- sizeof snd_intrinsics / sizeof snd_intrinsics[0],
- sizeof snd_intrinsics[0], compar)) != NULL)
- return item->func(instance, p2);
+static inline struct alisp_object * eval_cons(struct alisp_instance *instance, struct alisp_object * p)
+{
+ struct alisp_object * p1 = car(p);
- if ((p3 = get_object(instance, p1)) != &alsa_lisp_nil)
- return eval_func(instance, p3, p2);
- else
- lisp_warn(instance, "function `%s' is undefined", p1->value.id);
+ if (p1 != &alsa_lisp_nil && p1->type == ALISP_OBJ_IDENTIFIER) {
+ if (!strcmp(p1->value.id, "lambda"))
+ return p;
+
+ auto_garbage_collect(instance);
+
+ return eval_cons1(instance, p1, cdr(p));
}
return &alsa_lisp_nil;
{
struct alisp_object * p2;
- if (seq->type == ALISP_OBJ_CONS && seq->value.c.cdr->type == ALISP_OBJ_CONS)
- seq = seq->value.c.cdr;
+ if (seq->type == ALISP_OBJ_CONS && seq->value.c.car->type == ALISP_OBJ_CONS)
+ seq = seq->value.c.car;
if (seq->type == ALISP_OBJ_CONS) {
p2 = seq->value.c.car;
if (p2->type != ALISP_OBJ_STRING)
return lexpr;
}
-static inline struct alisp_object * new_result(struct alisp_instance * instance, int err)
-{
- return new_integer(instance, err);
-}
-
static struct alisp_object * new_result1(struct alisp_instance * instance, int err, const char *ptr_id, void *ptr)
{
struct alisp_object * lexpr, * p1;
typedef int (*snd_int_pp_strp_int_t)(void **rctl, const char *name, int mode);
typedef int (*snd_int_pp_p_t)(void **rctl, void *handle);
typedef int (*snd_int_p_t)(void *rctl);
+typedef char * (*snd_str_p_t)(void *rctl);
typedef int (*snd_int_intp_t)(int *val);
typedef int (*snd_int_str_t)(const char *str);
typedef int (*snd_int_int_strp_t)(int val, char **str);
handle = (void *)get_ptr(args, item->prefix);
if (handle == NULL)
return &alsa_lisp_nil;
- return new_result(instance, ((snd_int_p_t)item->xfunc)(handle));
+ return new_integer(instance, ((snd_int_p_t)item->xfunc)(handle));
+}
+
+static struct alisp_object * FA_str_p(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
+{
+ void *handle;
+
+ args = eval(instance, car(args));
+ handle = (void *)get_ptr(args, item->prefix);
+ if (handle == NULL)
+ return &alsa_lisp_nil;
+ return new_string(instance, ((snd_str_p_t)item->xfunc)(handle));
}
static struct alisp_object * FA_int_intp(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
if (args->type != ALISP_OBJ_STRING && args->type != ALISP_OBJ_IDENTIFIER)
return &alsa_lisp_nil;
err = ((snd_int_str_t)item->xfunc)(args->value.s);
- return new_result(instance, err);
+ return new_integer(instance, err);
}
static struct alisp_object * FA_int_int_strp(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
snd_ctl_elem_value_alloca(&value);
err = snd_hctl_elem_info(handle, info);
if (err < 0)
- return new_result(instance, err);
+ return new_integer(instance, err);
type = snd_ctl_elem_info_get_type(info);
count = snd_ctl_elem_info_get_count(info);
if (type == SND_CTL_ELEM_TYPE_IEC958) {
p1 = cdr(p1);
} while (p1 != &alsa_lisp_nil);
err = snd_hctl_elem_write(handle, value);
- return new_result(instance, err);
+ return new_integer(instance, err);
}
static struct alisp_object * FA_pcm_info(struct alisp_instance * instance, struct acall_table * item, struct alisp_object * args)
{ "hctl_open", &FA_int_pp_strp_int, (void *)&snd_hctl_open, "hctl" },
{ "hctl_open_ctl", &FA_int_pp_p, (void *)&snd_hctl_open_ctl, "hctl" },
{ "pcm_info", &FA_pcm_info, NULL, "pcm" },
+ { "pcm_name", &FA_str_p, (void *)&snd_pcm_name, "pcm" },
};
static int acall_compar(const void *p1, const void *p2)
+;
+; Toplevel configuration for the ALSA Ordinary Mixer Interface
+;
+
(defun sndo_include (hctl stream)
(setq info (Acall "ctl_card_info" (Acall "hctl_ctl" hctl)))
(if (= (Aerror info) 0)
(setq file (+ (path "data") "/alsa/cards/" (snd_card_alias driver) "/sndo" stream "-mixer.alisp"))
(setq r (include file))
(when (= r -2) (Asyserr "unable to find file " file))
- (unsetq driver file r)
)
(setq r (Aerror info))
- (unsetq info r)
)
+ (unsetq info driver file r)
+)
+
+(defun sndo_mixer_open_fcn (stream)
+ (setq fcn (+ "sndo" stream "_mixer_open"))
+ (setq r (if (exfun fcn) (call fcn hctl) 0))
+ (when (= r 0)
+ (setq hctls (if hctls (cons hctls (cons hctl)) hctl))
+ )
+ (unsetq fcn r)
+)
+
+(defun sndo_mixer_open_hctl (card stream)
+ (setq hctl (Acall "hctl_open" (+ "hw:" (str card)) nil))
+ (setq r (Aerror hctl))
+ (when (= r 0)
+ (setq hctl (Aresult hctl))
+ (setq r (sndo_include hctl stream))
+ (when (= r 0) (setq r (sndo_mixer_open_fcn stream)))
+ )
+ (unsetq hctl r)
+)
+
+(defun sndo_mixer_open_virtual (pcm stream)
+ (setq name (Acall "pcm_name" pcm))
+ (setq file (+ (path "data") "/alsa/virtual/" name "/sndo" stream "-mixer.alisp"))
+ (setq r (include file))
+ (when (= r -2) (Asyserr "unable to find file " file))
+ (when (= r 0) (setq r (sndo_mixer_open_fcn stream)))
+ (unsetq name file r)
)
(defun sndo_mixer_open1 (pcm stream)
(setq info (Acall "pcm_info" pcm))
(setq r (Aerror info))
(when (= r 0)
- (progn
- (setq info (Aresult info))
- (setq card (cdr (assq "card" info)))
- (setq r
- (if (< card 0)
- (+ (Acall "pcm_name" pcm) stream)
- (+ "hw:" (str card))
- )
+ (setq info (Aresult info))
+ (setq card (cdr (assq "card" info)))
+ (setq r
+ (if (< card 0)
+ (sndo_mixer_open_virtual pcm stream)
+ (sndo_mixer_open_hctl card stream)
)
- (unsetq card)
)
)
- (unsetq info r)
+ (unsetq info card r)
)
(defun sndo_mixer_open (ppcm cpcm)
- (setq pname (sndo_mixer_open1 ppcm "p"))
- (setq cname (sndo_mixer_open1 cpcm "c"))
- (setq phctl (Acall "hctl_open" pname nil))
- (if (= (Aerror phctl) 0)
+ (setq r (sndo_mixer_open1 ppcm "p"))
+ (when (= r 0) (setq r (sndo_mixer_open1 cpcm "c")))
+ (when (!= r 0) (sndo_mixer_close))
+ (unsetq r)
+)
+
+(defun sndo_mixer_close1 (hctl stream)
+ (when hctl
(progn
- (setq phctl (Aresult phctl))
- (setq chctl (Acall "hctl_open" cname nil))
- (if (= (Aerror chctl) 0)
- (progn
- (setq chctl (Aresult chctl))
- (setq hctls (cons phctl (cons chctl)))
- (setq r (sndo_include phctl "p"))
- (when (= r 0) (setq r (sndo_include chctl "c")))
- (when (= r 0) (setq r (if (exfun sndop_mixer_open) (sndop_mixer_open phctl) 0)))
- (when (= r 0)
- (progn
- (setq r (if (exfun sndoc_mixer_open) (sndoc_mixer_open chctl) 0))
- (unless (= r 0) (sndop_close phctl))
- )
- )
- (unless (= r 0) (sndo_close))
- (unsetq phctl chctl)
- (gc)
- (unsetq r)
- )
- (progn
- (Acall "hctl_close" (Aresult phctl))
- (setq r (Aerror chctl))
- (unsetq r)
- )
- )
+ (setq fcn (+ "sndo" stream "_mixer_close"))
+ (when (exfun fcn) (call fcn hctl))
+ (unsetq fcn)
+ (Acall "hctl_close" hctl)
)
- (setq r (Aerror phctl))
- (unsetq r)
)
)
(defun sndo_mixer_close nil
- (cond (exfun sndop_close) (sndop_close (nth 0 hctls)))
- (cond (exfun sndoc_close) (sndoc_close (nth 1 hctls)))
- (Acall "hctl_close" (nth 0 hctls))
- (Acall "hctl_close" (nth 1 hctls))
+ (sndo_mixer_close1 (nth 1 hctls) "c")
+ (sndo_mixer_close1 (nth 0 hctls) "p")
(unsetq hctls)
)
return snd_ctl_poll_descriptors(hctl->ctl, pfds, space);
}
+/**
+ * \brief get returned events from poll descriptors
+ * \param ctl HCTL handle
+ * \param pfds array of poll descriptors
+ * \param nfds count of poll descriptors
+ * \param revents returned events
+ * \return zero if success, otherwise a negative error code
+ */
+int snd_hctl_poll_descriptors_revents(snd_hctl_t *hctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
+{
+ assert(hctl);
+ return snd_ctl_poll_descriptors_revents(hctl->ctl, pfds, nfds, revents);
+}
+
static int snd_hctl_throw_event(snd_hctl_t *hctl, unsigned int mask,
snd_hctl_elem_t *elem)
{
*/
int sndo_mixer_poll_descriptors(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int space)
{
- //return snd_mixer_poll_descriptors(mixer->mixer, pfds, space);
- return -ENODEV;
+ int err, idx, res;
+
+ if (mixer->hctl_count > 0) {
+ for (idx = res = 0; idx < mixer->hctl_count && space > 0; idx++) {
+ err = snd_hctl_poll_descriptors(mixer->hctl[idx], pfds, space);
+ if (err < 0)
+ return err;
+ res += err;
+ space -= err;
+ }
+ return res;
+ } else {
+ struct alisp_seq_iterator *result;
+ long val;
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_poll_descriptors", "%i", space);
+ if (err < 0)
+ return err;
+ assert(0); /* FIXME: pass pfds to application */
+ err = alsa_lisp_seq_integer(result, &val);
+ return err < 0 ? err : val;
+ }
}
/**
*/
int sndo_mixer_poll_descriptors_revents(sndo_mixer_t *mixer, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
{
- //return snd_mixer_poll_descriptors_revents(mixer->mixer, pfds, nfds, revents);
- return -ENODEV;
+ int err, idx, count, res;
+
+ if (mixer->hctl_count > 0) {
+ for (idx = res = 0; idx < mixer->hctl_count && nfds > 0; idx++) {
+ err = snd_hctl_poll_descriptors_count(mixer->hctl[idx]);
+ if (err < 0)
+ return err;
+ count = err;
+ if (nfds < (unsigned int)err)
+ return -EINVAL;
+ err = snd_hctl_poll_descriptors_revents(mixer->hctl[idx], pfds, count, revents);
+ if (err < 0)
+ return err;
+ if (err != count)
+ return -EINVAL;
+ pfds += count;
+ nfds -= err;
+ revents += count;
+ res += count;
+ }
+ return res;
+ } else {
+ struct alisp_seq_iterator *result;
+ long val, tmp;
+
+ assert(0); /* FIXME: pass pfds to alisp too */
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_poll_descriptors_revents", "%i", nfds);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val);
+ if (err >= 0 && alsa_lisp_seq_count(result) > 1) {
+ alsa_lisp_seq_next(&result);
+ err = alsa_lisp_seq_integer(result, &tmp);
+ *revents = tmp;
+ } else {
+ *revents = 0;
+ }
+ return err < 0 ? err : val;
+ }
+}
+
+#define IOLINES 6
+
+static const char *name_table1[] = {
+ "Master",
+ "PCM",
+ "Line",
+ "Mic"
+ "CD",
+ "AUX"
+};
+
+#define SPEAKERS 14
+
+static const char *name_table2[] = {
+ "Front Left",
+ "Front Center Left",
+ "Front Center",
+ "Front Center Right",
+ "Front Right",
+ "Front Side Left",
+ "Front Side Right",
+ "Rear Side Left",
+ "Rear Side Right",
+ "Rear Left",
+ "Rear Center",
+ "Rear Right",
+ "LFE (Subwoofer)",
+ "Overhead"
+};
+
+#define CSOURCES 5
+
+static const char *name_table3[] = {
+ "Mic",
+ "Line",
+ "CD",
+ "AUX",
+ "Mix",
+};
+
+static int compose_string(char **result, const char *s1, const char *s2, const char *s3, const char *s4)
+{
+ int len = strlen(s1) + strlen(s2) + strlen(s3) + strlen(s4);
+ *result = malloc(len + 1);
+ if (*result == NULL)
+ return -ENOMEM;
+ strcpy(*result, s1);
+ strcat(*result, s2);
+ strcat(*result, s3);
+ strcat(*result, s4);
+ return 0;
+}
+
+/**
+ * \brief get ordinary mixer io control value
+ * \param mixer ordinary mixer handle
+ * \param type io type
+ * \param val returned value
+ * \return zero if success, otherwise a negative error code
+ */
+int sndo_mixer_io_get_name(enum sndo_mixer_io_type type, char **name)
+{
+ if (type < IOLINES * 0x40) {
+ int tmp = type / 0x40;
+ type %= 0x40;
+ if (type < SPEAKERS)
+ return compose_string(name, name_table1[tmp], " ", name_table2[type], " Volume");
+ } else if (type >= SNDO_MIO_CGAIN_FL && type < SNDO_MIO_CGAIN_FL + SPEAKERS) {
+ return compose_string(name, "Capture Gain ", name_table2[type - SNDO_MIO_CGAIN_FL], "", "");
+ } else if (type >= SNDO_MIO_CSOURCE_MIC && type < SNDO_MIO_CSOURCE_MIC + CSOURCES) {
+ return compose_string(name, "Capture Source ", name_table3[type - SNDO_MIO_CSOURCE_MIC], "", "");
+ }
+ return -ENOENT;
}
/**
*/
int sndo_mixer_io_get(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
{
- return -ENODEV;
+ struct alisp_seq_iterator *result;
+ long val1;
+ int err;
+
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set", "%i", type);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ *val = val1;
+ return 0;
}
/**
* \param val desired value
* \return zero if success, otherwise a negative error code
*/
-int sndo_mixer_io_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int val)
+int sndo_mixer_io_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
+{
+ struct alisp_seq_iterator *result;
+ long val1;
+ int err;
+
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set", "%i%i", type, *val);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ *val = val1;
+ return 0;
+}
+
+/**
+ * \brief try to set ordinary mixer io control value
+ * \param mixer ordinary mixer handle
+ * \param type io type
+ * \param val desired value
+ * \return zero if success, otherwise a negative error code
+ *
+ * This function does not update the value.
+ * It only returns the real value which will be set.
+ */
+int sndo_mixer_io_try_set(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
+{
+ struct alisp_seq_iterator *result;
+ long val1;
+ int err;
+
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_try_set", "%i%i", type, *val);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ *val = val1;
+ return 0;
+}
+
+/**
+ * \brief get ordinary mixer io control value in dB (decibel units)
+ * \param mixer ordinary mixer handle
+ * \param type io type
+ * \param val returned value in dB
+ * \return zero if success, otherwise a negative error code
+ */
+int sndo_mixer_io_get_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
+{
+ struct alisp_seq_iterator *result;
+ long val1;
+ int err;
+
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set_dB", "%i", type);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ *val = val1;
+ return 0;
+}
+
+/**
+ * \brief set ordinary mixer io control value in dB (decibel units)
+ * \param mixer ordinary mixer handle
+ * \param type io type
+ * \param val desired value in dB
+ * \return zero if success, otherwise a negative error code
+ */
+int sndo_mixer_io_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
+{
+ struct alisp_seq_iterator *result;
+ long val1;
+ int err;
+
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_set", "%i%i", type, *val);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ *val = val1;
+ return 0;
+}
+
+/**
+ * \brief try to set ordinary mixer io control value in dB (decibel units)
+ * \param mixer ordinary mixer handle
+ * \param type io type
+ * \param val desired and returned value in dB
+ * \return zero if success, otherwise a negative error code
+ *
+ * This function does not update the value.
+ * It only returns the real value which will be set.
+ */
+int sndo_mixer_io_try_set_dB(sndo_mixer_t *mixer, enum sndo_mixer_io_type type, int *val)
{
- return -ENODEV;
+ struct alisp_seq_iterator *result;
+ long val1;
+ int err;
+
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_try_set", "%i%i", type, *val);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ *val = val1;
+ return 0;
}
/**
*/
int sndo_mixer_io_change(sndo_mixer_t *mixer, enum sndo_mixer_io_type *changed, int changed_array_size)
{
- return -ENODEV;
+ struct alisp_seq_iterator *result;
+ long val1;
+ int err;
+
+ err = alsa_lisp_function(mixer->alisp, &result, "sndo_mixer_io_change", "%i", changed_array_size);
+ if (err < 0)
+ return err;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ if (val1 < 0)
+ return val1;
+ while (changed_array_size-- > 0) {
+ *changed = val1;
+ if (!alsa_lisp_seq_next(&result))
+ break;
+ err = alsa_lisp_seq_integer(result, &val1);
+ if (err < 0)
+ return err;
+ }
+ return 0;
}
static void help(void)
{
printf(
-"Usage: omixer [OPTION]...\n"
+"Usage: omixer [OPTION]...\n\n"
"-h,--help help\n"
"-P,--pname playback PCM device\n"
"-C,--cname capture PCM device\n"
-"\n");
+);
}
int main(int argc, char *argv[])