filter-chain: add scale property to volume

Some controls will scale the volume so add a scale property to undo
this scaling before setting the value.

See #3434
This commit is contained in:
Wim Taymans 2023-10-06 11:30:15 +02:00
parent bf9efb78ab
commit f03317e86e

View file

@ -83,10 +83,10 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
* inputs = [ <portname> ... ] * inputs = [ <portname> ... ]
* outputs = [ <portname> ... ] * outputs = [ <portname> ... ]
* capture.volumes = [ * capture.volumes = [
* { control = <portname> min = <value> max = <value> } ... * { control = <portname> min = <value> max = <value> scale = <scale> } ...
* ] * ]
* playback.volumes = [ * playback.volumes = [
* { control = <portname> min = <value> max = <value> } ... * { control = <portname> min = <value> max = <value> scale = <scale> } ...
* ] * ]
* } * }
*\endcode *\endcode
@ -152,6 +152,11 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
* The min and max values (defaults 0.0 and 1.0) respectively can be used to scale * The min and max values (defaults 0.0 and 1.0) respectively can be used to scale
* and translate the volume min and max values. * and translate the volume min and max values.
* *
* Normally the control values are linear and it is assumed that the plugin does not
* perform any scaling to the values. This can be changed with the scale property. By
* default this is linear but it can be set to cubic when the control applies a
* cubic transformation.
*
* ## Builtin filters * ## Builtin filters
* *
* There are some useful builtin filters available. You select them with the label * There are some useful builtin filters available. You select them with the label
@ -644,11 +649,14 @@ struct volume {
bool mute; bool mute;
uint32_t n_volumes; uint32_t n_volumes;
float volumes[SPA_AUDIO_MAX_CHANNELS]; float volumes[SPA_AUDIO_MAX_CHANNELS];
float min[SPA_AUDIO_MAX_CHANNELS];
float max[SPA_AUDIO_MAX_CHANNELS];
uint32_t n_ports; uint32_t n_ports;
struct port *ports[SPA_AUDIO_MAX_CHANNELS]; struct port *ports[SPA_AUDIO_MAX_CHANNELS];
float min[SPA_AUDIO_MAX_CHANNELS];
float max[SPA_AUDIO_MAX_CHANNELS];
#define SCALE_LINEAR 0
#define SCALE_CUBIC 1
int scale[SPA_AUDIO_MAX_CHANNELS];
}; };
struct graph { struct graph {
@ -1135,7 +1143,13 @@ static int sync_volume(struct graph *graph, struct volume *vol)
uint32_t n_port = i % vol->n_ports, n_hndl; uint32_t n_port = i % vol->n_ports, n_hndl;
struct port *p = vol->ports[n_port]; struct port *p = vol->ports[n_port];
float v = vol->mute ? 0.0f : vol->volumes[i]; float v = vol->mute ? 0.0f : vol->volumes[i];
switch (vol->scale[n_port]) {
case SCALE_CUBIC:
v = cbrt(v);
break;
}
v = v * (vol->max[n_port] - vol->min[n_port]) + vol->min[n_port]; v = v * (vol->max[n_port] - vol->min[n_port]) + vol->min[n_port];
n_hndl = SPA_MAX(1u, p->node->n_hndl); n_hndl = SPA_MAX(1u, p->node->n_hndl);
res += port_set_control_value(p, &v, i % n_hndl); res += port_set_control_value(p, &v, i % n_hndl);
} }
@ -1933,14 +1947,16 @@ static void link_free(struct link *link)
/** /**
* { * {
* control = [name:][portname] * control = [name:][portname]
* min = ... * min = <float, defaukt 0.0>
* max = ... * max = <float, default 1.0>
* scale = <string, default "linear", options "linear","cubic">
* } * }
*/ */
static int parse_volume(struct graph *graph, struct spa_json *json, bool capture) static int parse_volume(struct graph *graph, struct spa_json *json, bool capture)
{ {
char key[256]; char key[256];
char control[256] = ""; char control[256] = "";
char scale[64] = "linear";
float min = 0.0f, max = 1.0f; float min = 0.0f, max = 1.0f;
const char *val; const char *val;
struct node *def_control; struct node *def_control;
@ -1971,6 +1987,12 @@ static int parse_volume(struct graph *graph, struct spa_json *json, bool capture
return -EINVAL; return -EINVAL;
} }
} }
else if (spa_streq(key, "scale")) {
if (spa_json_get_string(json, scale, sizeof(scale)) <= 0) {
pw_log_error("scale expects a string");
return -EINVAL;
}
}
else if (spa_json_next(json, &val) < 0) else if (spa_json_next(json, &val) < 0)
break; break;
} }
@ -1986,10 +2008,18 @@ static int parse_volume(struct graph *graph, struct spa_json *json, bool capture
} }
if (vol->n_ports >= SPA_AUDIO_MAX_CHANNELS) { if (vol->n_ports >= SPA_AUDIO_MAX_CHANNELS) {
pw_log_error("too many volume controls"); pw_log_error("too many volume controls");
return -ENOENT; return -ENOSPC;
} }
pw_log_info("volume %d: \"%s:%s\" min:%f max:%f", vol->n_ports, port->node->name, if (spa_streq(scale, "linear")) {
port->node->desc->desc->ports[port->p].name, min, max); vol->scale[vol->n_ports] = SCALE_LINEAR;
} else if (spa_streq(scale, "cubic")) {
vol->scale[vol->n_ports] = SCALE_CUBIC;
} else {
pw_log_error("Invalid scale value '%s', use one of linear or cubic", scale);
return -EINVAL;
}
pw_log_info("volume %d: \"%s:%s\" min:%f max:%f scale:%s", vol->n_ports, port->node->name,
port->node->desc->desc->ports[port->p].name, min, max, scale);
vol->ports[vol->n_ports] = port; vol->ports[vol->n_ports] = port;
vol->min[vol->n_ports] = min; vol->min[vol->n_ports] = min;