If available, use the hardware output.level to control the volume.

With this change, there's a single outputs.level control: either the
hardware one or software one. Consequently, there can't be control
name clashes and there's no need to move hardware's top-level controls
into the "hw/" group.
This commit is contained in:
Alexandre Ratchov 2020-04-13 07:48:18 +02:00
parent fab9b7cb7e
commit e5f270a89f
3 changed files with 84 additions and 18 deletions

View File

@ -349,8 +349,26 @@ dev_midi_vol(struct dev *d, struct slot *s)
void
dev_midi_master(struct dev *d)
{
struct ctl *c;
unsigned int master, v;
struct sysex x;
if (d->master_enabled)
master = d->master;
else {
master = 0;
for (c = d->ctl_list; c != NULL; c = c->next) {
if (c->type != CTL_NUM ||
strcmp(c->group, "") != 0 ||
strcmp(c->node0.name, "output") != 0 ||
strcmp(c->func, "level") != 0)
continue;
v = (c->curval * 127 + c->maxval / 2) / c->maxval;
if (master < v)
master = v;
}
}
memset(&x, 0, sizeof(struct sysex));
x.start = SYSEX_START;
x.type = SYSEX_TYPE_RT;
@ -358,7 +376,7 @@ dev_midi_master(struct dev *d)
x.id0 = SYSEX_CONTROL;
x.id1 = SYSEX_MASTER;
x.u.master.fine = 0;
x.u.master.coarse = d->master;
x.u.master.coarse = master;
x.u.master.end = SYSEX_END;
midi_send(d->midi, (unsigned char *)&x, SYSEX_SIZE(master));
}
@ -442,8 +460,10 @@ dev_midi_omsg(void *arg, unsigned char *msg, int len)
if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
if (len == SYSEX_SIZE(master)) {
dev_master(d, x->u.master.coarse);
dev_onval(d, CTLADDR_MASTER,
x->u.master.coarse);
if (d->master_enabled) {
dev_onval(d, CTLADDR_MASTER,
x->u.master.coarse);
}
}
return;
}
@ -655,7 +675,8 @@ dev_mix_adjvol(struct dev *d)
}
if (weight > i->opt->maxweight)
weight = i->opt->maxweight;
i->mix.weight = ADATA_MUL(weight, MIDI_TO_ADATA(d->master));
i->mix.weight = d->master_enabled ?
ADATA_MUL(weight, MIDI_TO_ADATA(d->master)) : weight;
#ifdef DEBUG
if (log_level >= 3) {
slot_log(i);
@ -946,15 +967,30 @@ dev_onmove(struct dev *d, int delta)
void
dev_master(struct dev *d, unsigned int master)
{
struct ctl *c;
unsigned int v;
if (log_level >= 2) {
dev_log(d);
log_puts(": master volume set to ");
log_putu(master);
log_puts("\n");
}
d->master = master;
if (d->mode & MODE_PLAY)
dev_mix_adjvol(d);
if (d->master_enabled) {
d->master = master;
if (d->mode & MODE_PLAY)
dev_mix_adjvol(d);
} else {
for (c = d->ctl_list; c != NULL; c = c->next) {
if (c->type != CTL_NUM ||
strcmp(c->group, "") != 0 ||
strcmp(c->node0.name, "output") != 0 ||
strcmp(c->func, "level") != 0)
continue;
v = (master * c->maxval + 64) / 127;
dev_setctl(d, c->addr, v);
}
}
}
/*
@ -1121,6 +1157,7 @@ dev_open(struct dev *d)
int i;
char name[CTL_NAMEMAX];
d->master_enabled = 0;
d->mode = d->reqmode;
d->round = d->reqround;
d->bufsz = d->reqbufsz;
@ -1149,8 +1186,6 @@ dev_open(struct dev *d)
name, -1, "level",
NULL, -1, 127, d->slot[i].vol);
}
dev_addctl(d, "", CTL_NUM,
CTLADDR_MASTER, "output", -1, "level", NULL, -1, 127, d->master);
d->pstate = DEV_INIT;
return 1;
@ -2337,8 +2372,36 @@ dev_rmctl(struct dev *d, int addr)
void
dev_ctlsync(struct dev *d)
{
struct ctl *c;
struct ctlslot *s;
int i;
int found, i;
found = 0;
for (c = d->ctl_list; c != NULL; c = c->next) {
if (c->addr != CTLADDR_MASTER &&
c->type == CTL_NUM &&
strcmp(c->group, "") == 0 &&
strcmp(c->node0.name, "output") == 0 &&
strcmp(c->func, "level") == 0)
found = 1;
}
if (d->master_enabled && found) {
if (log_level >= 2) {
dev_log(d);
log_puts(": software master level control disabled\n");
}
d->master_enabled = 0;
dev_rmctl(d, CTLADDR_MASTER);
} else if (!d->master_enabled && !found) {
if (log_level >= 2) {
dev_log(d);
log_puts(": software master level control enabled\n");
}
d->master_enabled = 1;
dev_addctl(d, "", CTL_NUM, CTLADDR_MASTER,
"output", -1, "level", NULL, -1, 127, d->master);
}
for (s = d->ctlslot, i = DEV_NCTLSLOT; i > 0; i--, s++) {
if (s->ops)
@ -2392,8 +2455,10 @@ dev_setctl(struct dev *d, int addr, int val)
dev_ref(d);
} else {
if (addr == CTLADDR_MASTER) {
dev_master(d, val);
dev_midi_master(d);
if (d->master_enabled) {
dev_master(d, val);
dev_midi_master(d);
}
} else {
num = addr - CTLADDR_SLOT_LEVEL(0);
slot_setvol(d->slot + num, val);

View File

@ -244,7 +244,9 @@ struct dev {
#define MMC_START 2 /* attempting to start */
#define MMC_RUN 3 /* started */
unsigned int tstate; /* one of above */
unsigned int master; /* master volume controller */
unsigned int master; /* software vol. knob */
unsigned int master_enabled; /* 1 if h/w has no vo. knob */
/*
* control

View File

@ -65,18 +65,17 @@ dev_sioctl_ondesc(void *arg, struct sioctl_desc *desc, int val)
dev_rmctl(d, addr);
/*
* prefix group names we use (top-level and "app") with "hw."
* prefix group names we use (currently "app") with "hw/"
* to ensure that all controls have unique names when multiple
* sndiod's are chained
*/
if (desc->group[0] == 0)
group = GROUP_PREFIX;
else {
if (strcmp(desc->group, "app") == 0) {
group = group_buf;
if (snprintf(group_buf, CTL_NAMEMAX, GROUP_PREFIX "/%s",
desc->group) >= CTL_NAMEMAX)
return;
}
} else
group = desc->group;
dev_addctl(d, group, desc->type, addr,
desc->node0.name, desc->node0.unit, desc->func,