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:
Wim Taymans 2023-10-23 11:14:51 +02:00
parent 920beea3eb
commit 970a837670
5 changed files with 202 additions and 0 deletions

View file

@ -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.

View file

@ -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;
} }

View file

@ -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)
{ {

View file

@ -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,

View file

@ -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);