mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-03 09:01:54 -05:00
filter-graph: add a simple noise gate
This commit is contained in:
parent
616db9809e
commit
ef5d9ff028
2 changed files with 148 additions and 0 deletions
|
|
@ -60,6 +60,9 @@ struct builtin {
|
||||||
int mode;
|
int mode;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
float last;
|
float last;
|
||||||
|
|
||||||
|
float gate;
|
||||||
|
float hold;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *builtin_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor,
|
static void *builtin_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor,
|
||||||
|
|
@ -2876,6 +2879,136 @@ static const struct spa_fga_descriptor zeroramp_desc = {
|
||||||
.cleanup = builtin_cleanup,
|
.cleanup = builtin_cleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* noisegate */
|
||||||
|
static struct spa_fga_port noisegate_ports[] = {
|
||||||
|
{ .index = 0,
|
||||||
|
.name = "In",
|
||||||
|
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 1,
|
||||||
|
.name = "Out",
|
||||||
|
.flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 2,
|
||||||
|
.name = "Open Threshold",
|
||||||
|
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
|
||||||
|
.def = 0.004f, .min = 0.0f, .max = 1.0f
|
||||||
|
},
|
||||||
|
{ .index = 3,
|
||||||
|
.name = "Close Threshold",
|
||||||
|
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
|
||||||
|
.def = 0.003f, .min = 0.0f, .max = 1.0f
|
||||||
|
},
|
||||||
|
{ .index = 4,
|
||||||
|
.name = "Attack (s)",
|
||||||
|
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
|
||||||
|
.def = 0.005f, .min = 0.0f, .max = 1.0f
|
||||||
|
},
|
||||||
|
{ .index = 5,
|
||||||
|
.name = "Hold (s)",
|
||||||
|
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
|
||||||
|
.def = 0.050f, .min = 0.0f, .max = 1.0f
|
||||||
|
},
|
||||||
|
{ .index = 6,
|
||||||
|
.name = "Release (s)",
|
||||||
|
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
|
||||||
|
.def = 0.010f, .min = 0.0f, .max = 1.0f
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void noisegate_run(void * Instance, unsigned long SampleCount)
|
||||||
|
{
|
||||||
|
struct builtin *impl = Instance;
|
||||||
|
float *in = impl->port[0];
|
||||||
|
float *out = impl->port[1];
|
||||||
|
unsigned long n;
|
||||||
|
float o_thres = impl->port[2][0];
|
||||||
|
float c_thres = impl->port[3][0];
|
||||||
|
float gate, hold, o_rate, c_rate, level;
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
if (out == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (in == NULL) {
|
||||||
|
memset(out, 0, SampleCount * sizeof(float));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_rate = 1.0f / (impl->port[4][0] * impl->rate);
|
||||||
|
c_rate = 1.0f / (impl->port[6][0] * impl->rate);
|
||||||
|
gate = impl->gate;
|
||||||
|
hold = impl->hold;
|
||||||
|
mode = impl->mode;
|
||||||
|
level = impl->last;
|
||||||
|
|
||||||
|
for (n = 0; n < SampleCount; n++) {
|
||||||
|
float lev = fabsf(in[n]);
|
||||||
|
|
||||||
|
if (lev > level)
|
||||||
|
level = lev;
|
||||||
|
else
|
||||||
|
level = lev * 0.05f + level * 0.95f;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
/* closed */
|
||||||
|
if (level >= o_thres)
|
||||||
|
mode = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
/* opening */
|
||||||
|
gate += o_rate;
|
||||||
|
if (gate >= 1.0f) {
|
||||||
|
gate = 1.0f;
|
||||||
|
mode = 2;
|
||||||
|
hold = impl->port[5][0] * impl->rate;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* hold */
|
||||||
|
hold -= 1.0f;
|
||||||
|
if (hold <= 0.0f)
|
||||||
|
mode = 3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
/* open */
|
||||||
|
if (level < c_thres)
|
||||||
|
mode = 4;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
/* closing */
|
||||||
|
gate -= c_rate;
|
||||||
|
if (level >= o_thres)
|
||||||
|
mode = 1;
|
||||||
|
else if (gate <= 0.0f) {
|
||||||
|
gate = 0.0f;
|
||||||
|
mode = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out[n] = in[n] * gate;
|
||||||
|
}
|
||||||
|
impl->gate = gate;
|
||||||
|
impl->hold = hold;
|
||||||
|
impl->mode = mode;
|
||||||
|
impl->last = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct spa_fga_descriptor noisegate_desc = {
|
||||||
|
.name = "noisegate",
|
||||||
|
.flags = SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA,
|
||||||
|
|
||||||
|
.n_ports = SPA_N_ELEMENTS(noisegate_ports),
|
||||||
|
.ports = noisegate_ports,
|
||||||
|
|
||||||
|
.instantiate = builtin_instantiate,
|
||||||
|
.connect_port = builtin_connect_port,
|
||||||
|
.run = noisegate_run,
|
||||||
|
.cleanup = builtin_cleanup,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
|
static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
|
||||||
{
|
{
|
||||||
switch(Index) {
|
switch(Index) {
|
||||||
|
|
@ -2939,6 +3072,8 @@ static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
|
||||||
return &pipe_desc;
|
return &pipe_desc;
|
||||||
case 29:
|
case 29:
|
||||||
return &zeroramp_desc;
|
return &zeroramp_desc;
|
||||||
|
case 30:
|
||||||
|
return &noisegate_desc;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -623,6 +623,19 @@ extern struct spa_handle_factory spa_filter_graph_factory;
|
||||||
* "Duration (s)" determines how long the fade-in and fade-out should last
|
* "Duration (s)" determines how long the fade-in and fade-out should last
|
||||||
* (default 0.000666).
|
* (default 0.000666).
|
||||||
*
|
*
|
||||||
|
* ### Noisegate
|
||||||
|
*
|
||||||
|
* The `noisegate` plugin can be used to remove low volume noise.
|
||||||
|
*
|
||||||
|
* It has an "In" input port and an "Out" output data ports. Normally the input
|
||||||
|
* data is passed directly to the output.
|
||||||
|
*
|
||||||
|
* If the volume drops below "Close threshold", the noisegate will ramp down the
|
||||||
|
* volume to zero for a duration of "Release (s)" seconds. When the volume is above
|
||||||
|
* "Open threshold", the noisegate will ramp up the volume to 1 for a duration
|
||||||
|
* of "Attack (s)" seconds. The noise gate stays open for at least "Hold (s)"
|
||||||
|
* seconds before it can close again.
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* ## SOFA filters
|
* ## SOFA filters
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue