diff options
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | hosts/lv2_jack_host.c | 114 | ||||
-rw-r--r-- | hosts/lv2_simple_jack_host.c | 46 | ||||
-rw-r--r-- | slv2/port.h | 26 | ||||
-rw-r--r-- | slv2/types.h | 42 | ||||
-rw-r--r-- | src/plugin.c | 4 | ||||
-rw-r--r-- | src/pluginguiinstance.c | 2 | ||||
-rw-r--r-- | src/port.c | 107 | ||||
-rw-r--r-- | utils/lv2_inspect.c | 49 |
9 files changed, 253 insertions, 151 deletions
diff --git a/configure.ac b/configure.ac index 7285819..f0400b8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,15 +2,19 @@ AC_PREREQ(2.59) # SLV2 interface version (libtool shared library versioning) # -# current = incremented whenever the public slv2 API is changed -# revision = incremented when the slv2 implementation is changed +# current = incremented whenever the public API is changed +# revision = incremented when the implementation of current is changed # age = current library is both source and binary compatible with -# interfaces current,current-1,...,current-age +# interfaces: current,current-1,...,current-age # # See libtool documentation for detailed documentation -SLV2_API_CURRENT=1 +# +# Version history: +# 0.0.1 = 0,0,0 +# current svn = 2,0,0 +SLV2_API_CURRENT=2 SLV2_API_REVISION=0 -SLV2_API_AGE=1 +SLV2_API_AGE=0 AC_INIT([slv2],[0.0.2pre],[dave@drobilla.net]) AC_CONFIG_SRCDIR([src/plugin.c]) diff --git a/hosts/lv2_jack_host.c b/hosts/lv2_jack_host.c index 4a9995f..7c8ef60 100644 --- a/hosts/lv2_jack_host.c +++ b/hosts/lv2_jack_host.c @@ -30,11 +30,12 @@ #define MIDI_BUFFER_SIZE 1024 struct Port { - SLV2PortClass class; - SLV2Port slv2_port; - jack_port_t* jack_port; /**< For audio and MIDI ports, otherwise NULL */ - float control; /**< For control ports, otherwise 0.0f */ - LV2_MIDI* midi_buffer; /**< For midi ports, otherwise NULL */ + SLV2PortDirection direction; + SLV2PortType type; + SLV2Port slv2_port; + jack_port_t* jack_port; /**< For audio and MIDI ports, otherwise NULL */ + float control; /**< For control ports, otherwise 0.0f */ + LV2_MIDI* midi_buffer; /**< For midi ports, otherwise NULL */ }; @@ -170,7 +171,8 @@ create_port(struct JackHost* host, { struct Port* const port = &host->ports[port_index]; - port->class = SLV2_UNKNOWN_PORT_CLASS; + port->direction = SLV2_PORT_DIRECTION_UNKNOWN; + port->type = SLV2_PORT_TYPE_UNKNOWN; port->slv2_port = slv2_plugin_get_port_by_index(host->plugin, port_index); port->jack_port = NULL; port->control = 0.0f; @@ -181,41 +183,52 @@ create_port(struct JackHost* host, /* Get the port symbol (label) for console printing */ char* symbol = slv2_port_get_symbol(host->plugin, port->slv2_port); - /* Get the 'class' (not data type) of the port (control input, audio output, etc) */ - port->class = slv2_port_get_class(host->plugin, port->slv2_port); + /* Get the direction of the port (input, output) */ + port->direction = slv2_port_get_direction(host->plugin, port->slv2_port); + + /* Get the (data) type of the port (control, audio, MIDI, OSC) */ + port->type = slv2_port_get_type(host->plugin, port->slv2_port); + + if (port->type == SLV2_PORT_TYPE_CONTROL) + port->control = slv2_port_get_default_value(host->plugin, port->slv2_port); + + enum JackPortFlags jack_flags = 0; + switch (port->direction) { + case SLV2_PORT_DIRECTION_INPUT: + jack_flags = JackPortIsInput; break; + case SLV2_PORT_DIRECTION_OUTPUT: + jack_flags = JackPortIsOutput; break; + default: + // FIXME: check if port connection is is optional and die if not + slv2_instance_connect_port(host->instance, port_index, NULL); + return; + } - /* Connect the port based on it's 'class' */ - switch (port->class) { - case SLV2_CONTROL_INPUT: - port->control = slv2_port_get_default_value(host->plugin, port->slv2_port); - slv2_instance_connect_port(host->instance, port_index, &port->control); - printf("Set %s to %f\n", symbol, host->ports[port_index].control); - break; - case SLV2_CONTROL_OUTPUT: + /* Set control values */ + if (port->direction == SLV2_PORT_DIRECTION_INPUT && port->type == SLV2_PORT_TYPE_CONTROL) { + port->control = slv2_port_get_default_value(host->plugin, port->slv2_port); + printf("Set %s to %f\n", symbol, host->ports[port_index].control); + } + + /* Connect the port based on it's type */ + switch (port->type) { + case SLV2_PORT_TYPE_CONTROL: slv2_instance_connect_port(host->instance, port_index, &port->control); break; - case SLV2_AUDIO_INPUT: + case SLV2_PORT_TYPE_AUDIO: port->jack_port = jack_port_register(host->jack_client, - symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + symbol, JACK_DEFAULT_AUDIO_TYPE, jack_flags, 0); break; - case SLV2_AUDIO_OUTPUT: - port->jack_port = jack_port_register(host->jack_client, - symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - break; - case SLV2_MIDI_INPUT: + case SLV2_PORT_TYPE_MIDI: port->jack_port = jack_port_register(host->jack_client, symbol, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); port->midi_buffer = lv2midi_new(MIDI_BUFFER_SIZE); slv2_instance_connect_port(host->instance, port_index, port->midi_buffer); break; - case SLV2_MIDI_OUTPUT: - port->jack_port = jack_port_register(host->jack_client, - symbol, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); - port->midi_buffer = lv2midi_new(MIDI_BUFFER_SIZE); - slv2_instance_connect_port(host->instance, port_index, port->midi_buffer); - break; default: - fprintf(stderr, "ERROR: Unknown port class\n"); + // FIXME: check if port connection is is optional and die if not + slv2_instance_connect_port(host->instance, port_index, NULL); + fprintf(stderr, "WARNING: Unknown port type, port not connected.\n"); } free(symbol); @@ -233,32 +246,34 @@ jack_process_cb(jack_nframes_t nframes, void* data) if (!host->ports[p].jack_port) continue; - if (host->ports[p].class == SLV2_AUDIO_INPUT - || host->ports[p].class == SLV2_AUDIO_OUTPUT) { + if (host->ports[p].type == SLV2_PORT_TYPE_AUDIO) { + slv2_instance_connect_port(host->instance, p, jack_port_get_buffer(host->ports[p].jack_port, nframes)); - } else if (host->ports[p].class == SLV2_MIDI_INPUT) { - void* jack_buffer = jack_port_get_buffer(host->ports[p].jack_port, nframes); + + } else if (host->ports[p].type == SLV2_PORT_TYPE_MIDI) { lv2midi_reset_buffer(host->ports[p].midi_buffer); - - LV2_MIDIState state; - lv2midi_reset_state(&state, host->ports[p].midi_buffer, nframes); - const jack_nframes_t event_count - = jack_midi_get_event_count(jack_buffer); - - jack_midi_event_t ev; + if (host->ports[p].direction == SLV2_PORT_DIRECTION_INPUT) { + void* jack_buffer = jack_port_get_buffer(host->ports[p].jack_port, nframes); - for (jack_nframes_t e=0; e < event_count; ++e) { - jack_midi_event_get(&ev, jack_buffer, e); - lv2midi_put_event(&state, (double)ev.time, ev.size, ev.buffer); - } + lv2midi_reset_buffer(host->ports[p].midi_buffer); - } else if (host->ports[p].class == SLV2_MIDI_OUTPUT) { + LV2_MIDIState state; + lv2midi_reset_state(&state, host->ports[p].midi_buffer, nframes); - lv2midi_reset_buffer(host->ports[p].midi_buffer); - + const jack_nframes_t event_count + = jack_midi_get_event_count(jack_buffer); + + jack_midi_event_t ev; + + for (jack_nframes_t e=0; e < event_count; ++e) { + jack_midi_event_get(&ev, jack_buffer, e); + lv2midi_put_event(&state, (double)ev.time, ev.size, ev.buffer); + } + + } } } @@ -270,7 +285,8 @@ jack_process_cb(jack_nframes_t nframes, void* data) /* Deliver output */ for (uint32_t p=0; p < host->num_ports; ++p) { if (host->ports[p].jack_port - && host->ports[p].class == SLV2_MIDI_OUTPUT) { + && host->ports[p].direction == SLV2_PORT_DIRECTION_OUTPUT + && host->ports[p].type == SLV2_PORT_TYPE_MIDI) { void* jack_buffer = jack_port_get_buffer(host->ports[p].jack_port, nframes); diff --git a/hosts/lv2_simple_jack_host.c b/hosts/lv2_simple_jack_host.c index d0fabc1..4b1bcc3 100644 --- a/hosts/lv2_simple_jack_host.c +++ b/hosts/lv2_simple_jack_host.c @@ -160,32 +160,34 @@ create_port(struct JackHost* host, host->jack_ports[index] = NULL; host->controls[index] = 0.0f; - /* Get the 'class' of the port (control input, audio output, etc) */ - SLV2PortClass class = slv2_port_get_class(host->plugin, port); + /* Get the direction of the port (input, output) */ + SLV2PortDirection direction = slv2_port_get_direction(host->plugin, port); - /* Connect the port based on it's 'class' */ - switch (class) { - case SLV2_CONTROL_INPUT: - host->controls[index] = slv2_port_get_default_value(host->plugin, port); - slv2_instance_connect_port(host->instance, index, &host->controls[index]); - printf("Set %s to %f\n", symbol, host->controls[index]); - break; - case SLV2_CONTROL_OUTPUT: + /* Get the (data) type of the port (control, audio, MIDI, OSC) */ + SLV2PortType type = slv2_port_get_type(host->plugin, port); + + /* Connect control ports to controls array */ + if (type == SLV2_PORT_TYPE_CONTROL) { + + /* Set default control values for inputs */ + if (direction == SLV2_PORT_DIRECTION_INPUT) { + host->controls[index] = slv2_port_get_default_value(host->plugin, port); + printf("Set %s to %f\n", symbol, host->controls[index]); + } + slv2_instance_connect_port(host->instance, index, &host->controls[index]); - break; - case SLV2_AUDIO_INPUT: - host->jack_ports[index] = jack_port_register(host->jack_client, - symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); - break; - case SLV2_AUDIO_OUTPUT: - host->jack_ports[index] = jack_port_register(host->jack_client, - symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - break; - default: + + } else if (type == SLV2_PORT_TYPE_AUDIO) { + + host->jack_ports[index] = jack_port_register(host->jack_client, symbol, + JACK_DEFAULT_AUDIO_TYPE, + (direction == SLV2_PORT_DIRECTION_INPUT) ? JackPortIsInput : JackPortIsOutput, 0); + + } else { // Simple examples don't have to be robust :) - die("ERROR: Unknown port type, aborting messily!"); + die("ERROR: Unknown port type, aborting messily!\n"); } - + free(symbol); } diff --git a/slv2/port.h b/slv2/port.h index db1c308..08c1e45 100644 --- a/slv2/port.h +++ b/slv2/port.h @@ -60,6 +60,16 @@ SLV2Values slv2_port_get_hints(SLV2Plugin plugin, SLV2Port port); +#if 0 +/** Return whether a port has a certain hint. + * + * Time = Query + */ +bool +slv2_port_has_hint(SLV2Plugin p, + SLV2Port port, + SLV2Value hint) +#endif /** Get the symbol of a port given the index. * @@ -87,13 +97,21 @@ slv2_port_get_name(SLV2Plugin plugin, SLV2Port port); -/** Get the class (input/output, data type, rate...) of a port. +/** Get the direction (input, output) of a port. * * Time = Query */ -SLV2PortClass -slv2_port_get_class(SLV2Plugin plugin, - SLV2Port port); +SLV2PortDirection +slv2_port_get_direction(SLV2Plugin plugin, + SLV2Port port); + +/** Get the (data) type of a port. + * + * Time = Query + */ +SLV2PortType +slv2_port_get_type(SLV2Plugin plugin, + SLV2Port port); /** Get the default value of a port. diff --git a/slv2/types.h b/slv2/types.h index 0eba199..4b1782d 100644 --- a/slv2/types.h +++ b/slv2/types.h @@ -27,21 +27,35 @@ extern "C" { #endif -/** Class (direction and type) of a port +/** (Data) Type of a port * - * Note that ports may be of other classes not listed here, this is just - * to make the most common case simple. Use slv2_port_get_value(p, "rdf:type") - * if you need further class information. + * SLV2_UNKNOWN_PORT_TYPE means the Port is not of any type SLV2 understands + * (currently Control, Audio, MIDI, and OSC). + * + * Further class information can be using slv2_port_get_value(p, "rdf:type") + * or a custom query. + */ +typedef enum _SLV2PortType { + SLV2_PORT_TYPE_UNKNOWN, + SLV2_PORT_TYPE_CONTROL, /**< One float per block */ + SLV2_PORT_TYPE_AUDIO, /**< One float per frame */ + SLV2_PORT_TYPE_MIDI, /**< A buffer of MIDI data (LL extension) */ + SLV2_PORT_TYPE_OSC, /**< A buffer of OSC data (DR extension) */ +} SLV2PortType; + +/** Direction (input or output) of a port + * + * SLV2_UNKNOWN_PORT_DIRECTION means the Port is only of type lv2:Port + * (neither lv2:Input or lv2:Output) as far as SLV2 understands. + * + * Further class information can be using slv2_port_get_value(p, "rdf:type") + * or a custom query. */ -typedef enum _SLV2PortClass { - SLV2_UNKNOWN_PORT_CLASS, - SLV2_CONTROL_INPUT, /**< One input float per block */ - SLV2_CONTROL_OUTPUT, /**< One output float per block */ - SLV2_AUDIO_INPUT, /**< One input float per frame */ - SLV2_AUDIO_OUTPUT, /**< One output float per frame */ - SLV2_MIDI_INPUT, /**< MIDI input (LL extension) */ - SLV2_MIDI_OUTPUT /**< MIDI output (LL extension) */ -} SLV2PortClass; +typedef enum _SLV2PortDirection { + SLV2_PORT_DIRECTION_UNKNOWN, /**< Neither input or output */ + SLV2_PORT_DIRECTION_INPUT, /**< Plugin reads from port when run */ + SLV2_PORT_DIRECTION_OUTPUT, /**< Plugin writes to port when run */ +} SLV2PortDirection; /** The format of a URI string. @@ -58,7 +72,7 @@ typedef enum _SLV2URIType { /** A type of plugin GUI (corresponding to some LV2 GUI extension). */ typedef enum _SLV2GUIType { - SLV2_GTK2_GUI ///< http://ll-plugins.nongnu.org/lv2/ext/gtk2gui + SLV2_GUI_TYPE_GTK2 ///< http://ll-plugins.nongnu.org/lv2/ext/gtk2gui } SLV2GUIType; diff --git a/src/plugin.c b/src/plugin.c index 80f59a5..ed80ff1 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -571,7 +571,7 @@ slv2_plugin_get_guis(SLV2Plugin plugin) for (int i=0; i < raptor_sequence_size(result); ++i) { SLV2Value val = (SLV2Value)raptor_sequence_get_at(result, i); val->type = SLV2_VALUE_GUI; - val->val.gui_type_val = SLV2_GTK2_GUI; + val->val.gui_type_val = SLV2_GUI_TYPE_GTK2; } return result; @@ -612,7 +612,7 @@ const char* slv2_gui_type_get_uri(SLV2GUIType type) { // Only one for now... - assert(type == SLV2_GTK2_GUI); + assert(type == SLV2_GUI_TYPE_GTK2); return "http://ll-plugins.nongnu.org/lv2/ext/gtk2gui"; } diff --git a/src/pluginguiinstance.c b/src/pluginguiinstance.c index c3a6292..c115751 100644 --- a/src/pluginguiinstance.c +++ b/src/pluginguiinstance.c @@ -40,7 +40,7 @@ slv2_plugin_gtk2_gui_instantiate(SLV2Plugin plugin, { assert(gui->type == SLV2_VALUE_GUI); - if (gui->val.gui_type_val != SLV2_GTK2_GUI) + if (gui->val.gui_type_val != SLV2_GUI_TYPE_GTK2) return NULL; struct _SLV2GUIInstance* result = NULL; @@ -63,56 +63,99 @@ slv2_port_duplicate(SLV2Port port) } -SLV2PortClass -slv2_port_get_class(SLV2Plugin p, - SLV2Port port) +SLV2PortDirection +slv2_port_get_direction(SLV2Plugin p, + SLV2Port port) { - SLV2Values class = slv2_port_get_value(p, port, "rdf:type"); - assert(class); + SLV2Values direction = slv2_port_get_value(p, port, "rdf:type"); - SLV2PortClass ret = SLV2_UNKNOWN_PORT_CLASS; + SLV2PortDirection ret = SLV2_PORT_DIRECTION_UNKNOWN; - int io = -1; // 0 = in, 1 = out - enum { UNKNOWN, AUDIO, CONTROL, MIDI } type = UNKNOWN; + if (!direction) + return ret; - for (unsigned i=0; i < slv2_values_size(class); ++i) { - SLV2Value val = slv2_values_get_at(class, i); + for (unsigned i=0; i < slv2_values_size(direction); ++i) { + SLV2Value val = slv2_values_get_at(direction, i); if (slv2_value_is_uri(val)) { const char* uri = slv2_value_as_uri(val); if (!strcmp(uri, "http://lv2plug.in/ontology#InputPort")) - io = 0; + ret = SLV2_PORT_DIRECTION_INPUT; else if (!strcmp(uri, "http://lv2plug.in/ontology#OutputPort")) - io = 1; - else if (!strcmp(uri, "http://lv2plug.in/ontology#ControlPort")) - type = CONTROL; + ret = SLV2_PORT_DIRECTION_OUTPUT; + } + } + + slv2_values_free(direction); + + return ret; +} + + +SLV2PortType +slv2_port_get_type(SLV2Plugin p, + SLV2Port port) +{ + SLV2Values type = slv2_port_get_value(p, port, "rdf:type"); + + SLV2PortType ret = SLV2_PORT_TYPE_UNKNOWN; + + if (!type) + return ret; + + for (unsigned i=0; i < slv2_values_size(type); ++i) { + SLV2Value val = slv2_values_get_at(type, i); + if (slv2_value_is_uri(val)) { + const char* uri = slv2_value_as_uri(val); + if (!strcmp(uri, "http://lv2plug.in/ontology#ControlPort")) + ret = SLV2_PORT_TYPE_CONTROL; else if (!strcmp(uri, "http://lv2plug.in/ontology#AudioPort")) - type = AUDIO; + ret = SLV2_PORT_TYPE_AUDIO; else if (!strcmp(uri, "http://ll-plugins.nongnu.org/lv2/ext/MidiPort")) - type = MIDI; + ret = SLV2_PORT_TYPE_MIDI; + else if (!strcmp(uri, "http://drobilla.net/ns/lv2ext/osc/0#OSCPort")) + ret = SLV2_PORT_TYPE_OSC; } } - if (io == 0) { - if (type == AUDIO) - ret = SLV2_AUDIO_INPUT; - else if (type == CONTROL) - ret = SLV2_CONTROL_INPUT; - else if (type == MIDI) - ret = SLV2_MIDI_INPUT; - } else if (io == 1) { - if (type == AUDIO) - ret = SLV2_AUDIO_OUTPUT; - else if (type == CONTROL) - ret = SLV2_CONTROL_OUTPUT; - else if (type == MIDI) - ret = SLV2_MIDI_OUTPUT; + slv2_values_free(type); + + return ret; +} + +#if 0 +bool +slv2_port_has_hint(SLV2Plugin p, + SLV2Port port, + SLV2Value hint) +{ + /* FIXME: Add SLV2Value QName stuff to make this not suck to use */ + + SLV2Values hints = slv2_port_get_value(p, port, "lv2:portHint"); + + if (!hints) + return false; + + for (unsigned i=0; i < slv2_values_size(type); ++i) { + const SLV2Value val = slv2_values_get_at(type, i); + if (slv2_value_is_uri(val)) { + const char* uri = slv2_value_as_uri(val); + if (!strcmp(uri, "http://lv2plug.in/ontology#connectionOptional")) + return true; + ret = SLV2_PORT_TYPE_CONTROL; + else if (!strcmp(uri, "http://lv2plug.in/ontology#AudioPort")) + ret = SLV2_PORT_TYPE_AUDIO; + else if (!strcmp(uri, "http://ll-plugins.nongnu.org/lv2/ext/MidiPort")) + ret = SLV2_PORT_TYPE_MIDI; + else if (!strcmp(uri, "http://drobilla.net/ns/lv2ext/osc/0#OSCPort")) + ret = SLV2_PORT_TYPE_OSC; + } } - slv2_values_free(class); + slv2_values_free(type); return ret; } - +#endif SLV2Values slv2_port_get_value(SLV2Plugin p, diff --git a/utils/lv2_inspect.c b/utils/lv2_inspect.c index a3b1b5d..d96a193 100644 --- a/utils/lv2_inspect.c +++ b/utils/lv2_inspect.c @@ -27,47 +27,52 @@ print_port(SLV2Plugin p, uint32_t index) SLV2Port port = slv2_plugin_get_port_by_index(p, index); char* str = NULL; - SLV2PortClass cl = SLV2_UNKNOWN_PORT_CLASS; printf("\n\tPort %d:\n", index); - cl = slv2_port_get_class(p, port); - printf("\t\tClass: "); - switch (cl) { - case SLV2_CONTROL_INPUT: - printf("Control input"); + SLV2PortDirection dir = slv2_port_get_direction(p, port); + + printf("\t\tDirection: "); + switch (dir) { + case SLV2_PORT_DIRECTION_INPUT: + printf("Input"); break; - case SLV2_CONTROL_OUTPUT: - printf("Control output"); + case SLV2_PORT_DIRECTION_OUTPUT: + printf("Output"); break; - case SLV2_AUDIO_INPUT: - printf("Audio input"); + default: + printf("Unknown"); + } + + SLV2PortType type = slv2_port_get_type(p, port); + + printf("\n\t\tType: "); + switch (type) { + case SLV2_PORT_TYPE_CONTROL: + printf("Control"); break; - case SLV2_AUDIO_OUTPUT: - printf("Audio output"); + case SLV2_PORT_TYPE_AUDIO: + printf("Audio"); break; - case SLV2_MIDI_INPUT: - printf("MIDI input"); + case SLV2_PORT_TYPE_MIDI: + printf("MIDI"); break; - case SLV2_MIDI_OUTPUT: - printf("MIDI output"); + case SLV2_PORT_TYPE_OSC: + printf("OSC"); break; - case SLV2_UNKNOWN_PORT_CLASS: + default: printf("Unknown"); - break; } - printf("\n"); str = slv2_port_get_symbol(p, port); - printf("\t\tSymbol: %s\n", str); + printf("\n\t\tSymbol: %s\n", str); free(str); str = slv2_port_get_name(p, port); printf("\t\tName: %s\n", str); free(str); - if (cl == SLV2_CONTROL_INPUT || - cl == SLV2_CONTROL_OUTPUT) { + if (type == SLV2_PORT_TYPE_CONTROL) { printf("\t\tMinimum: %f\n", slv2_port_get_minimum_value(p, port)); printf("\t\tMaximum: %f\n", slv2_port_get_maximum_value(p, port)); printf("\t\tDefault: %f\n", slv2_port_get_default_value(p, port)); |