diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index ebfcd20a6..7a60b2897 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -369,6 +369,24 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME); * The control value "Base", "M1" and "M2" are used to calculate * 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 * * There is an optional builtin SOFA filter available. diff --git a/src/modules/module-filter-chain/builtin_plugin.c b/src/modules/module-filter-chain/builtin_plugin.c index ab440e5cb..c7f5d22fe 100644 --- a/src/modules/module-filter-chain/builtin_plugin.c +++ b/src/modules/module-filter-chain/builtin_plugin.c @@ -41,6 +41,7 @@ struct builtin { float gain; float b0, b1, b2; float a0, a1, a2; + float accum; }; static void *builtin_instantiate(const struct fc_descriptor * Descriptor, @@ -1528,6 +1529,149 @@ static const struct fc_descriptor log_desc = { .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) { switch(Index) { @@ -1569,6 +1713,10 @@ static const struct fc_descriptor * builtin_descriptor(unsigned long Index) return &exp_desc; case 18: return &log_desc; + case 19: + return &mult_desc; + case 20: + return &sine_desc; } return NULL; } diff --git a/src/modules/module-filter-chain/dsp-ops-c.c b/src/modules/module-filter-chain/dsp-ops-c.c index 03b4bceb8..82d20b50c 100644 --- a/src/modules/module-filter-chain/dsp-ops-c.c +++ b/src/modules/module-filter-chain/dsp-ops-c.c @@ -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, float *out, const float *in, uint32_t n_samples) { diff --git a/src/modules/module-filter-chain/dsp-ops.c b/src/modules/module-filter-chain/dsp-ops.c index a66c8c663..56eafe868 100644 --- a/src/modules/module-filter-chain/dsp-ops.c +++ b/src/modules/module-filter-chain/dsp-ops.c @@ -28,6 +28,7 @@ static struct dsp_info dsp_table[] = .funcs.biquad_run = dsp_biquad_run_c, .funcs.sum = dsp_sum_avx, .funcs.linear = dsp_linear_c, + .funcs.mult = dsp_mult_c, .funcs.fft_new = dsp_fft_new_c, .funcs.fft_free = dsp_fft_free_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.sum = dsp_sum_sse, .funcs.linear = dsp_linear_c, + .funcs.mult = dsp_mult_c, .funcs.fft_new = dsp_fft_new_c, .funcs.fft_free = dsp_fft_free_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.sum = dsp_sum_c, .funcs.linear = dsp_linear_c, + .funcs.mult = dsp_mult_c, .funcs.fft_new = dsp_fft_new_c, .funcs.fft_free = dsp_fft_free_c, .funcs.fft_run = dsp_fft_run_c, diff --git a/src/modules/module-filter-chain/dsp-ops.h b/src/modules/module-filter-chain/dsp-ops.h index 8ccf07d18..676548025 100644 --- a/src/modules/module-filter-chain/dsp-ops.h +++ b/src/modules/module-filter-chain/dsp-ops.h @@ -40,6 +40,9 @@ struct dsp_ops_funcs { void (*linear) (struct dsp_ops *ops, float * dst, const float * SPA_RESTRICT src, 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 { @@ -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_sum(ops,...) (ops)->funcs.sum(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_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) \ 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) +#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) \ 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_SUM_FUNC(c); MAKE_LINEAR_FUNC(c); +MAKE_MULT_FUNC(c); MAKE_FFT_NEW_FUNC(c); MAKE_FFT_FREE_FUNC(c);