mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-06 13:30:01 -05:00
filter-chain: add mult and sine plugin
mult is to multiple samples, sine to generate a sine wave. This can be used to make a tremolo effect.
This commit is contained in:
parent
920beea3eb
commit
970a837670
5 changed files with 202 additions and 0 deletions
|
|
@ -369,6 +369,24 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
||||||
* The control value "Base", "M1" and "M2" are used to calculate
|
* The control value "Base", "M1" and "M2" are used to calculate
|
||||||
* out = M2 * log2f(fabsf(in * M1)) / log2f(Base) for each sample.
|
* out = M2 * log2f(fabsf(in * M1)) / log2f(Base) for each sample.
|
||||||
*
|
*
|
||||||
|
* ### Multiply
|
||||||
|
*
|
||||||
|
* The mult plugin can be used to multiply samples together.
|
||||||
|
*
|
||||||
|
* It has 8 input ports named "In 1" to "In 8" and an output port "Out".
|
||||||
|
*
|
||||||
|
* All input ports samples are multiplied together into the output. Unused input ports
|
||||||
|
* will be ignored and not cause overhead.
|
||||||
|
*
|
||||||
|
* ### Sine
|
||||||
|
*
|
||||||
|
* The sine plugin generates a sine wave.
|
||||||
|
*
|
||||||
|
* It has an output port "Out" and also a control output port "notify".
|
||||||
|
*
|
||||||
|
* "Freq", "Ampl", "Offset" and "Phase" can be used to control the sine wave
|
||||||
|
* frequence, amplitude, offset and phase.
|
||||||
|
*
|
||||||
* ## SOFA filter
|
* ## SOFA filter
|
||||||
*
|
*
|
||||||
* There is an optional builtin SOFA filter available.
|
* There is an optional builtin SOFA filter available.
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ struct builtin {
|
||||||
float gain;
|
float gain;
|
||||||
float b0, b1, b2;
|
float b0, b1, b2;
|
||||||
float a0, a1, a2;
|
float a0, a1, a2;
|
||||||
|
float accum;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *builtin_instantiate(const struct fc_descriptor * Descriptor,
|
static void *builtin_instantiate(const struct fc_descriptor * Descriptor,
|
||||||
|
|
@ -1528,6 +1529,149 @@ static const struct fc_descriptor log_desc = {
|
||||||
.cleanup = builtin_cleanup,
|
.cleanup = builtin_cleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* mult */
|
||||||
|
static void mult_run(void * Instance, unsigned long SampleCount)
|
||||||
|
{
|
||||||
|
struct builtin *impl = Instance;
|
||||||
|
int i, n_src = 0;
|
||||||
|
float *out = impl->port[0];
|
||||||
|
const void *src[8];
|
||||||
|
|
||||||
|
if (out == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
float *in = impl->port[1+i];
|
||||||
|
|
||||||
|
if (in == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
src[n_src++] = in;
|
||||||
|
}
|
||||||
|
dsp_ops_mult(dsp_ops, out, src, n_src, SampleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fc_port mult_ports[] = {
|
||||||
|
{ .index = 0,
|
||||||
|
.name = "Out",
|
||||||
|
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 1,
|
||||||
|
.name = "In 1",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 2,
|
||||||
|
.name = "In 2",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 3,
|
||||||
|
.name = "In 3",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 4,
|
||||||
|
.name = "In 4",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 5,
|
||||||
|
.name = "In 5",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 6,
|
||||||
|
.name = "In 6",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 7,
|
||||||
|
.name = "In 7",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 8,
|
||||||
|
.name = "In 8",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fc_descriptor mult_desc = {
|
||||||
|
.name = "mult",
|
||||||
|
.flags = FC_DESCRIPTOR_SUPPORTS_NULL_DATA,
|
||||||
|
|
||||||
|
.n_ports = SPA_N_ELEMENTS(mult_ports),
|
||||||
|
.ports = mult_ports,
|
||||||
|
|
||||||
|
.instantiate = builtin_instantiate,
|
||||||
|
.connect_port = builtin_connect_port,
|
||||||
|
.run = mult_run,
|
||||||
|
.cleanup = builtin_cleanup,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define M_PI_M2 ( M_PI + M_PI )
|
||||||
|
|
||||||
|
/* sine */
|
||||||
|
static void sine_run(void * Instance, unsigned long SampleCount)
|
||||||
|
{
|
||||||
|
struct builtin *impl = Instance;
|
||||||
|
float *out = impl->port[0];
|
||||||
|
float *notify = impl->port[1];
|
||||||
|
float freq = impl->port[2][0];
|
||||||
|
float ampl = impl->port[3][0];
|
||||||
|
float offs = impl->port[5][0];
|
||||||
|
unsigned long n;
|
||||||
|
|
||||||
|
for (n = 0; n < SampleCount; n++) {
|
||||||
|
if (out != NULL)
|
||||||
|
out[n] = sin(impl->accum) * ampl + offs;
|
||||||
|
if (notify != NULL && n == 0)
|
||||||
|
notify[0] = sin(impl->accum) * ampl + offs;
|
||||||
|
|
||||||
|
impl->accum += M_PI_M2 * freq / impl->rate;
|
||||||
|
if (impl->accum >= M_PI_M2)
|
||||||
|
impl->accum -= M_PI_M2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fc_port sine_ports[] = {
|
||||||
|
{ .index = 0,
|
||||||
|
.name = "Out",
|
||||||
|
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
|
||||||
|
},
|
||||||
|
{ .index = 1,
|
||||||
|
.name = "Notify",
|
||||||
|
.flags = FC_PORT_OUTPUT | FC_PORT_CONTROL,
|
||||||
|
},
|
||||||
|
{ .index = 2,
|
||||||
|
.name = "Freq",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||||
|
.def = 440.0f, .min = 0.0f, .max = 1000000.0f
|
||||||
|
},
|
||||||
|
{ .index = 3,
|
||||||
|
.name = "Ampl",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||||
|
.def = 1.0, .min = 0.0f, .max = 10.0f
|
||||||
|
},
|
||||||
|
{ .index = 4,
|
||||||
|
.name = "Phase",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||||
|
.def = 0.0f, .min = -M_PI, .max = M_PI
|
||||||
|
},
|
||||||
|
{ .index = 5,
|
||||||
|
.name = "Offset",
|
||||||
|
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||||
|
.def = 0.0f, .min = -10.0f, .max = 10.0f
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct fc_descriptor sine_desc = {
|
||||||
|
.name = "sine",
|
||||||
|
.flags = FC_DESCRIPTOR_SUPPORTS_NULL_DATA,
|
||||||
|
|
||||||
|
.n_ports = SPA_N_ELEMENTS(sine_ports),
|
||||||
|
.ports = sine_ports,
|
||||||
|
|
||||||
|
.instantiate = builtin_instantiate,
|
||||||
|
.connect_port = builtin_connect_port,
|
||||||
|
.run = sine_run,
|
||||||
|
.cleanup = builtin_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) {
|
||||||
|
|
@ -1569,6 +1713,10 @@ static const struct fc_descriptor * builtin_descriptor(unsigned long Index)
|
||||||
return &exp_desc;
|
return &exp_desc;
|
||||||
case 18:
|
case 18:
|
||||||
return &log_desc;
|
return &log_desc;
|
||||||
|
case 19:
|
||||||
|
return &mult_desc;
|
||||||
|
case 20:
|
||||||
|
return &sine_desc;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,31 @@ void dsp_mix_gain_c(struct dsp_ops *ops,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void dsp_mult1_c(struct dsp_ops *ops, void * SPA_RESTRICT dst,
|
||||||
|
const void * SPA_RESTRICT src, uint32_t n_samples)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
const float *s = src;
|
||||||
|
float *d = dst;
|
||||||
|
for (i = 0; i < n_samples; i++)
|
||||||
|
d[i] *= s[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_mult_c(struct dsp_ops *ops,
|
||||||
|
void * SPA_RESTRICT dst,
|
||||||
|
const void * SPA_RESTRICT src[],
|
||||||
|
uint32_t n_src, uint32_t n_samples)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
if (n_src == 0) {
|
||||||
|
dsp_clear_c(ops, dst, n_samples);
|
||||||
|
} else {
|
||||||
|
dsp_copy_c(ops, dst, src[0], n_samples);
|
||||||
|
for (i = 1; i < n_src; i++)
|
||||||
|
dsp_mult1_c(ops, dst, src[i], n_samples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dsp_biquad_run_c(struct dsp_ops *ops, struct biquad *bq,
|
void dsp_biquad_run_c(struct dsp_ops *ops, struct biquad *bq,
|
||||||
float *out, const float *in, uint32_t n_samples)
|
float *out, const float *in, uint32_t n_samples)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ static struct dsp_info dsp_table[] =
|
||||||
.funcs.biquad_run = dsp_biquad_run_c,
|
.funcs.biquad_run = dsp_biquad_run_c,
|
||||||
.funcs.sum = dsp_sum_avx,
|
.funcs.sum = dsp_sum_avx,
|
||||||
.funcs.linear = dsp_linear_c,
|
.funcs.linear = dsp_linear_c,
|
||||||
|
.funcs.mult = dsp_mult_c,
|
||||||
.funcs.fft_new = dsp_fft_new_c,
|
.funcs.fft_new = dsp_fft_new_c,
|
||||||
.funcs.fft_free = dsp_fft_free_c,
|
.funcs.fft_free = dsp_fft_free_c,
|
||||||
.funcs.fft_run = dsp_fft_run_c,
|
.funcs.fft_run = dsp_fft_run_c,
|
||||||
|
|
@ -43,6 +44,7 @@ static struct dsp_info dsp_table[] =
|
||||||
.funcs.biquad_run = dsp_biquad_run_c,
|
.funcs.biquad_run = dsp_biquad_run_c,
|
||||||
.funcs.sum = dsp_sum_sse,
|
.funcs.sum = dsp_sum_sse,
|
||||||
.funcs.linear = dsp_linear_c,
|
.funcs.linear = dsp_linear_c,
|
||||||
|
.funcs.mult = dsp_mult_c,
|
||||||
.funcs.fft_new = dsp_fft_new_c,
|
.funcs.fft_new = dsp_fft_new_c,
|
||||||
.funcs.fft_free = dsp_fft_free_c,
|
.funcs.fft_free = dsp_fft_free_c,
|
||||||
.funcs.fft_run = dsp_fft_run_c,
|
.funcs.fft_run = dsp_fft_run_c,
|
||||||
|
|
@ -57,6 +59,7 @@ static struct dsp_info dsp_table[] =
|
||||||
.funcs.biquad_run = dsp_biquad_run_c,
|
.funcs.biquad_run = dsp_biquad_run_c,
|
||||||
.funcs.sum = dsp_sum_c,
|
.funcs.sum = dsp_sum_c,
|
||||||
.funcs.linear = dsp_linear_c,
|
.funcs.linear = dsp_linear_c,
|
||||||
|
.funcs.mult = dsp_mult_c,
|
||||||
.funcs.fft_new = dsp_fft_new_c,
|
.funcs.fft_new = dsp_fft_new_c,
|
||||||
.funcs.fft_free = dsp_fft_free_c,
|
.funcs.fft_free = dsp_fft_free_c,
|
||||||
.funcs.fft_run = dsp_fft_run_c,
|
.funcs.fft_run = dsp_fft_run_c,
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ struct dsp_ops_funcs {
|
||||||
void (*linear) (struct dsp_ops *ops,
|
void (*linear) (struct dsp_ops *ops,
|
||||||
float * dst, const float * SPA_RESTRICT src,
|
float * dst, const float * SPA_RESTRICT src,
|
||||||
const float mult, const float add, uint32_t n_samples);
|
const float mult, const float add, uint32_t n_samples);
|
||||||
|
void (*mult) (struct dsp_ops *ops,
|
||||||
|
void * SPA_RESTRICT dst,
|
||||||
|
const void * SPA_RESTRICT src[], uint32_t n_src, uint32_t n_samples);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dsp_ops {
|
struct dsp_ops {
|
||||||
|
|
@ -62,6 +65,7 @@ int dsp_ops_init(struct dsp_ops *ops);
|
||||||
#define dsp_ops_biquad_run(ops,...) (ops)->funcs.biquad_run(ops, __VA_ARGS__)
|
#define dsp_ops_biquad_run(ops,...) (ops)->funcs.biquad_run(ops, __VA_ARGS__)
|
||||||
#define dsp_ops_sum(ops,...) (ops)->funcs.sum(ops, __VA_ARGS__)
|
#define dsp_ops_sum(ops,...) (ops)->funcs.sum(ops, __VA_ARGS__)
|
||||||
#define dsp_ops_linear(ops,...) (ops)->funcs.linear(ops, __VA_ARGS__)
|
#define dsp_ops_linear(ops,...) (ops)->funcs.linear(ops, __VA_ARGS__)
|
||||||
|
#define dsp_ops_mult(ops,...) (ops)->funcs.mult(ops, __VA_ARGS__)
|
||||||
|
|
||||||
#define dsp_ops_fft_new(ops,...) (ops)->funcs.fft_new(ops, __VA_ARGS__)
|
#define dsp_ops_fft_new(ops,...) (ops)->funcs.fft_new(ops, __VA_ARGS__)
|
||||||
#define dsp_ops_fft_free(ops,...) (ops)->funcs.fft_free(ops, __VA_ARGS__)
|
#define dsp_ops_fft_free(ops,...) (ops)->funcs.fft_free(ops, __VA_ARGS__)
|
||||||
|
|
@ -86,6 +90,9 @@ void dsp_sum_##arch (struct dsp_ops *ops, float * SPA_RESTRICT dst, \
|
||||||
#define MAKE_LINEAR_FUNC(arch) \
|
#define MAKE_LINEAR_FUNC(arch) \
|
||||||
void dsp_linear_##arch (struct dsp_ops *ops, float * SPA_RESTRICT dst, \
|
void dsp_linear_##arch (struct dsp_ops *ops, float * SPA_RESTRICT dst, \
|
||||||
const float * SPA_RESTRICT src, const float mult, const float add, uint32_t n_samples)
|
const float * SPA_RESTRICT src, const float mult, const float add, uint32_t n_samples)
|
||||||
|
#define MAKE_MULT_FUNC(arch) \
|
||||||
|
void dsp_mult_##arch(struct dsp_ops *ops, void * SPA_RESTRICT dst, \
|
||||||
|
const void * SPA_RESTRICT src[], uint32_t n_src, uint32_t n_samples)
|
||||||
|
|
||||||
#define MAKE_FFT_NEW_FUNC(arch) \
|
#define MAKE_FFT_NEW_FUNC(arch) \
|
||||||
void *dsp_fft_new_##arch(struct dsp_ops *ops, int32_t size, bool real)
|
void *dsp_fft_new_##arch(struct dsp_ops *ops, int32_t size, bool real)
|
||||||
|
|
@ -110,6 +117,7 @@ MAKE_MIX_GAIN_FUNC(c);
|
||||||
MAKE_BIQUAD_RUN_FUNC(c);
|
MAKE_BIQUAD_RUN_FUNC(c);
|
||||||
MAKE_SUM_FUNC(c);
|
MAKE_SUM_FUNC(c);
|
||||||
MAKE_LINEAR_FUNC(c);
|
MAKE_LINEAR_FUNC(c);
|
||||||
|
MAKE_MULT_FUNC(c);
|
||||||
|
|
||||||
MAKE_FFT_NEW_FUNC(c);
|
MAKE_FFT_NEW_FUNC(c);
|
||||||
MAKE_FFT_FREE_FUNC(c);
|
MAKE_FFT_FREE_FUNC(c);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue