mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-06 13:29:56 -05:00
clamp sample data to -1 .. 1, before passing it to the plugin; if a control port data specification is left empty, initialize with the default value of the plugin
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/lennart@1877 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
29d25ec8d9
commit
1fc168b02f
1 changed files with 123 additions and 33 deletions
|
|
@ -52,7 +52,7 @@ PA_MODULE_USAGE(
|
||||||
"channels=<number of channels> "
|
"channels=<number of channels> "
|
||||||
"rate=<sample rate> "
|
"rate=<sample rate> "
|
||||||
"channel_map=<channel map> "
|
"channel_map=<channel map> "
|
||||||
"plugin=<ladspa plugin name> "
|
"plugin=<ladspa plugin name> "
|
||||||
"label=<ladspa plugin label> "
|
"label=<ladspa plugin label> "
|
||||||
"control=<comma seperated list of input control values>")
|
"control=<comma seperated list of input control values>")
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ PA_MODULE_USAGE(
|
||||||
struct userdata {
|
struct userdata {
|
||||||
pa_core *core;
|
pa_core *core;
|
||||||
pa_module *module;
|
pa_module *module;
|
||||||
|
|
||||||
pa_sink *sink, *master;
|
pa_sink *sink, *master;
|
||||||
pa_sink_input *sink_input;
|
pa_sink_input *sink_input;
|
||||||
|
|
||||||
|
|
@ -92,7 +92,7 @@ static const char* const valid_modargs[] = {
|
||||||
/* Called from I/O thread context */
|
/* Called from I/O thread context */
|
||||||
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
|
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
|
||||||
struct userdata *u = PA_SINK(o)->userdata;
|
struct userdata *u = PA_SINK(o)->userdata;
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
|
||||||
case PA_SINK_MESSAGE_GET_LATENCY: {
|
case PA_SINK_MESSAGE_GET_LATENCY: {
|
||||||
|
|
@ -100,25 +100,25 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
|
||||||
|
|
||||||
if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
|
if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
|
||||||
usec = 0;
|
usec = 0;
|
||||||
|
|
||||||
*((pa_usec_t*) data) = usec + pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
|
*((pa_usec_t*) data) = usec + pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pa_sink_process_msg(o, code, data, offset, chunk);
|
return pa_sink_process_msg(o, code, data, offset, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from main context */
|
/* Called from main context */
|
||||||
static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
|
static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
|
||||||
struct userdata *u;
|
struct userdata *u;
|
||||||
|
|
||||||
pa_sink_assert_ref(s);
|
pa_sink_assert_ref(s);
|
||||||
pa_assert_se(u = s->userdata);
|
pa_assert_se(u = s->userdata);
|
||||||
|
|
||||||
if (PA_SINK_LINKED(state) && u->sink_input)
|
if (PA_SINK_LINKED(state) && u->sink_input)
|
||||||
pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
|
pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,14 +157,14 @@ static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chun
|
||||||
n = tchunk.length / fs;
|
n = tchunk.length / fs;
|
||||||
|
|
||||||
pa_assert(n > 0);
|
pa_assert(n > 0);
|
||||||
|
|
||||||
u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, tchunk.length);
|
u->memchunk.memblock = pa_memblock_new(i->sink->core->mempool, tchunk.length);
|
||||||
u->memchunk.index = 0;
|
u->memchunk.index = 0;
|
||||||
u->memchunk.length = tchunk.length;
|
u->memchunk.length = tchunk.length;
|
||||||
|
|
||||||
src = (float*) ((uint8_t*) pa_memblock_acquire(tchunk.memblock) + tchunk.index);
|
src = (float*) ((uint8_t*) pa_memblock_acquire(tchunk.memblock) + tchunk.index);
|
||||||
dst = (float*) pa_memblock_acquire(u->memchunk.memblock);
|
dst = (float*) pa_memblock_acquire(u->memchunk.memblock);
|
||||||
|
|
||||||
for (c = 0; c < u->channels; c++) {
|
for (c = 0; c < u->channels; c++) {
|
||||||
unsigned j;
|
unsigned j;
|
||||||
float *p, *q;
|
float *p, *q;
|
||||||
|
|
@ -172,14 +172,14 @@ static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chun
|
||||||
p = src + c;
|
p = src + c;
|
||||||
q = u->input;
|
q = u->input;
|
||||||
for (j = 0; j < n; j++, p += u->channels, q++)
|
for (j = 0; j < n; j++, p += u->channels, q++)
|
||||||
*q = *p;
|
*q = CLAMP(*p, -1.0, 1.0);
|
||||||
|
|
||||||
u->descriptor->run(u->handle[c], n);
|
u->descriptor->run(u->handle[c], n);
|
||||||
|
|
||||||
q = u->output;
|
q = u->output;
|
||||||
p = dst + c;
|
p = dst + c;
|
||||||
for (j = 0; j < n; j++, q++, p += u->channels)
|
for (j = 0; j < n; j++, q++, p += u->channels)
|
||||||
*p = *q;
|
*p = CLAMP(*q, -1.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_memblock_release(tchunk.memblock);
|
pa_memblock_release(tchunk.memblock);
|
||||||
|
|
@ -188,9 +188,12 @@ static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chun
|
||||||
pa_memblock_unref(tchunk.memblock);
|
pa_memblock_unref(tchunk.memblock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pa_assert(u->memchunk.length > 0);
|
||||||
pa_assert(u->memchunk.memblock);
|
pa_assert(u->memchunk.memblock);
|
||||||
|
|
||||||
*chunk = u->memchunk;
|
*chunk = u->memchunk;
|
||||||
pa_memblock_ref(chunk->memblock);
|
pa_memblock_ref(chunk->memblock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,13 +206,13 @@ static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
|
||||||
pa_assert(length > 0);
|
pa_assert(length > 0);
|
||||||
|
|
||||||
if (u->memchunk.memblock) {
|
if (u->memchunk.memblock) {
|
||||||
|
|
||||||
if (length < u->memchunk.length) {
|
if (length < u->memchunk.length) {
|
||||||
u->memchunk.index += length;
|
u->memchunk.index += length;
|
||||||
u->memchunk.length -= length;
|
u->memchunk.length -= length;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_memblock_unref(u->memchunk.memblock);
|
pa_memblock_unref(u->memchunk.memblock);
|
||||||
length -= u->memchunk.length;
|
length -= u->memchunk.length;
|
||||||
pa_memchunk_reset(&u->memchunk);
|
pa_memchunk_reset(&u->memchunk);
|
||||||
|
|
@ -238,7 +241,7 @@ static void sink_input_attach_cb(pa_sink_input *i) {
|
||||||
|
|
||||||
pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq);
|
pa_sink_set_asyncmsgq(u->sink, i->sink->asyncmsgq);
|
||||||
pa_sink_set_rtpoll(u->sink, i->sink->rtpoll);
|
pa_sink_set_rtpoll(u->sink, i->sink->rtpoll);
|
||||||
|
|
||||||
pa_sink_attach_within_thread(u->sink);
|
pa_sink_attach_within_thread(u->sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,7 +259,7 @@ static void sink_input_kill_cb(pa_sink_input *i) {
|
||||||
pa_sink_unlink(u->sink);
|
pa_sink_unlink(u->sink);
|
||||||
pa_sink_unref(u->sink);
|
pa_sink_unref(u->sink);
|
||||||
u->sink = NULL;
|
u->sink = NULL;
|
||||||
|
|
||||||
pa_module_unload_request(u->module);
|
pa_module_unload_request(u->module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,11 +277,12 @@ int pa__init(pa_module*m) {
|
||||||
const LADSPA_Descriptor *d;
|
const LADSPA_Descriptor *d;
|
||||||
unsigned long input_port, output_port, p, j, n_control;
|
unsigned long input_port, output_port, p, j, n_control;
|
||||||
unsigned c;
|
unsigned c;
|
||||||
|
pa_bool_t *use_default = NULL;
|
||||||
|
|
||||||
pa_assert(m);
|
pa_assert(m);
|
||||||
|
|
||||||
pa_assert(sizeof(LADSPA_Data) == sizeof(float));
|
pa_assert(sizeof(LADSPA_Data) == sizeof(float));
|
||||||
|
|
||||||
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
||||||
pa_log("Failed to parse module arguments.");
|
pa_log("Failed to parse module arguments.");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -308,7 +312,7 @@ int pa__init(pa_module*m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cdata = pa_modargs_get_value(ma, "control", NULL);
|
cdata = pa_modargs_get_value(ma, "control", NULL);
|
||||||
|
|
||||||
u = pa_xnew0(struct userdata, 1);
|
u = pa_xnew0(struct userdata, 1);
|
||||||
u->core = m->core;
|
u->core = m->core;
|
||||||
u->module = m;
|
u->module = m;
|
||||||
|
|
@ -358,7 +362,7 @@ int pa__init(pa_module*m) {
|
||||||
|
|
||||||
input_port = output_port = (unsigned long) -1;
|
input_port = output_port = (unsigned long) -1;
|
||||||
n_control = 0;
|
n_control = 0;
|
||||||
|
|
||||||
for (p = 0; p < d->PortCount; p++) {
|
for (p = 0; p < d->PortCount; p++) {
|
||||||
|
|
||||||
if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
|
if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
|
||||||
|
|
@ -370,7 +374,7 @@ int pa__init(pa_module*m) {
|
||||||
pa_log("Found audio input port on plugin we cannot handle: %s", d->PortNames[p]);
|
pa_log("Found audio input port on plugin we cannot handle: %s", d->PortNames[p]);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
|
} else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
|
||||||
|
|
||||||
if (strcmp(d->PortNames[p], "Output") == 0) {
|
if (strcmp(d->PortNames[p], "Output") == 0) {
|
||||||
|
|
@ -381,7 +385,7 @@ int pa__init(pa_module*m) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
|
} else if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
|
||||||
n_control++;
|
n_control++;
|
||||||
else
|
else
|
||||||
pa_log("Cannot handle type of port %s", d->PortNames[p]);
|
pa_log("Cannot handle type of port %s", d->PortNames[p]);
|
||||||
|
|
@ -401,9 +405,9 @@ int pa__init(pa_module*m) {
|
||||||
u->output = (LADSPA_Data*) pa_xnew(uint8_t, u->block_size);
|
u->output = (LADSPA_Data*) pa_xnew(uint8_t, u->block_size);
|
||||||
else
|
else
|
||||||
u->output = u->input;
|
u->output = u->input;
|
||||||
|
|
||||||
u->channels = ss.channels;
|
u->channels = ss.channels;
|
||||||
|
|
||||||
for (c = 0; c < ss.channels; c++) {
|
for (c = 0; c < ss.channels; c++) {
|
||||||
if (!(u->handle[c] = d->instantiate(d, ss.rate))) {
|
if (!(u->handle[c] = d->instantiate(d, ss.rate))) {
|
||||||
pa_log("Failed to instantiate plugin %s with label %s for channel %i", plugin, d->Label, c);
|
pa_log("Failed to instantiate plugin %s with label %s for channel %i", plugin, d->Label, c);
|
||||||
|
|
@ -423,13 +427,20 @@ int pa__init(pa_module*m) {
|
||||||
const char *state = NULL;
|
const char *state = NULL;
|
||||||
char *k;
|
char *k;
|
||||||
unsigned long h;
|
unsigned long h;
|
||||||
|
|
||||||
u->control = pa_xnew(LADSPA_Data, n_control);
|
u->control = pa_xnew(LADSPA_Data, n_control);
|
||||||
|
use_default = pa_xnew(pa_bool_t, n_control);
|
||||||
p = 0;
|
p = 0;
|
||||||
|
|
||||||
while ((k = pa_split(cdata, ",", &state))) {
|
while ((k = pa_split(cdata, ",", &state))) {
|
||||||
float f;
|
float f;
|
||||||
|
|
||||||
|
if (*k == 0) {
|
||||||
|
use_default[p++] = TRUE;
|
||||||
|
pa_xfree(k);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (pa_atof(k, &f) < 0) {
|
if (pa_atof(k, &f) < 0) {
|
||||||
pa_log("Failed to parse control value '%s'", k);
|
pa_log("Failed to parse control value '%s'", k);
|
||||||
pa_xfree(k);
|
pa_xfree(k);
|
||||||
|
|
@ -443,6 +454,7 @@ int pa__init(pa_module*m) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use_default[p] = FALSE;
|
||||||
u->control[p++] = f;
|
u->control[p++] = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -453,15 +465,89 @@ int pa__init(pa_module*m) {
|
||||||
|
|
||||||
h = 0;
|
h = 0;
|
||||||
for (p = 0; p < d->PortCount; p++) {
|
for (p = 0; p < d->PortCount; p++) {
|
||||||
|
LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor;
|
||||||
|
|
||||||
if (!LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) || !LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
|
if (!LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) || !LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pa_assert(h < n_control);
|
pa_assert(h < n_control);
|
||||||
|
|
||||||
|
if (use_default[c]) {
|
||||||
|
LADSPA_Data lower, upper;
|
||||||
|
|
||||||
|
if (!LADSPA_IS_HINT_HAS_DEFAULT(hint)) {
|
||||||
|
pa_log("Control port value left empty but plugin defines no default.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
lower = d->PortRangeHints[p].LowerBound;
|
||||||
|
upper = d->PortRangeHints[p].UpperBound;
|
||||||
|
|
||||||
|
if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) {
|
||||||
|
lower *= ss.rate;
|
||||||
|
upper *= ss.rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (hint & LADSPA_HINT_DEFAULT_MASK) {
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_MINIMUM:
|
||||||
|
u->control[h] = lower;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_MAXIMUM:
|
||||||
|
u->control[h] = upper;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_LOW:
|
||||||
|
if (LADSPA_IS_HINT_LOGARITHMIC(hint))
|
||||||
|
u->control[h] = exp(log(lower) * 0.75 + log(upper) * 0.25);
|
||||||
|
else
|
||||||
|
u->control[h] = lower * 0.75 + upper * 0.25;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_MIDDLE:
|
||||||
|
if (LADSPA_IS_HINT_LOGARITHMIC(hint))
|
||||||
|
u->control[h] = exp(log(lower) * 0.5 + log(upper) * 0.5);
|
||||||
|
else
|
||||||
|
u->control[h] = lower * 0.5 + upper * 0.5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_HIGH:
|
||||||
|
if (LADSPA_IS_HINT_LOGARITHMIC(hint))
|
||||||
|
u->control[h] = exp(log(lower) * 0.25 + log(upper) * 0.75);
|
||||||
|
else
|
||||||
|
u->control[h] = lower * 0.25 + upper * 0.75;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_0:
|
||||||
|
u->control[h] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_1:
|
||||||
|
u->control[h] = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_100:
|
||||||
|
u->control[h] = 100;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LADSPA_HINT_DEFAULT_440:
|
||||||
|
u->control[h] = 440;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
pa_assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LADSPA_IS_HINT_INTEGER(hint))
|
||||||
|
u->control[h] = roundf(u->control[h]);
|
||||||
|
|
||||||
|
pa_log_debug("Binding %f to port %s", u->control[h], d->PortNames[p]);
|
||||||
|
|
||||||
for (c = 0; c < ss.channels; c++)
|
for (c = 0; c < ss.channels; c++)
|
||||||
d->connect_port(u->handle[c], p, &u->control[h]);
|
d->connect_port(u->handle[c], p, &u->control[h]);
|
||||||
|
|
||||||
h++;
|
h++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -482,7 +568,7 @@ int pa__init(pa_module*m) {
|
||||||
u->sink->set_state = sink_set_state;
|
u->sink->set_state = sink_set_state;
|
||||||
u->sink->userdata = u;
|
u->sink->userdata = u;
|
||||||
u->sink->flags = PA_SINK_LATENCY|PA_SINK_CAN_SUSPEND;
|
u->sink->flags = PA_SINK_LATENCY|PA_SINK_CAN_SUSPEND;
|
||||||
|
|
||||||
pa_sink_set_module(u->sink, m);
|
pa_sink_set_module(u->sink, m);
|
||||||
pa_sink_set_description(u->sink, t = pa_sprintf_malloc("LADSPA on '%s'", master->description));
|
pa_sink_set_description(u->sink, t = pa_sprintf_malloc("LADSPA on '%s'", master->description));
|
||||||
pa_xfree(t);
|
pa_xfree(t);
|
||||||
|
|
@ -514,12 +600,16 @@ int pa__init(pa_module*m) {
|
||||||
|
|
||||||
pa_modargs_free(ma);
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
pa_xfree(use_default);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (ma)
|
if (ma)
|
||||||
pa_modargs_free(ma);
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
pa_xfree(use_default);
|
||||||
|
|
||||||
pa__done(m);
|
pa__done(m);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -528,7 +618,7 @@ fail:
|
||||||
void pa__done(pa_module*m) {
|
void pa__done(pa_module*m) {
|
||||||
struct userdata *u;
|
struct userdata *u;
|
||||||
unsigned c;
|
unsigned c;
|
||||||
|
|
||||||
pa_assert(m);
|
pa_assert(m);
|
||||||
|
|
||||||
if (!(u = m->userdata))
|
if (!(u = m->userdata))
|
||||||
|
|
@ -558,8 +648,8 @@ void pa__done(pa_module*m) {
|
||||||
pa_xfree(u->output);
|
pa_xfree(u->output);
|
||||||
|
|
||||||
pa_xfree(u->input);
|
pa_xfree(u->input);
|
||||||
|
|
||||||
pa_xfree(u->control);
|
pa_xfree(u->control);
|
||||||
|
|
||||||
pa_xfree(u);
|
pa_xfree(u);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue