View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0006639 | ardour | bugs | public | 2015-10-14 12:15 | 2020-04-19 20:17 |
Reporter | SadKo | Assigned To | x42 | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | no change required | ||
Product Version | 4.X git (version in description) | ||||
Summary | 0006639: LADSPA and LV2 hosting problems ? | ||||
Description | Hello! I'm developing LADSPA-compatible plugin now and met some problems on official Ardour 4.2 build. The first problem is with input control ports: 1. I define control port with HintDescriptor = LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE 2. I specify LowerBound = -100.0f, UpperBound = 100.0f 3. The configuration interface of plugin does not allow to set value less than 0.0f for this port. The second problem is with audio ports: I just add printf() to connect_port and get infinite stdout: [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 0, 0x29d9240 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 1, 0x29d9a80 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 2, 0x29d9240 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 3, 0x29d9a80 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 0, 0x29d9240 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 1, 0x29d9a80 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 2, 0x29d9240 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 3, 0x29d9a80 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 0, 0x29d9240 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 1, 0x29d9a80 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 2, 0x29d9240 [ladspa.cpp:39] ladspa_connect_port: 0x2c02280, 3, 0x29d9a80 Also this happens with LV2: [lv2.cpp:31] lv2_connect_port: 0x2b28910, 0, 0x289d0c0 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 1, 0x289d900 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 2, 0x289d0c0 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 3, 0x289d900 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 0, 0x28a12c0 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 1, 0x28a1b00 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 2, 0x28a12c0 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 3, 0x28a1b00 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 0, 0x28a12c0 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 1, 0x28a1b00 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 2, 0x28a12c0 [lv2.cpp:31] lv2_connect_port: 0x2b28910, 3, 0x28a1b00 Also when I specify Toggle control (both LADSPA and LV2) and declare minimium and maximum values, the result values of the toggle control are always 0.0f and 1.0f even if minimum value is -1.0f. Don't know if it is a real problem but has to be noticed. | ||||
Tags | No tags attached. | ||||
|
Is the code for that plugin available? Other LADSPA plugins work just fine with a range spanning zero. e.g swh's gate (ID 1921) has a threshold -70, +20 Infinite loop when connecting definitely suggests some other issue. http://lv2plug.in/ns/lv2core/#toggled "Indicates that the data item should be considered a Boolean toggle. Data less than or equal to zero should be considered off or false, and data above zero should be considered on or true." The range is irrelevant. (also note http://lv2plug.in/ns/lv2core/#minimum and #maximum. those are soft-limits, the plugin must be able to cope with any value). |
2015-10-15 15:08
|
test.cpp (15,554 bytes)
#include <sys/types.h> #include <stddef.h> #include <string.h> #include <stdio.h> #include <math.h> #include <ladspa.h> namespace xxx { class StaticInitializer { public: typedef void (*func_t)(); private: func_t init; func_t fini; public: StaticInitializer(func_t f_init, func_t f_fini) { init = f_init; fini = f_fini; if (init != NULL) init(); } ~StaticInitializer() { if (fini != NULL) fini(); } }; enum flags_t { F_NONE = 0, // Input F_UPPER = (1 << 0), // Upper-limit defined F_LOWER = (1 << 1), // Lower-llmit defined F_STEP = (1 << 2), // Step defined F_LOG = (1 << 3) // Logarithmic scale }; enum unit_t { U_TOGGLE, U_VALUE, U_SECONDS, U_MILLIS, U_GAIN, U_PERCENT, U_METERS, U_SAMPLES, U_HZ, U_INDEX }; enum plugin_class_t { C_DELAY, C_REVERB, C_DISTORTION, C_WAVESHAPER, C_DYNAMICS, C_AMPLIFIER, C_COMPRESSOR, C_ENVELOPE, C_EXPANDER, C_GATE, C_LIMITER, C_FILTER, C_ALLPASS, C_BANDPASS, C_COMB, C_EQ, C_MULTI_EQ, C_PARA_EQ, C_HIGHPASS, C_LOWPASS, C_GENERATOR, C_CONSTANT, C_INSTRUMENT, C_OSCILLATOR, C_MODULATOR, C_CHORUS, C_FLANGER, C_PHASER, C_SIMULATOR, C_SPATIAL, C_SPECTRAL, C_PITCH, C_UTILITY, C_ANALYSER, C_CONVERTER, C_FUNCTION, C_MIXER }; typedef struct control_t { const char *id; // Control ID const char *name; // Control name unit_t unit; // Units int flags; // Flags float min; // Minimum value float max; // Maximum value float start; // Initial value float step; // Change step const char **items; // Items for list } parameter_t; typedef struct port_t { const char *id; // Port ID const char *name; // Port name } port_t; typedef struct plugin_metadata_t { const char *name; // Plugin description const char *author; // Author const int *classes; // List of plugin classes terminated by negative value const port_t *in_buffers; // List of data input ports const port_t *out_buffers; // List of data output ports const control_t *in_controls; // List of input controls const control_t *out_controls; // List of output controls } plugin_metadata_t; class plugin { public: plugin() {}; virtual ~plugin() {}; public: virtual void init(int sample_rate) {}; virtual void destroy() {}; virtual void activate() {}; virtual void deactivate() {}; virtual void bind(size_t port, void *data) {}; virtual void update_settings() {}; virtual void run(size_t samples) {}; virtual void process(size_t samples) {}; }; class test_plugin: public plugin { public: static const plugin_metadata_t metadata; static const float DETECT_TIME_MIN = 1.0f; static const float DETECT_TIME_MAX = 100.0f; static const float DETECT_TIME_DFL = 10.0f; static const float DETECT_TIME_STEP = 1.0f; public: test_plugin() {}; virtual ~test_plugin() {}; }; static const port_t input_ports[] = { { "in_a", "Input A" }, { "in_b", "Input B" }, { NULL } }; static const port_t output_ports[] = { { "out_a", "Output A" }, { "out_b", "Output B" }, { NULL } }; static const control_t input_controls[] = { { "sel_time", "Selected time", U_MILLIS, F_UPPER | F_LOWER | F_STEP, - test_plugin::DETECT_TIME_MAX, test_plugin::DETECT_TIME_MAX, 0, 1, NULL }, { NULL, NULL } }; static const control_t output_controls[] = { { "best_time", "Best time", U_MILLIS, F_NONE, 0, 0, 0, 0, NULL }, { NULL, NULL } }; static const int classes[] = { C_UTILITY, C_ANALYSER, -1 }; const plugin_metadata_t test_plugin::metadata = { // Name "test_plugin", // Author "Vladimir Sadovnikov", // Classes classes, // Inputs input_ports, // Outputs output_ports, // Input controls input_controls, // Output controls output_controls }; LADSPA_Handle ladspa_instantiate( const struct _LADSPA_Descriptor * Descriptor, unsigned long SampleRate) { plugin *p = NULL; size_t id = 0x10000; #define PLUGIN_DEF(plugin) \ if ((!p) && (Descriptor->UniqueID == id)) \ p = new plugin(); \ id++; PLUGIN_DEF(test_plugin); #undef PLUGIN_DEF if (p) p->init(SampleRate); return reinterpret_cast<LADSPA_Handle>(p); } void ladspa_connect_port( LADSPA_Handle Instance, unsigned long Port, LADSPA_Data * DataLocation) { printf("ladspa_connect_port %p, %d, %p\n", Instance, (int)Port, DataLocation); plugin *p = reinterpret_cast<plugin *>(Instance); p->bind(Port, DataLocation); } void ladspa_activate(LADSPA_Handle Instance) { plugin *p = reinterpret_cast<plugin *>(Instance); p->activate(); } void ladspa_run(LADSPA_Handle Instance, unsigned long SampleCount) { plugin *p = reinterpret_cast<plugin *>(Instance); p->run(SampleCount); } void ladspa_deactivate(LADSPA_Handle Instance) { plugin *p = reinterpret_cast<plugin *>(Instance); p->deactivate(); } void ladspa_cleanup(LADSPA_Handle Instance) { plugin *p = reinterpret_cast<plugin *>(Instance); p->destroy(); delete p; } LADSPA_Descriptor *ladspa_descriptors = NULL; size_t ladspa_descriptors_count = 0; const char *decode_unit(size_t unit) { switch (unit) { case U_SECONDS: return "s"; case U_MILLIS: return "ms"; case U_PERCENT: return "%"; case U_METERS: return "m"; case U_SAMPLES: return "samples"; case U_HZ: return "Hz"; } return NULL; } const char *ladspa_add_units(const char *s, size_t units) { char buf[256]; const char *unit = decode_unit(units); if (unit == NULL) return strdup(s); snprintf(buf, sizeof(buf) - 1, "%s (%s)", s, unit); return strdup(buf); } void ladspa_make_descriptor(LADSPA_Descriptor *d, unsigned long id, const char *label, const plugin_metadata_t &m) { d->UniqueID = id; d->Label = label; d->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; d->Name = m.name; d->Maker = m.author; d->Copyright = "(C)"; d->PortCount = 0; // Calculate number of ports for (const port_t *p = m.in_buffers; p->name != NULL; ++p) d->PortCount ++; for (const port_t *p = m.out_buffers; p->name != NULL; ++p) d->PortCount ++; for (const control_t *p = m.in_controls; (p->id != NULL) && (p->name != NULL); ++p) d->PortCount ++; for (const control_t *p = m.out_controls; (p->id != NULL) && (p->name != NULL); ++p) d->PortCount ++; LADSPA_PortDescriptor *p_descr = new LADSPA_PortDescriptor[d->PortCount]; const char **p_name = new const char *[d->PortCount]; LADSPA_PortRangeHint *p_hint = new LADSPA_PortRangeHint[d->PortCount]; d->PortDescriptors = p_descr; d->PortNames = p_name; d->PortRangeHints = p_hint; d->ImplementationData = NULL; for (const port_t *p = m.in_buffers; p->name != NULL; ++p) { *p_descr = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; *p_name = p->name; p_hint->HintDescriptor = 0; p_hint->LowerBound = 0.0f; p_hint->UpperBound = 0.0f; p_descr++; p_name++; p_hint++; } for (const port_t *p = m.out_buffers; p->name != NULL; ++p) { *p_descr = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; *p_name = p->name; p_hint->HintDescriptor = 0; p_hint->LowerBound = 0.0f; p_hint->UpperBound = 0.0f; p_descr++; p_name++; p_hint++; } for (size_t i=0; i<2; ++i) { const control_t *p = (i == 0) ? m.in_controls : m.out_controls; while ((p->id != NULL) && (p->name != NULL)) { *p_descr = (i == 0) ? LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL : LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; *p_name = ladspa_add_units(p->name, p->unit); p_hint->HintDescriptor = 0; if (p->unit == U_TOGGLE) { p_hint->HintDescriptor |= LADSPA_HINT_TOGGLED | LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_BELOW; p_hint->HintDescriptor |= (p->start > 0) ? LADSPA_HINT_DEFAULT_1 : LADSPA_HINT_DEFAULT_0; p_hint->LowerBound = -1.0f; p_hint->UpperBound = 1.0f; } else { printf("port name=%s\n", p->name); if (p->flags & F_LOWER) { p_hint->HintDescriptor |= LADSPA_HINT_BOUNDED_BELOW; if (p->min == p->start) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM; p_hint->LowerBound = p->min; printf("lower=%.3f\n", p_hint->LowerBound); } if (p->flags & F_UPPER) { p_hint->HintDescriptor |= LADSPA_HINT_BOUNDED_ABOVE; if (p->max == p->start) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM; p_hint->UpperBound = p->max; printf("upper=%.3f\n", p_hint->UpperBound); } if (p->flags & F_LOG) p_hint->HintDescriptor |= LADSPA_HINT_LOGARITHMIC; if (p->unit == U_INDEX) p_hint->HintDescriptor |= LADSPA_HINT_INTEGER; if ((p_hint->HintDescriptor & LADSPA_HINT_DEFAULT_MASK) == LADSPA_HINT_DEFAULT_NONE) { if (p->start == 1.0f) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_1; else if (p->start == 0.0f) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_0; else if (p->start == 100.0f) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_100; else if (p->start == 440.0f) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_440; else if ((p->flags & (F_LOWER | F_UPPER)) == (F_LOWER | F_UPPER)) { float factor = (p->flags & F_LOG) ? (logf(p->start) - logf(p->min)) / (logf(p->max) - logf(p->min)) : (p->start - p->min) / (p->max - p->min); if (factor <= 0.33) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_LOW; else if (factor >= 0.66) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH; else p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE; } else if (p->flags & F_LOWER) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM; else if (p->flags & F_UPPER) p_hint->HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM; } } p_descr++; p_name++; p_hint++; p++; } } d->instantiate = ladspa_instantiate; d->connect_port = ladspa_connect_port; d->activate = ladspa_activate; d->run = ladspa_run; d->run_adding = NULL; d->set_run_adding_gain = NULL; d->deactivate = ladspa_deactivate; d->cleanup = ladspa_cleanup; } void ladspa_gen_descriptors() { printf("ladspa_gen_descriptors\n"); if (ladspa_descriptors != NULL) return; // Calculate number of plugins ladspa_descriptors_count = 0; #define PLUGIN_DEF(plugin) ladspa_descriptors_count++; PLUGIN_DEF(test_plugin); #undef PLUGIN_DEF // Now allocate descriptors ladspa_descriptors = new LADSPA_Descriptor[ladspa_descriptors_count]; LADSPA_Descriptor *d = ladspa_descriptors; size_t id = 0; #define PLUGIN_DEF(plugin) ladspa_make_descriptor(&d[id], 0x10000 + id, "http://plugin.org/plugins/ladspa/test_plugin", plugin::metadata); id++; PLUGIN_DEF(test_plugin); #undef PLUGIN_DEF }; void ladspa_drop_descriptors() { printf("ladspa_drop_descriptors\n"); if (ladspa_descriptors == NULL) return; LADSPA_Descriptor *d = ladspa_descriptors; while (ladspa_descriptors_count--) { delete [] d->PortNames; delete [] d->PortDescriptors; delete [] d->PortRangeHints; } delete [] ladspa_descriptors; ladspa_descriptors = NULL; }; StaticInitializer ladspa_init(ladspa_gen_descriptors, ladspa_drop_descriptors); } const LADSPA_Descriptor * ladspa_descriptor(unsigned long index) { using namespace xxx; return (index < ladspa_descriptors_count) ? &ladspa_descriptors[index] : NULL; } |
|
Hello! I can't reproduce it with reduced code (see test.cpp). Probably it's a compiler issue: { "sel_time", "Selected time", U_MILLIS, F_UPPER | F_LOWER | F_STEP, - test_plugin::DETECT_TIME_MAX, test_plugin::DETECT_TIME_MAX, 0, 1, NULL }, The problem is that "- test_plugin::DETECT_TIME_MAX" was interpreted in original implementation as 0 (compiler bug?). But the connect_port() still runs infinitely after plugin is placed into mixer strip. You can compile test plugin and watch ardour's stdout. |
|
Okay, now I understood what was going on. Constant '- test_plugin::DETECT_TIME_MAX' was as routine and placed into initialization list. And descriptors were built with initialization-list primitive, too. So it could be simply uninitialized when the descriptors were instantiated. |
|
The "infinite" stdout is not infinite. Ports are [re]connected every process cycle. (the pointers may change any time). printf("ladspa_run %d\n", SampleCount); to ladspa_run() and you should see e.g. ladspa_connect_port 0 ... ladspa_connect_port 1 ... ladspa_run 1024 ladspa_connect_port 0 ... ladspa_connect_port 1 ... ladspa_run 1024 |
|
same for LV2. connect_port() is called every cycle. Usually the control-ports stay (same pointer) and audio buffers change every cycle, but you can't rely on this. The port pointers are only valid during run(). http://lv2plug.in/doc/html/group__lv2core.html#a4d904937a1bd27cb5f5478f95c708b16 |
|
Okay them, it's not a bug. Thank you for information. |
|
Not a problem |
|
marking this as resolved. but feel free to ask more questions.. Good resource in general is the linux-audio-dev email list http://lists.linuxaudio.org/listinfo/linux-audio-dev and the #lad IRC chat channel on freenode http://webchat.freenode.net/?channels=lad |
|
Issue has been closed automatically, by Trigger Close Plugin. Feel free to re-open with additional information if you think the issue is not resolved. |
Date Modified | Username | Field | Change |
---|---|---|---|
2015-10-14 12:15 | SadKo | New Issue | |
2015-10-14 22:07 | x42 | Note Added: 0017459 | |
2015-10-15 15:08 | SadKo | File Added: test.cpp | |
2015-10-15 15:13 | SadKo | Note Added: 0017461 | |
2015-10-15 15:27 | SadKo | Note Added: 0017462 | |
2015-10-15 17:39 | x42 | Note Added: 0017463 | |
2015-10-15 18:05 | x42 | Note Added: 0017464 | |
2015-10-15 19:27 | SadKo | Note Added: 0017466 | |
2015-10-15 19:28 | SadKo | Note Added: 0017467 | |
2015-10-15 23:59 | x42 | Note Added: 0017468 | |
2015-10-15 23:59 | x42 | Status | new => resolved |
2015-10-15 23:59 | x42 | Resolution | open => no change required |
2015-10-15 23:59 | x42 | Assigned To | => x42 |
2020-04-19 20:17 | system | Note Added: 0023550 | |
2020-04-19 20:17 | system | Status | resolved => closed |