mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
parent
2dfc41766f
commit
49486bceeb
2 changed files with 162 additions and 1 deletions
|
|
@ -191,7 +191,6 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
||||||
* - `bq_notch` a notch filter.
|
* - `bq_notch` a notch filter.
|
||||||
* - `bq_allpass` an allpass filter.
|
* - `bq_allpass` an allpass filter.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* ### Convolver
|
* ### Convolver
|
||||||
*
|
*
|
||||||
* The convolver can be used to apply an impulse response to a signal. It is usually used
|
* The convolver can be used to apply an impulse response to a signal. It is usually used
|
||||||
|
|
@ -243,6 +242,37 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
||||||
* - `length` The number of samples to use as the IR.
|
* - `length` The number of samples to use as the IR.
|
||||||
* - `channel` The channel to use from the file as the IR.
|
* - `channel` The channel to use from the file as the IR.
|
||||||
*
|
*
|
||||||
|
* ### Delay
|
||||||
|
*
|
||||||
|
* The delay can be used to delay a signal in time.
|
||||||
|
*
|
||||||
|
* The delay has an input port "In" and an output port "Out". It also has
|
||||||
|
* a "Delay (s)" control port. It requires a config section in the node declaration
|
||||||
|
* in this format:
|
||||||
|
*
|
||||||
|
*\code{.unparsed}
|
||||||
|
* filter.graph = {
|
||||||
|
* nodes = [
|
||||||
|
* {
|
||||||
|
* type = builtin
|
||||||
|
* name = ...
|
||||||
|
* label = delay
|
||||||
|
* config = {
|
||||||
|
* "max-delay" = ...
|
||||||
|
* }
|
||||||
|
* control = {
|
||||||
|
* "Delay (s)" = ...
|
||||||
|
* }
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
*\endcode
|
||||||
|
*
|
||||||
|
* - `max-delay` the maximum delay in seconds. The "Delay (s)" parameter will
|
||||||
|
* be clamped to this value.
|
||||||
|
*
|
||||||
* ## General options
|
* ## General options
|
||||||
*
|
*
|
||||||
* Options with well-known behavior. Most options can be added to the global
|
* Options with well-known behavior. Most options can be added to the global
|
||||||
|
|
|
||||||
|
|
@ -730,6 +730,135 @@ static const struct fc_descriptor convolve_desc = {
|
||||||
.cleanup = convolver_cleanup,
|
.cleanup = convolver_cleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** delay */
|
||||||
|
struct delay_impl {
|
||||||
|
unsigned long rate;
|
||||||
|
float *port[4];
|
||||||
|
|
||||||
|
float delay;
|
||||||
|
uint32_t delay_samples;
|
||||||
|
uint32_t buffer_samples;
|
||||||
|
float *buffer;
|
||||||
|
uint32_t ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void delay_cleanup(void * Instance)
|
||||||
|
{
|
||||||
|
struct delay_impl *impl = Instance;
|
||||||
|
free(impl->buffer);
|
||||||
|
free(impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *delay_instantiate(const struct fc_descriptor * Descriptor,
|
||||||
|
unsigned long *SampleRate, int index, const char *config)
|
||||||
|
{
|
||||||
|
struct delay_impl *impl;
|
||||||
|
struct spa_json it[2];
|
||||||
|
const char *val;
|
||||||
|
char key[256];
|
||||||
|
float max_delay = 1.0f;
|
||||||
|
|
||||||
|
if (config == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
spa_json_init(&it[0], config, strlen(config));
|
||||||
|
if (spa_json_enter_object(&it[0], &it[1]) <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
|
||||||
|
if (spa_streq(key, "max-delay")) {
|
||||||
|
if (spa_json_get_float(&it[1], &max_delay) <= 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (spa_json_next(&it[1], &val) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (max_delay <= 0.0f)
|
||||||
|
max_delay = 1.0f;
|
||||||
|
|
||||||
|
impl = calloc(1, sizeof(*impl));
|
||||||
|
if (impl == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
impl->rate = *SampleRate;
|
||||||
|
impl->buffer_samples = max_delay * impl->rate;
|
||||||
|
pw_log_info("%lu %d", impl->rate, impl->buffer_samples);
|
||||||
|
|
||||||
|
impl->buffer = calloc(impl->buffer_samples, sizeof(float));
|
||||||
|
if (impl->buffer == NULL) {
|
||||||
|
delay_cleanup(impl);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delay_connect_port(void * Instance, unsigned long Port,
|
||||||
|
float * DataLocation)
|
||||||
|
{
|
||||||
|
struct delay_impl *impl = Instance;
|
||||||
|
if (Port > 2)
|
||||||
|
return;
|
||||||
|
impl->port[Port] = DataLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delay_run(void * Instance, unsigned long SampleCount)
|
||||||
|
{
|
||||||
|
struct delay_impl *impl = Instance;
|
||||||
|
float *in = impl->port[1], *out = impl->port[0];
|
||||||
|
float delay = impl->port[2][0];
|
||||||
|
unsigned long n;
|
||||||
|
uint32_t r, w;
|
||||||
|
|
||||||
|
if (delay != impl->delay) {
|
||||||
|
impl->delay_samples = SPA_CLAMP(delay * impl->rate, 0, impl->buffer_samples-1);
|
||||||
|
impl->delay = delay;
|
||||||
|
}
|
||||||
|
r = impl->ptr;
|
||||||
|
w = impl->ptr + impl->delay_samples;
|
||||||
|
if (w >= impl->buffer_samples)
|
||||||
|
w -= impl->buffer_samples;
|
||||||
|
|
||||||
|
for (n = 0; n < SampleCount; n++) {
|
||||||
|
impl->buffer[w] = in[n];
|
||||||
|
out[n] = impl->buffer[r];
|
||||||
|
if (++r >= impl->buffer_samples)
|
||||||
|
r = 0;
|
||||||
|
if (++w >= impl->buffer_samples)
|
||||||
|
w = 0;
|
||||||
|
}
|
||||||
|
impl->ptr = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fc_port delay_ports[] = {
|
||||||
|
{ .index = 0,
|
||||||
|
.name = "Out",
|
||||||
|
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 1,
|
||||||
|
.name = "In",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 2,
|
||||||
|
.name = "Delay (s)",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||||
|
.def = 0.0f, .min = 0.0f, .max = 100.0f
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fc_descriptor delay_desc = {
|
||||||
|
.name = "delay",
|
||||||
|
|
||||||
|
.n_ports = 3,
|
||||||
|
.ports = delay_ports,
|
||||||
|
|
||||||
|
.instantiate = delay_instantiate,
|
||||||
|
.connect_port = delay_connect_port,
|
||||||
|
.run = delay_run,
|
||||||
|
.cleanup = delay_cleanup,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct fc_descriptor * builtin_descriptor(unsigned long Index)
|
static const struct fc_descriptor * builtin_descriptor(unsigned long Index)
|
||||||
{
|
{
|
||||||
switch(Index) {
|
switch(Index) {
|
||||||
|
|
@ -755,6 +884,8 @@ static const struct fc_descriptor * builtin_descriptor(unsigned long Index)
|
||||||
return ©_desc;
|
return ©_desc;
|
||||||
case 10:
|
case 10:
|
||||||
return &convolve_desc;
|
return &convolve_desc;
|
||||||
|
case 11:
|
||||||
|
return &delay_desc;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue