mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
module-filter-chain: add raw biquad
Add bq_raw that allows access to the raw biquad filter values. Fixes #3139
This commit is contained in:
parent
950c4487e9
commit
880c1b0bd6
2 changed files with 336 additions and 90 deletions
|
|
@ -162,7 +162,11 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
*
|
||||
* All biquad filters have an input port "In" and an output port "Out". They have
|
||||
* a "Freq", "Q" and "Gain" control. Their meaning depends on the particular biquad that
|
||||
* is used. The following labels can be used:
|
||||
* is used. The biquads also have "b0", "b1", "b2", "a0", "a1" and "a2" ports that
|
||||
* are read-only except for the bq_raw biquad, which can configure default values
|
||||
* depending on the graph rate and change those at runtime.
|
||||
*
|
||||
* The following labels can be used:
|
||||
*
|
||||
* - `bq_lowpass` a lowpass filter.
|
||||
* - `bq_highpass` a highpass filter.
|
||||
|
|
@ -172,6 +176,30 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
* - `bq_peaking` a peaking filter.
|
||||
* - `bq_notch` a notch filter.
|
||||
* - `bq_allpass` an allpass filter.
|
||||
* - `bq_raw` a raw biquad filter. You need a config section to specify coefficients
|
||||
* per sample rate. The coefficients of the sample rate closest to the
|
||||
* graph rate are selected:
|
||||
*
|
||||
*\code{.unparsed}
|
||||
* filter.graph = {
|
||||
* nodes = [
|
||||
* {
|
||||
* type = builtin
|
||||
* name = ...
|
||||
* label = bq_raw
|
||||
* config = {
|
||||
* coefficients = [
|
||||
* { rate = 44100, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
|
||||
* { rate = 48000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
|
||||
* { rate = 192000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }
|
||||
* ]
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
*\endcode
|
||||
*
|
||||
* ### Convolver
|
||||
*
|
||||
|
|
@ -1006,6 +1034,20 @@ static void node_control_changed(struct node *node)
|
|||
node->control_changed = false;
|
||||
}
|
||||
|
||||
static void update_props_param(struct impl *impl)
|
||||
{
|
||||
struct graph *graph = &impl->graph;
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod_dynamic_builder b;
|
||||
const struct spa_pod *params[1];
|
||||
|
||||
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
|
||||
params[0] = get_props_param(graph, &b.b);
|
||||
|
||||
pw_stream_update_params(impl->capture, params, 1);
|
||||
spa_pod_dynamic_builder_clean(&b);
|
||||
}
|
||||
|
||||
static void param_props_changed(struct impl *impl, const struct spa_pod *param)
|
||||
{
|
||||
struct spa_pod_object *obj = (struct spa_pod_object *) param;
|
||||
|
|
@ -1018,19 +1060,12 @@ static void param_props_changed(struct impl *impl, const struct spa_pod *param)
|
|||
changed += parse_params(graph, &prop->value);
|
||||
}
|
||||
if (changed > 0) {
|
||||
uint8_t buffer[1024];
|
||||
struct spa_pod_dynamic_builder b;
|
||||
const struct spa_pod *params[1];
|
||||
struct node *node;
|
||||
|
||||
spa_list_for_each(node, &graph->node_list, link)
|
||||
node_control_changed(node);
|
||||
|
||||
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
|
||||
params[0] = get_props_param(graph, &b.b);
|
||||
|
||||
pw_stream_update_params(impl->capture, params, 1);
|
||||
spa_pod_dynamic_builder_clean(&b);
|
||||
update_props_param(impl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1847,6 +1882,7 @@ static int graph_instantiate(struct graph *graph)
|
|||
d->control_changed(node->hndl[i]);
|
||||
}
|
||||
}
|
||||
update_props_param(impl);
|
||||
return 0;
|
||||
error:
|
||||
graph_cleanup(graph);
|
||||
|
|
|
|||
|
|
@ -32,10 +32,13 @@ struct builtin {
|
|||
unsigned long rate;
|
||||
float *port[64];
|
||||
|
||||
int type;
|
||||
struct biquad bq;
|
||||
float freq;
|
||||
float Q;
|
||||
float gain;
|
||||
float b0, b1, b2;
|
||||
float a0, a1, a2;
|
||||
};
|
||||
|
||||
static void *builtin_instantiate(const struct fc_descriptor * Descriptor,
|
||||
|
|
@ -215,6 +218,159 @@ static const struct fc_descriptor mixer_desc = {
|
|||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/** biquads */
|
||||
static int bq_type_from_name(const char *name)
|
||||
{
|
||||
if (spa_streq(name, "bq_lowpass"))
|
||||
return BQ_LOWPASS;
|
||||
if (spa_streq(name, "bq_highpass"))
|
||||
return BQ_HIGHPASS;
|
||||
if (spa_streq(name, "bq_bandpass"))
|
||||
return BQ_BANDPASS;
|
||||
if (spa_streq(name, "bq_lowshelf"))
|
||||
return BQ_LOWSHELF;
|
||||
if (spa_streq(name, "bq_highshelf"))
|
||||
return BQ_HIGHSHELF;
|
||||
if (spa_streq(name, "bq_peaking"))
|
||||
return BQ_PEAKING;
|
||||
if (spa_streq(name, "bq_notch"))
|
||||
return BQ_NOTCH;
|
||||
if (spa_streq(name, "bq_allpass"))
|
||||
return BQ_ALLPASS;
|
||||
if (spa_streq(name, "bq_raw"))
|
||||
return BQ_NONE;
|
||||
return BQ_NONE;
|
||||
}
|
||||
|
||||
static void bq_raw_update(struct builtin *impl, float b0, float b1, float b2,
|
||||
float a0, float a1, float a2)
|
||||
{
|
||||
struct biquad *bq = &impl->bq;
|
||||
impl->b0 = b0;
|
||||
impl->b1 = b1;
|
||||
impl->b2 = b2;
|
||||
impl->a0 = a0;
|
||||
impl->a1 = a1;
|
||||
impl->a2 = a2;
|
||||
if (a0 != 0.0f)
|
||||
a0 = 1.0f / a0;
|
||||
bq->b0 = impl->b0 * a0;
|
||||
bq->b1 = impl->b1 * a0;
|
||||
bq->b2 = impl->b2 * a0;
|
||||
bq->a1 = impl->a1 * a0;
|
||||
bq->a2 = impl->a2 * a0;
|
||||
bq->x1 = bq->x2 = bq->y1 = bq->y2 = 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* config = {
|
||||
* coefficients = [
|
||||
* { rate = 44100, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
|
||||
* { rate = 48000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
|
||||
* { rate = 192000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
static void *bq_instantiate(const struct fc_descriptor * Descriptor,
|
||||
unsigned long SampleRate, int index, const char *config)
|
||||
{
|
||||
struct builtin *impl;
|
||||
struct spa_json it[4];
|
||||
const char *val;
|
||||
char key[256];
|
||||
uint32_t best_rate = 0;
|
||||
|
||||
impl = calloc(1, sizeof(*impl));
|
||||
if (impl == NULL)
|
||||
return NULL;
|
||||
|
||||
impl->rate = SampleRate;
|
||||
impl->b0 = impl->a0 = 1.0f;
|
||||
impl->type = bq_type_from_name(Descriptor->name);
|
||||
|
||||
if (config == NULL)
|
||||
goto error;
|
||||
|
||||
spa_json_init(&it[0], config, strlen(config));
|
||||
if (spa_json_enter_object(&it[0], &it[1]) <= 0)
|
||||
goto error;
|
||||
|
||||
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
|
||||
if (spa_streq(key, "coefficients")) {
|
||||
if (spa_json_enter_array(&it[1], &it[2]) <= 0) {
|
||||
pw_log_error("biquads:coefficients require an array");
|
||||
goto error;
|
||||
}
|
||||
while (spa_json_enter_object(&it[2], &it[3]) > 0) {
|
||||
int32_t rate = 0;
|
||||
float b0 = 1.0f, b1 = 0.0f, b2 = 0.0f;
|
||||
float a0 = 1.0f, a1 = 0.0f, a2 = 0.0f;
|
||||
|
||||
while (spa_json_get_string(&it[3], key, sizeof(key)) > 0) {
|
||||
if (spa_streq(key, "rate")) {
|
||||
if (spa_json_get_int(&it[3], &rate) <= 0) {
|
||||
pw_log_error("biquads:rate requires a number");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "b0")) {
|
||||
if (spa_json_get_float(&it[3], &b0) <= 0) {
|
||||
pw_log_error("biquads:b0 requires a float");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "b1")) {
|
||||
if (spa_json_get_float(&it[3], &b1) <= 0) {
|
||||
pw_log_error("biquads:b1 requires a float");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "b2")) {
|
||||
if (spa_json_get_float(&it[3], &b2) <= 0) {
|
||||
pw_log_error("biquads:b2 requires a float");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "a0")) {
|
||||
if (spa_json_get_float(&it[3], &a0) <= 0) {
|
||||
pw_log_error("biquads:a0 requires a float");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "a1")) {
|
||||
if (spa_json_get_float(&it[3], &a1) <= 0) {
|
||||
pw_log_error("biquads:a1 requires a float");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "a2")) {
|
||||
if (spa_json_get_float(&it[3], &a2) <= 0) {
|
||||
pw_log_error("biquads:a0 requires a float");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_json_next(&it[1], &val) < 0)
|
||||
break;
|
||||
}
|
||||
if (labs((long)rate - (long)SampleRate) <
|
||||
labs((long)best_rate - (long)SampleRate)) {
|
||||
best_rate = rate;
|
||||
bq_raw_update(impl, b0, b1, b2, a0, a1, a2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (spa_json_next(&it[1], &val) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return impl;
|
||||
error:
|
||||
free(impl);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define BQ_NUM_PORTS 11
|
||||
static struct fc_port bq_ports[] = {
|
||||
{ .index = 0,
|
||||
.name = "Out",
|
||||
|
|
@ -240,176 +396,227 @@ static struct fc_port bq_ports[] = {
|
|||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 0.0f, .min = -120.0f, .max = 20.0f,
|
||||
},
|
||||
{ .index = 5,
|
||||
.name = "b0",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = -10.0f, .max = 10.0f,
|
||||
},
|
||||
{ .index = 6,
|
||||
.name = "b1",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 0.0f, .min = -10.0f, .max = 10.0f,
|
||||
},
|
||||
{ .index = 7,
|
||||
.name = "b2",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 0.0f, .min = -10.0f, .max = 10.0f,
|
||||
},
|
||||
{ .index = 8,
|
||||
.name = "a0",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = -10.0f, .max = 10.0f,
|
||||
},
|
||||
{ .index = 9,
|
||||
.name = "a1",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 0.0f, .min = -10.0f, .max = 10.0f,
|
||||
},
|
||||
{ .index = 10,
|
||||
.name = "a2",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 0.0f, .min = -10.0f, .max = 10.0f,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static void bq_run(struct builtin *impl, unsigned long samples, int type)
|
||||
static void bq_freq_update(struct builtin *impl, int type, float freq, float Q, float gain)
|
||||
{
|
||||
struct biquad *bq = &impl->bq;
|
||||
float *out = impl->port[0];
|
||||
float *in = impl->port[1];
|
||||
float freq = impl->port[2][0];
|
||||
float Q = impl->port[3][0];
|
||||
float gain = impl->port[4][0];
|
||||
|
||||
if (impl->freq != freq || impl->Q != Q || impl->gain != gain) {
|
||||
impl->freq = freq;
|
||||
impl->Q = Q;
|
||||
impl->gain = gain;
|
||||
biquad_set(bq, type, freq * 2 / impl->rate, Q, gain);
|
||||
impl->port[5][0] = impl->b0 = bq->b0;
|
||||
impl->port[6][0] = impl->b1 = bq->b1;
|
||||
impl->port[7][0] = impl->b2 = bq->b2;
|
||||
impl->port[8][0] = impl->a0 = 1.0f;
|
||||
impl->port[9][0] = impl->a1 = bq->a1;
|
||||
impl->port[10][0] = impl->a2 = bq->a2;
|
||||
}
|
||||
|
||||
static void bq_activate(void * Instance)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
if (impl->type == BQ_NONE) {
|
||||
float b0, b1, b2, a0, a1, a2;
|
||||
b0 = impl->port[5][0];
|
||||
b1 = impl->port[6][0];
|
||||
b2 = impl->port[7][0];
|
||||
a0 = impl->port[8][0];
|
||||
a1 = impl->port[9][0];
|
||||
a2 = impl->port[10][0];
|
||||
bq_raw_update(impl, b0, b1, b2, a0, a1, a2);
|
||||
} else {
|
||||
float freq = impl->port[2][0];
|
||||
float Q = impl->port[3][0];
|
||||
float gain = impl->port[4][0];
|
||||
bq_freq_update(impl, impl->type, freq, Q, gain);
|
||||
}
|
||||
}
|
||||
|
||||
static void bq_run(void *Instance, unsigned long samples)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
struct biquad *bq = &impl->bq;
|
||||
float *out = impl->port[0];
|
||||
float *in = impl->port[1];
|
||||
|
||||
if (impl->type == BQ_NONE) {
|
||||
float b0, b1, b2, a0, a1, a2;
|
||||
b0 = impl->port[5][0];
|
||||
b1 = impl->port[6][0];
|
||||
b2 = impl->port[7][0];
|
||||
a0 = impl->port[8][0];
|
||||
a1 = impl->port[9][0];
|
||||
a2 = impl->port[10][0];
|
||||
if (impl->b0 != b0 || impl->b1 != b1 || impl->b2 != b2 ||
|
||||
impl->a0 != a0 || impl->a1 != a1 || impl->a2 != a2) {
|
||||
bq_raw_update(impl, b0, b1, b2, a0, a1, a2);
|
||||
}
|
||||
} else {
|
||||
float freq = impl->port[2][0];
|
||||
float Q = impl->port[3][0];
|
||||
float gain = impl->port[4][0];
|
||||
if (impl->freq != freq || impl->Q != Q || impl->gain != gain)
|
||||
bq_freq_update(impl, impl->type, freq, Q, gain);
|
||||
}
|
||||
dsp_ops_biquad_run(dsp_ops, bq, out, in, samples);
|
||||
}
|
||||
|
||||
/** bq_lowpass */
|
||||
static void bq_lowpass_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_LOWPASS);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_lowpass_desc = {
|
||||
.name = "bq_lowpass",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_lowpass_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/** bq_highpass */
|
||||
static void bq_highpass_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_HIGHPASS);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_highpass_desc = {
|
||||
.name = "bq_highpass",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_highpass_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/** bq_bandpass */
|
||||
static void bq_bandpass_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_BANDPASS);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_bandpass_desc = {
|
||||
.name = "bq_bandpass",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_bandpass_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/** bq_lowshelf */
|
||||
static void bq_lowshelf_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_LOWSHELF);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_lowshelf_desc = {
|
||||
.name = "bq_lowshelf",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_lowshelf_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/** bq_highshelf */
|
||||
static void bq_highshelf_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_HIGHSHELF);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_highshelf_desc = {
|
||||
.name = "bq_highshelf",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_highshelf_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/** bq_peaking */
|
||||
static void bq_peaking_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_PEAKING);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_peaking_desc = {
|
||||
.name = "bq_peaking",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_peaking_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/** bq_notch */
|
||||
static void bq_notch_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_NOTCH);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_notch_desc = {
|
||||
.name = "bq_notch",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_notch_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
|
||||
/** bq_allpass */
|
||||
static void bq_allpass_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
bq_run(impl, SampleCount, BQ_ALLPASS);
|
||||
}
|
||||
|
||||
static const struct fc_descriptor bq_allpass_desc = {
|
||||
.name = "bq_allpass",
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.run = bq_allpass_run,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
/* bq_raw */
|
||||
static const struct fc_descriptor bq_raw_desc = {
|
||||
.name = "bq_raw",
|
||||
|
||||
.n_ports = BQ_NUM_PORTS,
|
||||
.ports = bq_ports,
|
||||
|
||||
.instantiate = bq_instantiate,
|
||||
.connect_port = builtin_connect_port,
|
||||
.activate = bq_activate,
|
||||
.run = bq_run,
|
||||
.cleanup = builtin_cleanup,
|
||||
};
|
||||
|
||||
|
|
@ -958,6 +1165,7 @@ static const struct fc_descriptor delay_desc = {
|
|||
.cleanup = delay_cleanup,
|
||||
};
|
||||
|
||||
/* invert */
|
||||
static void invert_run(void * Instance, unsigned long SampleCount)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
|
|
@ -1019,6 +1227,8 @@ static const struct fc_descriptor * builtin_descriptor(unsigned long Index)
|
|||
return &delay_desc;
|
||||
case 12:
|
||||
return &invert_desc;
|
||||
case 13:
|
||||
return &bq_raw_desc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue