mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
filter-chain: add more mixer ports
Add option to set NULL data as the port data so that plugins can skip processing. Add 8 mixer ports and skip NULL data. Move silence and discard samples to static area. Improve the virtual sink examples. use the correct mixing for the HRIR channels.
This commit is contained in:
parent
123fe3d1c5
commit
1e4e83d305
5 changed files with 177 additions and 48 deletions
|
|
@ -35,7 +35,7 @@ context.modules = [
|
|||
{
|
||||
type = builtin
|
||||
label = convolver
|
||||
name = convFL
|
||||
name = convFL_L
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 0
|
||||
|
|
@ -44,10 +44,28 @@ context.modules = [
|
|||
{
|
||||
type = builtin
|
||||
label = convolver
|
||||
name = convFR
|
||||
name = convFL_R
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 4
|
||||
channel = 1
|
||||
}
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = convolver
|
||||
name = convFR_L
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 1
|
||||
}
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = convolver
|
||||
name = convFR_R
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 0
|
||||
}
|
||||
}
|
||||
{
|
||||
|
|
@ -71,16 +89,16 @@ context.modules = [
|
|||
{
|
||||
type = builtin
|
||||
label = convolver
|
||||
name = convSL
|
||||
name = convSL_L
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 1
|
||||
channel = 4
|
||||
}
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = convolver
|
||||
name = convSR
|
||||
name = convSL_R
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 5
|
||||
|
|
@ -88,48 +106,80 @@ context.modules = [
|
|||
}
|
||||
{
|
||||
type = builtin
|
||||
label = mixer
|
||||
name = mix1L
|
||||
label = convolver
|
||||
name = convSR_L
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 5
|
||||
}
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = convolver
|
||||
name = convSR_R
|
||||
config = {
|
||||
filename = "hrir_kemar/hrir-kemar.wav"
|
||||
channel = 4
|
||||
}
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = mixer
|
||||
name = mix1R
|
||||
name = mixL
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = mixer
|
||||
name = mixC
|
||||
name = mixR
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = mixer
|
||||
name = mix2L
|
||||
label = copy
|
||||
name = copyFL
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = mixer
|
||||
name = mix2R
|
||||
label = copy
|
||||
name = copyFR
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = copy
|
||||
name = copySL
|
||||
}
|
||||
{
|
||||
type = builtin
|
||||
label = copy
|
||||
name = copySR
|
||||
}
|
||||
]
|
||||
links = [
|
||||
{ output = "convFL:Out" input = "mix1L:In 1" }
|
||||
{ output = "convSL:Out" input = "mix1L:In 2" }
|
||||
{ output = "copyFL:Out" input = "convFL_L:In" }
|
||||
{ output = "copyFL:Out" input = "convFL_R:In" }
|
||||
{ output = "copyFR:Out" input = "convFR_R:In" }
|
||||
{ output = "copyFR:Out" input = "convFR_L:In" }
|
||||
|
||||
{ output = "convFR:Out" input = "mix1R:In 1" }
|
||||
{ output = "convSR:Out" input = "mix1R:In 2" }
|
||||
{ output = "copySL:Out" input = "convSL_L:In" }
|
||||
{ output = "copySL:Out" input = "convSL_R:In" }
|
||||
{ output = "copySR:Out" input = "convSR_R:In" }
|
||||
{ output = "copySR:Out" input = "convSR_L:In" }
|
||||
|
||||
{ output = "convFC:Out" input = "mixC:In 1" }
|
||||
{ output = "convLFE:Out" input = "mixC:In 2" }
|
||||
{ output = "convFL_L:Out" input = "mixL:In 1" }
|
||||
{ output = "convFR_L:Out" input = "mixL:In 2" }
|
||||
{ output = "convFC:Out" input = "mixL:In 3" }
|
||||
{ output = "convLFE:Out" input = "mixL:In 4" }
|
||||
{ output = "convSL_L:Out" input = "mixL:In 5" }
|
||||
{ output = "convSR_L:Out" input = "mixL:In 6" }
|
||||
|
||||
{ output = "mixC:Out" input = "mix2L:In 1" }
|
||||
{ output = "mix1L:Out" input = "mix2L:In 2" }
|
||||
|
||||
{ output = "mixC:Out" input = "mix2R:In 1" }
|
||||
{ output = "mix1R:Out" input = "mix2R:In 2" }
|
||||
{ output = "convFL_R:Out" input = "mixR:In 1" }
|
||||
{ output = "convFR_R:Out" input = "mixR:In 2" }
|
||||
{ output = "convFC:Out" input = "mixR:In 3" }
|
||||
{ output = "convLFE:Out" input = "mixR:In 4" }
|
||||
{ output = "convSL_R:Out" input = "mixR:In 5" }
|
||||
{ output = "convSR_R:Out" input = "mixR:In 6" }
|
||||
]
|
||||
inputs = [ "convFL:In" "convFR:In" "convFC:In" "convLFE:In" "convSL:In" "convSR:In" ]
|
||||
outputs = [ "mix2L:Out" "mix2R:Out" ]
|
||||
inputs = [ "copyFL:In" "copyFR:In" "convFC:In" "convLFE:In" "copySL:In" "copySR:In" ]
|
||||
outputs = [ "mixL:Out" "mixR:Out" ]
|
||||
|
||||
}
|
||||
capture.props = {
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ static const struct spa_dict_item module_props[] = {
|
|||
#define MAX_CONTROLS 256
|
||||
#define MAX_SAMPLES 8192
|
||||
|
||||
static float silence_data[MAX_SAMPLES];
|
||||
static float discard_data[MAX_SAMPLES];
|
||||
|
||||
struct plugin {
|
||||
struct spa_list link;
|
||||
int ref;
|
||||
|
|
@ -212,9 +215,6 @@ struct graph {
|
|||
|
||||
uint32_t n_control;
|
||||
struct port *control_port[MAX_CONTROLS];
|
||||
|
||||
float silence_data[MAX_SAMPLES];
|
||||
float discard_data[MAX_SAMPLES];
|
||||
};
|
||||
|
||||
struct impl {
|
||||
|
|
@ -1265,8 +1265,13 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_
|
|||
* the control and notify ports already */
|
||||
graph->n_control = 0;
|
||||
spa_list_for_each(node, &graph->node_list, link) {
|
||||
float *sd = silence_data, *dd = discard_data;
|
||||
|
||||
desc = node->desc;
|
||||
d = desc->desc;
|
||||
if (d->flags & FC_DESCRIPTOR_SUPPORTS_NULL_DATA)
|
||||
sd = dd = NULL;
|
||||
|
||||
for (i = 0; i < n_hndl; i++) {
|
||||
if ((node->hndl[i] = d->instantiate(d, impl->rate, i, node->config)) == NULL) {
|
||||
pw_log_error("cannot create plugin instance");
|
||||
|
|
@ -1277,11 +1282,11 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_
|
|||
|
||||
for (j = 0; j < desc->n_input; j++) {
|
||||
p = desc->input[j];
|
||||
d->connect_port(node->hndl[i], p, graph->silence_data);
|
||||
d->connect_port(node->hndl[i], p, sd);
|
||||
}
|
||||
for (j = 0; j < desc->n_output; j++) {
|
||||
p = desc->output[j];
|
||||
d->connect_port(node->hndl[i], p, graph->discard_data);
|
||||
d->connect_port(node->hndl[i], p, dd);
|
||||
}
|
||||
for (j = 0; j < desc->n_control; j++) {
|
||||
port = &node->control_port[j];
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ static void *builtin_instantiate(const struct fc_descriptor * Descriptor,
|
|||
return impl;
|
||||
}
|
||||
|
||||
static void builtin_connect_port(void *Instance, unsigned long Port,
|
||||
float * DataLocation)
|
||||
static void builtin_connect_port(void *Instance, unsigned long Port, float * DataLocation)
|
||||
{
|
||||
struct builtin *impl = Instance;
|
||||
impl->port[Port] = DataLocation;
|
||||
|
|
@ -110,19 +109,37 @@ static void mixer_run(void * Instance, unsigned long SampleCount)
|
|||
{
|
||||
struct builtin *impl = Instance;
|
||||
unsigned long i;
|
||||
float gain1 = impl->port[3][0];
|
||||
float gain2 = impl->port[4][0];
|
||||
float *in1 = impl->port[1], *in2 = impl->port[2], *out = impl->port[0];
|
||||
float *out = impl->port[0];
|
||||
bool first = true;
|
||||
|
||||
if (gain1 == 0.0f && gain2 == 0.0f) {
|
||||
memset(out, 0, SampleCount * sizeof(float));
|
||||
} else if (gain1 == 1.0f && gain2 == 1.0f) {
|
||||
for (i = 0; i < SampleCount; i++)
|
||||
out[i] = in1[i] + in2[i];
|
||||
} else {
|
||||
for (i = 0; i < SampleCount; i++)
|
||||
out[i] = in1[i] * gain1 + in2[i] * gain2;
|
||||
if (out == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
float *in = impl->port[1+i];
|
||||
float gain = impl->port[9+i][0];
|
||||
|
||||
if (in == NULL || gain == 0.0f)
|
||||
continue;
|
||||
|
||||
if (first) {
|
||||
if (gain == 1.0f)
|
||||
memcpy(out, in, SampleCount * sizeof(float));
|
||||
else
|
||||
for (i = 0; i < SampleCount; i++)
|
||||
out[i] = in[i] * gain;
|
||||
first = false;
|
||||
} else {
|
||||
if (gain == 1.0f)
|
||||
for (i = 0; i < SampleCount; i++)
|
||||
out[i] += in[i];
|
||||
else
|
||||
for (i = 0; i < SampleCount; i++)
|
||||
out[i] += in[i] * gain;
|
||||
}
|
||||
}
|
||||
if (first)
|
||||
memset(out, 0, SampleCount * sizeof(float));
|
||||
}
|
||||
|
||||
static struct fc_port mixer_ports[] = {
|
||||
|
|
@ -130,6 +147,7 @@ static struct fc_port mixer_ports[] = {
|
|||
.name = "Out",
|
||||
.flags = FC_PORT_OUTPUT | FC_PORT_AUDIO,
|
||||
},
|
||||
|
||||
{ .index = 1,
|
||||
.name = "In 1",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_AUDIO,
|
||||
|
|
@ -139,21 +157,77 @@ static struct fc_port mixer_ports[] = {
|
|||
.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,
|
||||
},
|
||||
|
||||
{ .index = 9,
|
||||
.name = "Gain 1",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
{ .index = 4,
|
||||
{ .index = 10,
|
||||
.name = "Gain 2",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
{ .index = 11,
|
||||
.name = "Gain 3",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
{ .index = 12,
|
||||
.name = "Gain 4",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
{ .index = 13,
|
||||
.name = "Gain 5",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
{ .index = 14,
|
||||
.name = "Gain 6",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
{ .index = 15,
|
||||
.name = "Gain 7",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
{ .index = 16,
|
||||
.name = "Gain 8",
|
||||
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
|
||||
.def = 1.0f, .min = 0.0f, .max = 10.0f
|
||||
},
|
||||
};
|
||||
|
||||
static const struct fc_descriptor mixer_desc = {
|
||||
.name = "mixer",
|
||||
.flags = FC_DESCRIPTOR_SUPPORTS_NULL_DATA,
|
||||
|
||||
.n_ports = 5,
|
||||
.n_ports = 17,
|
||||
.ports = mixer_ports,
|
||||
|
||||
.instantiate = builtin_instantiate,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#include "plugin.h"
|
||||
#include "ladspa.h"
|
||||
|
||||
|
||||
struct plugin {
|
||||
struct fc_plugin plugin;
|
||||
void *handle;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ struct fc_port {
|
|||
|
||||
struct fc_descriptor {
|
||||
const char *name;
|
||||
#define FC_DESCRIPTOR_SUPPORTS_NULL_DATA (1ULL << 0)
|
||||
uint64_t flags;
|
||||
|
||||
void (*free) (struct fc_descriptor *desc);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue