| @@ -29,7 +29,7 @@ claudia: src/ui_claudia.py \ | |||
| carla: carla_backend carla_bridges carla_discovery carla_gui | |||
| carla_backend: | |||
| # $(MAKE) -C src/carla | |||
| $(MAKE) -C src/carla | |||
| carla_bridges: | |||
| # $(MAKE) native$(_arch_n) -C src/carla-bridges | |||
| @@ -0,0 +1,56 @@ | |||
| /* | |||
| LV2 Data Access Extension | |||
| Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file data-access.h | |||
| C header for the LV2 Extension Data extension | |||
| <http://lv2plug.in/ns/ext/data-access>. | |||
| This extension defines a method for (e.g.) plugin UIs to have (possibly | |||
| marshalled) access to the extension_data function on a plugin instance. | |||
| */ | |||
| #ifndef LV2_DATA_ACCESS_H | |||
| #define LV2_DATA_ACCESS_H | |||
| #define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access" | |||
| /** | |||
| The data field of the LV2_Feature for this extension. | |||
| To support this feature the host must pass an LV2_Feature struct to the | |||
| instantiate method with URI "http://lv2plug.in/ns/ext/data-access" | |||
| and data pointed to an instance of this struct. | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| A pointer to a method the UI can call to get data (of a type specified | |||
| by some other extension) from the plugin. | |||
| This call never is never guaranteed to return anything, UIs should | |||
| degrade gracefully if direct access to the plugin data is not possible | |||
| (in which case this function will return NULL). | |||
| This is for access to large data that can only possibly work if the UI | |||
| and plugin are running in the same process. For all other things, use | |||
| the normal LV2 UI communication system. | |||
| */ | |||
| const void* (*data_access)(const char* uri); | |||
| } LV2_Extension_Data_Feature; | |||
| #endif /* LV2_DATA_ACCESS_H */ | |||
| @@ -0,0 +1,248 @@ | |||
| /* | |||
| Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file event-helpers.h Helper functions for the LV2 Event extension | |||
| <http://lv2plug.in/ns/ext/event>. | |||
| */ | |||
| #ifndef LV2_EVENT_HELPERS_H | |||
| #define LV2_EVENT_HELPERS_H | |||
| #include <stdint.h> | |||
| #include <stdbool.h> | |||
| #include <string.h> | |||
| #include <stdlib.h> | |||
| #include <assert.h> | |||
| #include "event.h" | |||
| /** @file | |||
| * Helper functions for the LV2 Event extension | |||
| * <http://lv2plug.in/ns/ext/event>. | |||
| * | |||
| * These functions are provided for convenience only, use of them is not | |||
| * required for supporting lv2ev (i.e. the events extension is defined by the | |||
| * raw buffer format described in lv2_event.h and NOT by this API). | |||
| * | |||
| * Note that these functions are all static inline which basically means: | |||
| * do not take the address of these functions. */ | |||
| /** Pad a size to 64 bits (for event sizes) */ | |||
| static inline uint16_t | |||
| lv2_event_pad_size(uint16_t size) | |||
| { | |||
| return (size + 7) & (~7); | |||
| } | |||
| /** Initialize (empty, reset..) an existing event buffer. | |||
| * The contents of buf are ignored entirely and overwritten, except capacity | |||
| * which is unmodified. */ | |||
| static inline void | |||
| lv2_event_buffer_reset(LV2_Event_Buffer* buf, | |||
| uint16_t stamp_type, | |||
| uint8_t *data) | |||
| { | |||
| buf->data = data; | |||
| buf->header_size = sizeof(LV2_Event_Buffer); | |||
| buf->stamp_type = stamp_type; | |||
| buf->event_count = 0; | |||
| buf->size = 0; | |||
| } | |||
| /** Allocate a new, empty event buffer. */ | |||
| static inline LV2_Event_Buffer* | |||
| lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type) | |||
| { | |||
| const size_t size = sizeof(LV2_Event_Buffer) + capacity; | |||
| LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(size); | |||
| if (buf != NULL) { | |||
| buf->capacity = capacity; | |||
| lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1)); | |||
| return buf; | |||
| } else { | |||
| return NULL; | |||
| } | |||
| } | |||
| /** An iterator over an LV2_Event_Buffer. | |||
| * | |||
| * Multiple simultaneous read iterators over a single buffer is fine, | |||
| * but changing the buffer invalidates all iterators (e.g. RW Lock). */ | |||
| typedef struct { | |||
| LV2_Event_Buffer* buf; | |||
| uint32_t offset; | |||
| } LV2_Event_Iterator; | |||
| /** Reset an iterator to point to the start of @a buf. | |||
| * @return True if @a iter is valid, otherwise false (buffer is empty) */ | |||
| static inline bool | |||
| lv2_event_begin(LV2_Event_Iterator* iter, | |||
| LV2_Event_Buffer* buf) | |||
| { | |||
| iter->buf = buf; | |||
| iter->offset = 0; | |||
| return (buf->size > 0); | |||
| } | |||
| /** Check if @a iter is valid. | |||
| * @return True if @a iter is valid, otherwise false (past end of buffer) */ | |||
| static inline bool | |||
| lv2_event_is_valid(LV2_Event_Iterator* iter) | |||
| { | |||
| return (iter->offset < iter->buf->size); | |||
| } | |||
| /** Advance @a iter forward one event. | |||
| * @a iter must be valid. | |||
| * @return True if @a iter is valid, otherwise false (reached end of buffer) */ | |||
| static inline bool | |||
| lv2_event_increment(LV2_Event_Iterator* iter) | |||
| { | |||
| assert(lv2_event_is_valid(iter)); | |||
| LV2_Event* const ev = (LV2_Event*)( | |||
| (uint8_t*)iter->buf->data + iter->offset); | |||
| iter->offset += lv2_event_pad_size(sizeof(LV2_Event) + ev->size); | |||
| return true; | |||
| } | |||
| /** Dereference an event iterator (get the event currently pointed at). | |||
| * @a iter must be valid. | |||
| * @a data if non-NULL, will be set to point to the contents of the event | |||
| * returned. | |||
| * @return A Pointer to the event @a iter is currently pointing at, or NULL | |||
| * if the end of the buffer is reached (in which case @a data is | |||
| * also set to NULL). */ | |||
| static inline LV2_Event* | |||
| lv2_event_get(LV2_Event_Iterator* iter, | |||
| uint8_t** data) | |||
| { | |||
| assert(lv2_event_is_valid(iter)); | |||
| LV2_Event* const ev = (LV2_Event*)( | |||
| (uint8_t*)iter->buf->data + iter->offset); | |||
| if (data) | |||
| *data = (uint8_t*)ev + sizeof(LV2_Event); | |||
| return ev; | |||
| } | |||
| /** Write an event at @a iter. | |||
| * The event (if any) pointed to by @a iter will be overwritten, and @a iter | |||
| * incremented to point to the following event (i.e. several calls to this | |||
| * function can be done in sequence without twiddling iter in-between). | |||
| * @return True if event was written, otherwise false (buffer is full). */ | |||
| static inline bool | |||
| lv2_event_write(LV2_Event_Iterator* iter, | |||
| uint32_t frames, | |||
| uint32_t subframes, | |||
| uint16_t type, | |||
| uint16_t size, | |||
| const uint8_t* data) | |||
| { | |||
| if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) | |||
| return false; | |||
| LV2_Event* const ev = (LV2_Event*)( | |||
| (uint8_t*)iter->buf->data + iter->offset); | |||
| ev->frames = frames; | |||
| ev->subframes = subframes; | |||
| ev->type = type; | |||
| ev->size = size; | |||
| memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size); | |||
| ++iter->buf->event_count; | |||
| size = lv2_event_pad_size(sizeof(LV2_Event) + size); | |||
| iter->buf->size += size; | |||
| iter->offset += size; | |||
| return true; | |||
| } | |||
| /** Reserve space for an event in the buffer and return a pointer to | |||
| the memory where the caller can write the event data, or NULL if there | |||
| is not enough room in the buffer. */ | |||
| static inline uint8_t* | |||
| lv2_event_reserve(LV2_Event_Iterator* iter, | |||
| uint32_t frames, | |||
| uint32_t subframes, | |||
| uint16_t type, | |||
| uint16_t size) | |||
| { | |||
| size = lv2_event_pad_size(size); | |||
| if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) | |||
| return NULL; | |||
| LV2_Event* const ev = (LV2_Event*)((uint8_t*)iter->buf->data + | |||
| iter->offset); | |||
| ev->frames = frames; | |||
| ev->subframes = subframes; | |||
| ev->type = type; | |||
| ev->size = size; | |||
| ++iter->buf->event_count; | |||
| size = lv2_event_pad_size(sizeof(LV2_Event) + size); | |||
| iter->buf->size += size; | |||
| iter->offset += size; | |||
| return (uint8_t*)ev + sizeof(LV2_Event); | |||
| } | |||
| /** Write an event at @a iter. | |||
| * The event (if any) pointed to by @a iter will be overwritten, and @a iter | |||
| * incremented to point to the following event (i.e. several calls to this | |||
| * function can be done in sequence without twiddling iter in-between). | |||
| * @return True if event was written, otherwise false (buffer is full). */ | |||
| static inline bool | |||
| lv2_event_write_event(LV2_Event_Iterator* iter, | |||
| const LV2_Event* ev, | |||
| const uint8_t* data) | |||
| { | |||
| if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + ev->size) | |||
| return false; | |||
| LV2_Event* const write_ev = (LV2_Event*)( | |||
| (uint8_t*)iter->buf->data + iter->offset); | |||
| *write_ev = *ev; | |||
| memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size); | |||
| ++iter->buf->event_count; | |||
| const uint16_t size = lv2_event_pad_size(sizeof(LV2_Event) + ev->size); | |||
| iter->buf->size += size; | |||
| iter->offset += size; | |||
| return true; | |||
| } | |||
| #endif /* LV2_EVENT_HELPERS_H */ | |||
| @@ -0,0 +1,280 @@ | |||
| /* | |||
| Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
| Copyright 2006-2007 Lars Luthman <lars.luthman@gmail.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file event.h | |||
| C API for the LV2 Event extension <http://lv2plug.in/ns/ext/event>. | |||
| This extension is a generic transport mechanism for time stamped events | |||
| of any type (e.g. MIDI, OSC, ramps, etc). Each port can transport mixed | |||
| events of any type; the type of events and timestamps are defined by a URI | |||
| which is mapped to an integer by the host for performance reasons. | |||
| This extension requires the host to support the LV2 URI Map extension. | |||
| Any host which supports this extension MUST guarantee that any call to | |||
| the LV2 URI Map uri_to_id function with the URI of this extension as the | |||
| 'map' argument returns a value within the range of uint16_t. | |||
| */ | |||
| #ifndef LV2_EVENT_H | |||
| #define LV2_EVENT_H | |||
| #define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event" | |||
| #define LV2_EVENT_AUDIO_STAMP 0 | |||
| #include <stdint.h> | |||
| /** | |||
| The best Pulses Per Quarter Note for tempo-based uint32_t timestamps. | |||
| Equal to 2^12 * 5 * 7 * 9 * 11 * 13 * 17, which is evenly divisble | |||
| by all integers from 1 through 18 inclusive, and powers of 2 up to 2^12. | |||
| */ | |||
| static const uint32_t LV2_EVENT_PPQN = 3136573440U; | |||
| /** | |||
| An LV2 event (header only). | |||
| LV2 events are generic time-stamped containers for any type of event. | |||
| The type field defines the format of a given event's contents. | |||
| This struct defines the header of an LV2 event. An LV2 event is a single | |||
| chunk of POD (plain old data), usually contained in a flat buffer (see | |||
| LV2_EventBuffer below). Unless a required feature says otherwise, hosts may | |||
| assume a deep copy of an LV2 event can be created safely using a simple: | |||
| memcpy(ev_copy, ev, sizeof(LV2_Event) + ev->size); (or equivalent) | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| The frames portion of timestamp. The units used here can optionally be | |||
| set for a port (with the lv2ev:timeUnits property), otherwise this is | |||
| audio frames, corresponding to the sample_count parameter of the LV2 run | |||
| method (e.g. frame 0 is the first frame for that call to run). | |||
| */ | |||
| uint32_t frames; | |||
| /** | |||
| The sub-frames portion of timestamp. The units used here can optionally | |||
| be set for a port (with the lv2ev:timeUnits property), otherwise this is | |||
| 1/(2^32) of an audio frame. | |||
| */ | |||
| uint32_t subframes; | |||
| /** | |||
| The type of this event, as a number which represents some URI | |||
| defining an event type. This value MUST be some value previously | |||
| returned from a call to the uri_to_id function defined in the LV2 | |||
| URI map extension (see lv2_uri_map.h). | |||
| There are special rules which must be followed depending on the type | |||
| of an event. If the plugin recognizes an event type, the definition | |||
| of that event type will describe how to interpret the event, and | |||
| any required behaviour. Otherwise, if the type is 0, this event is a | |||
| non-POD event and lv2_event_unref MUST be called if the event is | |||
| 'dropped' (see above). Even if the plugin does not understand an event, | |||
| it may pass the event through to an output by simply copying (and NOT | |||
| calling lv2_event_unref). These rules are designed to allow for generic | |||
| event handling plugins and large non-POD events, but with minimal hassle | |||
| on simple plugins that "don't care" about these more advanced features. | |||
| */ | |||
| uint16_t type; | |||
| /** | |||
| The size of the data portion of this event in bytes, which immediately | |||
| follows. The header size (12 bytes) is not included in this value. | |||
| */ | |||
| uint16_t size; | |||
| /* size bytes of data follow here */ | |||
| } LV2_Event; | |||
| /** | |||
| A buffer of LV2 events (header only). | |||
| Like events (which this contains) an event buffer is a single chunk of POD: | |||
| the entire buffer (including contents) can be copied with a single memcpy. | |||
| The first contained event begins sizeof(LV2_EventBuffer) bytes after the | |||
| start of this struct. | |||
| After this header, the buffer contains an event header (defined by struct | |||
| LV2_Event), followed by that event's contents (padded to 64 bits), followed | |||
| by another header, etc: | |||
| | | | | | | | | |||
| | | | | | | | | | | | | | | | | | | | | | | | | | | |||
| |FRAMES |SUBFRMS|TYP|LEN|DATA..DATA..PAD|FRAMES | ... | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| The contents of the event buffer. This may or may not reside in the | |||
| same block of memory as this header, plugins must not assume either. | |||
| The host guarantees this points to at least capacity bytes of allocated | |||
| memory (though only size bytes of that are valid events). | |||
| */ | |||
| uint8_t* data; | |||
| /** | |||
| The size of this event header in bytes (including everything). | |||
| This is to allow for extending this header in the future without | |||
| breaking binary compatibility. Whenever this header is copied, | |||
| it MUST be done using this field (and NOT the sizeof this struct). | |||
| */ | |||
| uint16_t header_size; | |||
| /** | |||
| The type of the time stamps for events in this buffer. | |||
| As a special exception, '0' always means audio frames and subframes | |||
| (1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate. | |||
| INPUTS: The host must set this field to the numeric ID of some URI | |||
| defining the meaning of the frames/subframes fields of contained events | |||
| (obtained by the LV2 URI Map uri_to_id function with the URI of this | |||
| extension as the 'map' argument, see lv2_uri_map.h). The host must | |||
| never pass a plugin a buffer which uses a stamp type the plugin does not | |||
| 'understand'. The value of this field must never change, except when | |||
| connect_port is called on the input port, at which time the host MUST | |||
| have set the stamp_type field to the value that will be used for all | |||
| subsequent run calls. | |||
| OUTPUTS: The plugin may set this to any value that has been returned | |||
| from uri_to_id with the URI of this extension for a 'map' argument. | |||
| When connected to a buffer with connect_port, output ports MUST set this | |||
| field to the type of time stamp they will be writing. On any call to | |||
| connect_port on an event input port, the plugin may change this field on | |||
| any output port, it is the responsibility of the host to check if any of | |||
| these values have changed and act accordingly. | |||
| */ | |||
| uint16_t stamp_type; | |||
| /** | |||
| The number of events in this buffer. | |||
| INPUTS: The host must set this field to the number of events contained | |||
| in the data buffer before calling run(). The plugin must not change | |||
| this field. | |||
| OUTPUTS: The plugin must set this field to the number of events it has | |||
| written to the buffer before returning from run(). Any initial value | |||
| should be ignored by the plugin. | |||
| */ | |||
| uint32_t event_count; | |||
| /** | |||
| The size of the data buffer in bytes. | |||
| This is set by the host and must not be changed by the plugin. | |||
| The host is allowed to change this between run() calls. | |||
| */ | |||
| uint32_t capacity; | |||
| /** | |||
| The size of the initial portion of the data buffer containing data. | |||
| INPUTS: The host must set this field to the number of bytes used | |||
| by all events it has written to the buffer (including headers) | |||
| before calling the plugin's run(). | |||
| The plugin must not change this field. | |||
| OUTPUTS: The plugin must set this field to the number of bytes | |||
| used by all events it has written to the buffer (including headers) | |||
| before returning from run(). | |||
| Any initial value should be ignored by the plugin. | |||
| */ | |||
| uint32_t size; | |||
| } LV2_Event_Buffer; | |||
| /** | |||
| Opaque pointer to host data. | |||
| */ | |||
| typedef void* LV2_Event_Callback_Data; | |||
| /** | |||
| Non-POD events feature. | |||
| To support this feature the host must pass an LV2_Feature struct to the | |||
| plugin's instantiate method with URI "http://lv2plug.in/ns/ext/event" | |||
| and data pointed to an instance of this struct. Note this feature | |||
| is not mandatory to support the event extension. | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| Opaque pointer to host data. | |||
| The plugin MUST pass this to any call to functions in this struct. | |||
| Otherwise, it must not be interpreted in any way. | |||
| */ | |||
| LV2_Event_Callback_Data callback_data; | |||
| /** | |||
| Take a reference to a non-POD event. | |||
| If a plugin receives an event with type 0, it means the event is a | |||
| pointer to some object in memory and not a flat sequence of bytes | |||
| in the buffer. When receiving a non-POD event, the plugin already | |||
| has an implicit reference to the event. If the event is stored AND | |||
| passed to an output, lv2_event_ref MUST be called on that event. | |||
| If the event is only stored OR passed through, this is not necessary | |||
| (as the plugin already has 1 implicit reference). | |||
| @param event An event received at an input that will not be copied to | |||
| an output or stored in any way. | |||
| @param context The calling context. Like event types, this is a mapped | |||
| URI, see lv2_context.h. Simple plugin with just a run() method should | |||
| pass 0 here (the ID of the 'standard' LV2 run context). The host | |||
| guarantees that this function is realtime safe iff @a context is | |||
| realtime safe. | |||
| PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. | |||
| */ | |||
| uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data, | |||
| LV2_Event* event); | |||
| /** | |||
| Drop a reference to a non-POD event. | |||
| If a plugin receives an event with type 0, it means the event is a | |||
| pointer to some object in memory and not a flat sequence of bytes | |||
| in the buffer. If the plugin does not pass the event through to | |||
| an output or store it internally somehow, it MUST call this function | |||
| on the event (more information on using non-POD events below). | |||
| @param event An event received at an input that will not be copied to an | |||
| output or stored in any way. | |||
| @param context The calling context. Like event types, this is a mapped | |||
| URI, see lv2_context.h. Simple plugin with just a run() method should | |||
| pass 0 here (the ID of the 'standard' LV2 run context). The host | |||
| guarantees that this function is realtime safe iff @a context is | |||
| realtime safe. | |||
| PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. | |||
| */ | |||
| uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data, | |||
| LV2_Event* event); | |||
| } LV2_Event_Feature; | |||
| #endif /* LV2_EVENT_H */ | |||
| @@ -0,0 +1,38 @@ | |||
| /* | |||
| LV2 Instance Access Extension | |||
| Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifndef LV2_INSTANCE_ACCESS_H | |||
| #define LV2_INSTANCE_ACCESS_H | |||
| #define LV2_INSTANCE_ACCESS_URI "http://lv2plug.in/ns/ext/instance-access" | |||
| /** @file | |||
| * C header for the LV2 Instance Access extension | |||
| * <http://lv2plug.in/ns/ext/instance-access>. | |||
| * | |||
| * This extension defines a method for (e.g.) plugin UIs to get a direct | |||
| * handle to an LV2 plugin instance (LV2_Handle), if possible. | |||
| * | |||
| * To support this feature the host must pass an LV2_Feature struct to the | |||
| * UI instantiate method with URI "http://lv2plug.in/ns/ext/instance-access" | |||
| * and data pointed directly to the LV2_Handle of the plugin instance. | |||
| */ | |||
| #endif /* LV2_INSTANCE_ACCESS_H */ | |||
| @@ -0,0 +1,452 @@ | |||
| /* | |||
| LV2 - An audio plugin interface specification. | |||
| Copyright 2006-2012 Steve Harris, David Robillard. | |||
| Based on LADSPA, Copyright 2000-2002 Richard W.E. Furse, | |||
| Paul Barton-Davis, Stefan Westerfeld. | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file lv2.h | |||
| API for the LV2 specification <http://lv2plug.in/ns/lv2core>. | |||
| Revision: 6.5 | |||
| */ | |||
| #ifndef LV2_H_INCLUDED | |||
| #define LV2_H_INCLUDED | |||
| #include <stdint.h> | |||
| #define LV2_CORE_URI "http://lv2plug.in/ns/lv2core" | |||
| #define LV2_CORE_PREFIX LV2_CORE_URI "#" | |||
| #define LV2_CORE__AllpassPlugin LV2_CORE_PREFIX "AllpassPlugin" | |||
| #define LV2_CORE__AmplifierPlugin LV2_CORE_PREFIX "AmplifierPlugin" | |||
| #define LV2_CORE__AnalyserPlugin LV2_CORE_PREFIX "AnalyserPlugin" | |||
| #define LV2_CORE__AudioPort LV2_CORE_PREFIX "AudioPort" | |||
| #define LV2_CORE__BandpassPlugin LV2_CORE_PREFIX "BandpassPlugin" | |||
| #define LV2_CORE__ChorusPlugin LV2_CORE_PREFIX "ChorusPlugin" | |||
| #define LV2_CORE__CombPlugin LV2_CORE_PREFIX "CombPlugin" | |||
| #define LV2_CORE__CompressorPlugin LV2_CORE_PREFIX "CompressorPlugin" | |||
| #define LV2_CORE__ConstantPlugin LV2_CORE_PREFIX "ConstantPlugin" | |||
| #define LV2_CORE__ControlPort LV2_CORE_PREFIX "ControlPort" | |||
| #define LV2_CORE__ConverterPlugin LV2_CORE_PREFIX "ConverterPlugin" | |||
| #define LV2_CORE__DelayPlugin LV2_CORE_PREFIX "DelayPlugin" | |||
| #define LV2_CORE__DistortionPlugin LV2_CORE_PREFIX "DistortionPlugin" | |||
| #define LV2_CORE__DynamicsPlugin LV2_CORE_PREFIX "DynamicsPlugin" | |||
| #define LV2_CORE__EQPlugin LV2_CORE_PREFIX "EQPlugin" | |||
| #define LV2_CORE__ExpanderPlugin LV2_CORE_PREFIX "ExpanderPlugin" | |||
| #define LV2_CORE__ExtensionData LV2_CORE_PREFIX "ExtensionData" | |||
| #define LV2_CORE__Feature LV2_CORE_PREFIX "Feature" | |||
| #define LV2_CORE__FilterPlugin LV2_CORE_PREFIX "FilterPlugin" | |||
| #define LV2_CORE__FlangerPlugin LV2_CORE_PREFIX "FlangerPlugin" | |||
| #define LV2_CORE__FunctionPlugin LV2_CORE_PREFIX "FunctionPlugin" | |||
| #define LV2_CORE__GatePlugin LV2_CORE_PREFIX "GatePlugin" | |||
| #define LV2_CORE__GeneratorPlugin LV2_CORE_PREFIX "GeneratorPlugin" | |||
| #define LV2_CORE__HighpassPlugin LV2_CORE_PREFIX "HighpassPlugin" | |||
| #define LV2_CORE__InputPort LV2_CORE_PREFIX "InputPort" | |||
| #define LV2_CORE__InstrumentPlugin LV2_CORE_PREFIX "InstrumentPlugin" | |||
| #define LV2_CORE__LimiterPlugin LV2_CORE_PREFIX "LimiterPlugin" | |||
| #define LV2_CORE__LowpassPlugin LV2_CORE_PREFIX "LowpassPlugin" | |||
| #define LV2_CORE__MixerPlugin LV2_CORE_PREFIX "MixerPlugin" | |||
| #define LV2_CORE__ModulatorPlugin LV2_CORE_PREFIX "ModulatorPlugin" | |||
| #define LV2_CORE__MultiEQPlugin LV2_CORE_PREFIX "MultiEQPlugin" | |||
| #define LV2_CORE__OscillatorPlugin LV2_CORE_PREFIX "OscillatorPlugin" | |||
| #define LV2_CORE__OutputPort LV2_CORE_PREFIX "OutputPort" | |||
| #define LV2_CORE__ParaEQPlugin LV2_CORE_PREFIX "ParaEQPlugin" | |||
| #define LV2_CORE__PhaserPlugin LV2_CORE_PREFIX "PhaserPlugin" | |||
| #define LV2_CORE__PitchPlugin LV2_CORE_PREFIX "PitchPlugin" | |||
| #define LV2_CORE__Plugin LV2_CORE_PREFIX "Plugin" | |||
| #define LV2_CORE__PluginBase LV2_CORE_PREFIX "PluginBase" | |||
| #define LV2_CORE__Point LV2_CORE_PREFIX "Point" | |||
| #define LV2_CORE__Port LV2_CORE_PREFIX "Port" | |||
| #define LV2_CORE__PortProperty LV2_CORE_PREFIX "PortProperty" | |||
| #define LV2_CORE__Resource LV2_CORE_PREFIX "Resource" | |||
| #define LV2_CORE__ReverbPlugin LV2_CORE_PREFIX "ReverbPlugin" | |||
| #define LV2_CORE__ScalePoint LV2_CORE_PREFIX "ScalePoint" | |||
| #define LV2_CORE__SimulatorPlugin LV2_CORE_PREFIX "SimulatorPlugin" | |||
| #define LV2_CORE__SpatialPlugin LV2_CORE_PREFIX "SpatialPlugin" | |||
| #define LV2_CORE__Specification LV2_CORE_PREFIX "Specification" | |||
| #define LV2_CORE__SpectralPlugin LV2_CORE_PREFIX "SpectralPlugin" | |||
| #define LV2_CORE__UtilityPlugin LV2_CORE_PREFIX "UtilityPlugin" | |||
| #define LV2_CORE__WaveshaperPlugin LV2_CORE_PREFIX "WaveshaperPlugin" | |||
| #define LV2_CORE__appliesTo LV2_CORE_PREFIX "appliesTo" | |||
| #define LV2_CORE__binary LV2_CORE_PREFIX "binary" | |||
| #define LV2_CORE__connectionOptional LV2_CORE_PREFIX "connectionOptional" | |||
| #define LV2_CORE__default LV2_CORE_PREFIX "default" | |||
| #define LV2_CORE__designation LV2_CORE_PREFIX "designation" | |||
| #define LV2_CORE__documentation LV2_CORE_PREFIX "documentation" | |||
| #define LV2_CORE__enumeration LV2_CORE_PREFIX "enumeration" | |||
| #define LV2_CORE__extensionData LV2_CORE_PREFIX "extensionData" | |||
| #define LV2_CORE__freeWheeling LV2_CORE_PREFIX "freeWheeling" | |||
| #define LV2_CORE__hardRTCapable LV2_CORE_PREFIX "hardRTCapable" | |||
| #define LV2_CORE__hasParameter LV2_CORE_PREFIX "hasParameter" | |||
| #define LV2_CORE__inPlaceBroken LV2_CORE_PREFIX "inPlaceBroken" | |||
| #define LV2_CORE__index LV2_CORE_PREFIX "index" | |||
| #define LV2_CORE__integer LV2_CORE_PREFIX "integer" | |||
| #define LV2_CORE__isLive LV2_CORE_PREFIX "isLive" | |||
| #define LV2_CORE__isParameter LV2_CORE_PREFIX "isParameter" | |||
| #define LV2_CORE__latency LV2_CORE_PREFIX "latency" | |||
| #define LV2_CORE__maximum LV2_CORE_PREFIX "maximum" | |||
| #define LV2_CORE__microVersion LV2_CORE_PREFIX "microVersion" | |||
| #define LV2_CORE__minimum LV2_CORE_PREFIX "minimum" | |||
| #define LV2_CORE__minorVersion LV2_CORE_PREFIX "minorVersion" | |||
| #define LV2_CORE__name LV2_CORE_PREFIX "name" | |||
| #define LV2_CORE__optionalFeature LV2_CORE_PREFIX "optionalFeature" | |||
| #define LV2_CORE__port LV2_CORE_PREFIX "port" | |||
| #define LV2_CORE__portProperty LV2_CORE_PREFIX "portProperty" | |||
| #define LV2_CORE__reportsLatency LV2_CORE_PREFIX "reportsLatency" | |||
| #define LV2_CORE__requiredFeature LV2_CORE_PREFIX "requiredFeature" | |||
| #define LV2_CORE__sampleRate LV2_CORE_PREFIX "sampleRate" | |||
| #define LV2_CORE__scalePoint LV2_CORE_PREFIX "scalePoint" | |||
| #define LV2_CORE__symbol LV2_CORE_PREFIX "symbol" | |||
| #define LV2_CORE__toggled LV2_CORE_PREFIX "toggled" | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #endif | |||
| /** | |||
| Plugin Instance Handle. | |||
| This is a handle for one particular instance of a plugin. It is valid to | |||
| compare to NULL (or 0 for C++) but otherwise the host MUST NOT attempt to | |||
| interpret it. | |||
| */ | |||
| typedef void * LV2_Handle; | |||
| /** | |||
| Feature. | |||
| Features allow hosts to make additional functionality available to plugins | |||
| without requiring modification to the LV2 API. Extensions may define new | |||
| features and specify the @ref URI and @ref data to be used if necessary. | |||
| Some features, such as lv2:isLive, do not require the host to pass data. | |||
| */ | |||
| typedef struct _LV2_Feature { | |||
| /** | |||
| A globally unique, case-sensitive identifier (URI) for this feature. | |||
| This MUST be a valid URI string as defined by RFC 3986. | |||
| */ | |||
| const char * URI; | |||
| /** | |||
| Pointer to arbitrary data. | |||
| The format of this data is defined by the extension which describes the | |||
| feature with the given @ref URI. | |||
| */ | |||
| void * data; | |||
| } LV2_Feature; | |||
| /** | |||
| Plugin Descriptor. | |||
| This structure provides the core functions necessary to instantiate and use | |||
| a plugin. | |||
| */ | |||
| typedef struct _LV2_Descriptor { | |||
| /** | |||
| A globally unique, case-sensitive identifier for this plugin. | |||
| This MUST be a valid URI string as defined by RFC 3986. All plugins with | |||
| the same URI MUST be compatible to some degree, see | |||
| http://lv2plug.in/ns/lv2core for details. | |||
| */ | |||
| const char * URI; | |||
| /** | |||
| Instantiate the plugin. | |||
| Note that instance initialisation should generally occur in activate() | |||
| rather than here. If a host calls instantiate(), it MUST call cleanup() | |||
| at some point in the future. | |||
| @param descriptor Descriptor of the plugin to instantiate. | |||
| @param sample_rate Sample rate, in Hz, for the new plugin instance. | |||
| @param bundle_path Path to the LV2 bundle which contains this plugin | |||
| binary. It MUST include the trailing directory separator (e.g. '/') so | |||
| that simply appending a filename will yield the path to that file in the | |||
| bundle. | |||
| @param features A NULL terminated array of LV2_Feature structs which | |||
| represent the features the host supports. Plugins may refuse to | |||
| instantiate if required features are not found here. However, hosts MUST | |||
| NOT use this as a discovery mechanism: instead, use the RDF data to | |||
| determine which features are required and do not attempt to instantiate | |||
| unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host | |||
| that supports no features MUST pass a single element array containing | |||
| NULL. | |||
| @return A handle for the new plugin instance, or NULL if instantiation | |||
| has failed. | |||
| */ | |||
| LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor, | |||
| double sample_rate, | |||
| const char * bundle_path, | |||
| const LV2_Feature *const * features); | |||
| /** | |||
| Connect a port on a plugin instance to a memory location. | |||
| Plugin writers should be aware that the host may elect to use the same | |||
| buffer for more than one port and even use the same buffer for both | |||
| input and output (see lv2:inPlaceBroken in lv2.ttl). | |||
| If the plugin has the feature lv2:hardRTCapable then there are various | |||
| things that the plugin MUST NOT do within the connect_port() function; | |||
| see lv2core.ttl for details. | |||
| connect_port() MUST be called at least once for each port before run() | |||
| is called, unless that port is lv2:connectionOptional. The plugin must | |||
| pay careful attention to the block size passed to run() since the block | |||
| allocated may only just be large enough to contain the data, and is not | |||
| guaranteed to remain constant between run() calls. | |||
| connect_port() may be called more than once for a plugin instance to | |||
| allow the host to change the buffers that the plugin is reading or | |||
| writing. These calls may be made before or after activate() or | |||
| deactivate() calls. | |||
| @param instance Plugin instance containing the port. | |||
| @param port Index of the port to connect. The host MUST NOT try to | |||
| connect a port index that is not defined in the plugin's RDF data. If | |||
| it does, the plugin's behaviour is undefined (a crash is likely). | |||
| @param data_location Pointer to data of the type defined by the port | |||
| type in the plugin's RDF data (e.g. an array of float for an | |||
| lv2:AudioPort). This pointer must be stored by the plugin instance and | |||
| used to read/write data when run() is called. Data present at the time | |||
| of the connect_port() call MUST NOT be considered meaningful. | |||
| */ | |||
| void (*connect_port)(LV2_Handle instance, | |||
| uint32_t port, | |||
| void * data_location); | |||
| /** | |||
| Initialise a plugin instance and activate it for use. | |||
| This is separated from instantiate() to aid real-time support and so | |||
| that hosts can reinitialise a plugin instance by calling deactivate() | |||
| and then activate(). In this case the plugin instance MUST reset all | |||
| state information dependent on the history of the plugin instance except | |||
| for any data locations provided by connect_port(). If there is nothing | |||
| for activate() to do then this field may be NULL. | |||
| When present, hosts MUST call this function once before run() is called | |||
| for the first time. This call SHOULD be made as close to the run() call | |||
| as possible and indicates to real-time plugins that they are now live, | |||
| however plugins MUST NOT rely on a prompt call to run() after | |||
| activate(). | |||
| The host MUST NOT call activate() again until deactivate() has been | |||
| called first. If a host calls activate(), it MUST call deactivate() at | |||
| some point in the future. Note that connect_port() may be called before | |||
| or after activate(). | |||
| */ | |||
| void (*activate)(LV2_Handle instance); | |||
| /** | |||
| Run a plugin instance for a block. | |||
| Note that if an activate() function exists then it must be called before | |||
| run(). If deactivate() is called for a plugin instance then run() may | |||
| not be called until activate() has been called again. | |||
| If the plugin has the feature lv2:hardRTCapable then there are various | |||
| things that the plugin MUST NOT do within the run() function (see | |||
| lv2core.ttl for details). | |||
| As a special case, when @c sample_count == 0, the plugin should update | |||
| any output ports that represent a single instant in time (e.g. control | |||
| ports, but not audio ports). This is particularly useful for latent | |||
| plugins, which should update their latency output port so hosts can | |||
| pre-roll plugins to compute latency. Plugins MUST NOT crash when | |||
| @c sample_count == 0. | |||
| @param instance Instance to be run. | |||
| @param sample_count The block size (in samples) for which the plugin | |||
| instance must run. | |||
| */ | |||
| void (*run)(LV2_Handle instance, | |||
| uint32_t sample_count); | |||
| /** | |||
| Deactivate a plugin instance (counterpart to activate()). | |||
| Hosts MUST deactivate all activated instances after they have been run() | |||
| for the last time. This call SHOULD be made as close to the last run() | |||
| call as possible and indicates to real-time plugins that they are no | |||
| longer live, however plugins MUST NOT rely on prompt deactivation. If | |||
| there is nothing for deactivate() to do then this field may be NULL | |||
| Deactivation is not similar to pausing since the plugin instance will be | |||
| reinitialised by activate(). However, deactivate() itself MUST NOT fully | |||
| reset plugin state. For example, the host may deactivate a plugin, then | |||
| store its state (using some extension to do so). | |||
| Hosts MUST NOT call deactivate() unless activate() was previously | |||
| called. Note that connect_port() may be called before or after | |||
| deactivate(). | |||
| */ | |||
| void (*deactivate)(LV2_Handle instance); | |||
| /** | |||
| Clean up a plugin instance (counterpart to instantiate()). | |||
| Once an instance of a plugin has been finished with it must be deleted | |||
| using this function. The instance handle passed ceases to be valid after | |||
| this call. | |||
| If activate() was called for a plugin instance then a corresponding call | |||
| to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT | |||
| call cleanup() unless instantiate() was previously called. | |||
| */ | |||
| void (*cleanup)(LV2_Handle instance); | |||
| /** | |||
| Return additional plugin data defined by some extenion. | |||
| A typical use of this facility is to return a struct containing function | |||
| pointers to extend the LV2_Descriptor API. | |||
| The actual type and meaning of the returned object MUST be specified | |||
| precisely by the extension. This function MUST return NULL for any | |||
| unsupported URI. If a plugin does not support any extension data, this | |||
| field may be NULL. | |||
| The host is never responsible for freeing the returned value. | |||
| */ | |||
| const void * (*extension_data)(const char * uri); | |||
| } LV2_Descriptor; | |||
| /** | |||
| Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded | |||
| by the host as a symbol from the dynamic library. | |||
| */ | |||
| #ifdef _WIN32 | |||
| # define LV2_SYMBOL_EXPORT __declspec(dllexport) | |||
| #else | |||
| # define LV2_SYMBOL_EXPORT | |||
| #endif | |||
| /** | |||
| Prototype for plugin accessor function. | |||
| This is part of the old discovery API, which has been replaced due to being | |||
| inadequate for some plugins. It is limited because the bundle path is not | |||
| available during discovery, and it relies on non-portable shared library | |||
| constructors/destructors. However, this API is still supported and plugins | |||
| are not required to migrate. | |||
| Plugins are discovered by hosts using RDF data (not by loading libraries). | |||
| See http://lv2plug.in for details on the discovery process, though most | |||
| hosts should use an existing library to implement this functionality. | |||
| A plugin library MUST include a function called "lv2_descriptor" with this | |||
| prototype. This function MUST have C-style linkage (if you are using C++ | |||
| this is taken care of by the 'extern "C"' clause at the top of this file). | |||
| When it is time to load a plugin (designated by its URI), the host loads the | |||
| plugin's library, gets the lv2_descriptor() function from it, and uses this | |||
| function to find the LV2_Descriptor for the desired plugin. Plugins are | |||
| accessed by index using values from 0 upwards. This function MUST return | |||
| NULL for out of range indices, so the host can enumerate plugins by | |||
| increasing @c index until NULL is returned. | |||
| Note that @c index has no meaning, hosts MUST NOT depend on it remaining | |||
| consistent between loads of the plugin library. | |||
| */ | |||
| LV2_SYMBOL_EXPORT | |||
| const LV2_Descriptor * lv2_descriptor(uint32_t index); | |||
| /** | |||
| Type of the lv2_descriptor() function in a library (old discovery API). | |||
| */ | |||
| typedef const LV2_Descriptor * | |||
| (*LV2_Descriptor_Function)(uint32_t index); | |||
| /** | |||
| Handle for a library descriptor. | |||
| */ | |||
| typedef void* LV2_Lib_Handle; | |||
| /** | |||
| Descriptor for a plugin library. | |||
| To access a plugin library, the host creates an LV2_Lib_Descriptor via the | |||
| lv2_lib_descriptor() function in the shared object. | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| Opaque library data which must be passed as the first parameter to all | |||
| the methods of this struct. | |||
| */ | |||
| LV2_Lib_Handle handle; | |||
| /** | |||
| The total size of this struct. This allows for this struct to be | |||
| expanded in the future if necessary. This MUST be set by the library to | |||
| sizeof(LV2_Lib_Descriptor). The host MUST NOT access any fields of this | |||
| struct beyond get_plugin() unless this field indicates they are present. | |||
| */ | |||
| uint32_t size; | |||
| /** | |||
| Destroy this library descriptor and free all related resources. | |||
| */ | |||
| void (*cleanup)(LV2_Lib_Handle handle); | |||
| /** | |||
| Plugin accessor. | |||
| Plugins are accessed by index using values from 0 upwards. Out of range | |||
| indices MUST result in this function returning NULL, so the host can | |||
| enumerate plugins by increasing @a index until NULL is returned. | |||
| */ | |||
| const LV2_Descriptor * (*get_plugin)(LV2_Lib_Handle handle, | |||
| uint32_t index); | |||
| } LV2_Lib_Descriptor; | |||
| /** | |||
| Prototype for library accessor function. | |||
| This is the entry point for a plugin library. Hosts load this symbol from | |||
| the library and call this function to obtain a library descriptor which can | |||
| be used to access all the contained plugins. The returned object must not | |||
| be destroyed (using LV2_Lib_Descriptor::cleanup()) until all plugins loaded | |||
| from that library have been destroyed. | |||
| */ | |||
| const LV2_Lib_Descriptor * | |||
| lv2_lib_descriptor(const char * bundle_path, | |||
| const LV2_Feature *const * features); | |||
| /** | |||
| Type of the lv2_lib_descriptor() function in an LV2 library. | |||
| */ | |||
| typedef const LV2_Lib_Descriptor * | |||
| (*LV2_Lib_Descriptor_Function)(const char * bundle_path, | |||
| const LV2_Feature *const * features); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* LV2_H_INCLUDED */ | |||
| @@ -0,0 +1,67 @@ | |||
| /* | |||
| Copyright 2012 David Robillard <http://drobilla.net> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file midi.h | |||
| C definitions for the LV2 MIDI extension <http://lv2plug.in/ns/ext/midi>. | |||
| */ | |||
| #ifndef LV2_MIDI_H | |||
| #define LV2_MIDI_H | |||
| #define LV2_MIDI_URI "http://lv2plug.in/ns/ext/midi" | |||
| #define LV2_MIDI__ActiveSense LV2_MIDI_URI "#ActiveSense" | |||
| #define LV2_MIDI__Aftertouch LV2_MIDI_URI "#Aftertouch" | |||
| #define LV2_MIDI__Bender LV2_MIDI_URI "#Bender" | |||
| #define LV2_MIDI__ChannelPressure LV2_MIDI_URI "#ChannelPressure" | |||
| #define LV2_MIDI__Chunk LV2_MIDI_URI "#Chunk" | |||
| #define LV2_MIDI__Clock LV2_MIDI_URI "#Clock" | |||
| #define LV2_MIDI__Continue LV2_MIDI_URI "#Continue" | |||
| #define LV2_MIDI__Controller LV2_MIDI_URI "#Controller" | |||
| #define LV2_MIDI__MidiEvent LV2_MIDI_URI "#MidiEvent" | |||
| #define LV2_MIDI__NoteOff LV2_MIDI_URI "#NoteOff" | |||
| #define LV2_MIDI__NoteOn LV2_MIDI_URI "#NoteOn" | |||
| #define LV2_MIDI__ProgramChange LV2_MIDI_URI "#ProgramChange" | |||
| #define LV2_MIDI__QuarterFrame LV2_MIDI_URI "#QuarterFrame" | |||
| #define LV2_MIDI__Reset LV2_MIDI_URI "#Reset" | |||
| #define LV2_MIDI__SongPosition LV2_MIDI_URI "#SongPosition" | |||
| #define LV2_MIDI__SongSelect LV2_MIDI_URI "#SongSelect" | |||
| #define LV2_MIDI__Start LV2_MIDI_URI "#Start" | |||
| #define LV2_MIDI__Stop LV2_MIDI_URI "#Stop" | |||
| #define LV2_MIDI__SystemCommon LV2_MIDI_URI "#SystemCommon" | |||
| #define LV2_MIDI__SystemExclusive LV2_MIDI_URI "#SystemExclusive" | |||
| #define LV2_MIDI__SystemMessage LV2_MIDI_URI "#SystemMessage" | |||
| #define LV2_MIDI__SystemRealtime LV2_MIDI_URI "#SystemRealtime" | |||
| #define LV2_MIDI__Tick LV2_MIDI_URI "#Tick" | |||
| #define LV2_MIDI__TuneRequest LV2_MIDI_URI "#TuneRequest" | |||
| #define LV2_MIDI__VoiceMessage LV2_MIDI_URI "#VoiceMessage" | |||
| #define LV2_MIDI__benderValue LV2_MIDI_URI "#benderValue" | |||
| #define LV2_MIDI__byteNumber LV2_MIDI_URI "#byteNumber" | |||
| #define LV2_MIDI__chunk LV2_MIDI_URI "#chunk" | |||
| #define LV2_MIDI__controllerNumber LV2_MIDI_URI "#controllerNumber" | |||
| #define LV2_MIDI__controllerValue LV2_MIDI_URI "#controllerValue" | |||
| #define LV2_MIDI__noteNumber LV2_MIDI_URI "#noteNumber" | |||
| #define LV2_MIDI__pressure LV2_MIDI_URI "#pressure" | |||
| #define LV2_MIDI__programNumber LV2_MIDI_URI "#programNumber" | |||
| #define LV2_MIDI__property LV2_MIDI_URI "#property" | |||
| #define LV2_MIDI__songNumber LV2_MIDI_URI "#songNumber" | |||
| #define LV2_MIDI__songPosition LV2_MIDI_URI "#songPosition" | |||
| #define LV2_MIDI__status LV2_MIDI_URI "#status" | |||
| #define LV2_MIDI__statusMask LV2_MIDI_URI "#statusMask" | |||
| #define LV2_MIDI__velocity LV2_MIDI_URI "#velocity" | |||
| #endif /* LV2_MIDI_H */ | |||
| @@ -0,0 +1,357 @@ | |||
| /* | |||
| Copyright 2010-2012 David Robillard <http://drobilla.net> | |||
| Copyright 2010 Leonard Ritter <paniq@paniq.org> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file state.h | |||
| C API for the LV2 State extension <http://lv2plug.in/ns/ext/state>. | |||
| */ | |||
| #ifndef LV2_STATE_H | |||
| #define LV2_STATE_H | |||
| #include <stddef.h> | |||
| #include <stdint.h> | |||
| #include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
| #define LV2_STATE_URI "http://lv2plug.in/ns/ext/state" | |||
| #define LV2_STATE_PREFIX LV2_STATE_URI "#" | |||
| #define LV2_STATE__Interface LV2_STATE_PREFIX "Interface" | |||
| #define LV2_STATE__State LV2_STATE_PREFIX "State" | |||
| #define LV2_STATE__makePath LV2_STATE_PREFIX "makePath" | |||
| #define LV2_STATE__mapPath LV2_STATE_PREFIX "mapPath" | |||
| #define LV2_STATE__state LV2_STATE_PREFIX "state" | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #else | |||
| # include <stdbool.h> | |||
| #endif | |||
| typedef void* LV2_State_Handle; | |||
| typedef void* LV2_State_Map_Path_Handle; | |||
| typedef void* LV2_State_Make_Path_Handle; | |||
| /** | |||
| Flags describing value characteristics. | |||
| These flags are used along with the value's type URI to determine how to | |||
| (de-)serialise the value data, or whether it is even possible to do so. | |||
| */ | |||
| typedef enum { | |||
| /** | |||
| Plain Old Data. | |||
| Values with this flag contain no pointers or references to other areas | |||
| of memory. It is safe to copy POD values with a simple memcpy and store | |||
| them for the duration of the process. A POD value is not necessarily | |||
| safe to trasmit between processes or machines (e.g. filenames are POD), | |||
| see LV2_STATE_IS_PORTABLE for details. | |||
| Implementations MUST NOT attempt to copy or serialise a non-POD value if | |||
| they do not understand its type (and thus know how to correctly do so). | |||
| */ | |||
| LV2_STATE_IS_POD = 1, | |||
| /** | |||
| Portable (architecture independent) data. | |||
| Values with this flag are in a format that is usable on any | |||
| architecture. A portable value saved on one machine can be restored on | |||
| another machine regardless of architecture. The format of portable | |||
| values MUST NOT depend on architecture-specific properties like | |||
| endianness or alignment. Portable values MUST NOT contain filenames. | |||
| */ | |||
| LV2_STATE_IS_PORTABLE = 1 << 1, | |||
| /** | |||
| Native data. | |||
| This flag is used by the host to indicate that the saved data is only | |||
| going to be used locally in the currently running process (e.g. for | |||
| instance duplication or snapshots), so the plugin should use the most | |||
| efficient representation possible and not worry about serialisation | |||
| and portability. | |||
| */ | |||
| LV2_STATE_IS_NATIVE = 1 << 2 | |||
| } LV2_State_Flags; | |||
| /** A status code for state functions. */ | |||
| typedef enum { | |||
| LV2_STATE_SUCCESS = 0, /**< Completed successfully. */ | |||
| LV2_STATE_ERR_UNKNOWN = 1, /**< Unknown error. */ | |||
| LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ | |||
| LV2_STATE_ERR_BAD_FLAGS = 3 /**< Failed due to unsupported flags. */ | |||
| } LV2_State_Status; | |||
| /** | |||
| A host-provided function to store a property. | |||
| @param handle Must be the handle passed to LV2_State_Interface.save(). | |||
| @param key The key to store @p value under (URID). | |||
| @param value Pointer to the value to be stored. | |||
| @param size The size of @p value in bytes. | |||
| @param type The type of @p value (URID). | |||
| @param flags LV2_State_Flags for @p value. | |||
| @return 0 on success, otherwise a non-zero error code. | |||
| The host passes a callback of this type to LV2_State_Interface.save(). This | |||
| callback is called repeatedly by the plugin to store all the properties that | |||
| describe its current state. | |||
| DO NOT INVENT NONSENSE URI SCHEMES FOR THE KEY. Best is to use keys from | |||
| existing vocabularies. If nothing appropriate is available, use http URIs | |||
| that point to somewhere you can host documents so documentation can be made | |||
| resolvable (e.g. a child of the plugin or project URI). If this is not | |||
| possible, invent a URN scheme, e.g. urn:myproj:whatever. The plugin MUST | |||
| NOT pass an invalid URI key. | |||
| The host MAY fail to store a property for whatever reason, but SHOULD | |||
| store any property that is LV2_STATE_IS_POD and LV2_STATE_IS_PORTABLE. | |||
| Implementations SHOULD use the types from the LV2 Atom extension | |||
| (http://lv2plug.in/ns/ext/atom) wherever possible. The plugin SHOULD | |||
| attempt to fall-back and avoid the error if possible. | |||
| Note that @p size MUST be > 0, and @p value MUST point to a valid region of | |||
| memory @p size bytes long (this is required to make restore unambiguous). | |||
| The plugin MUST NOT attempt to use this function outside of the | |||
| LV2_State_Interface.restore() context. | |||
| */ | |||
| typedef LV2_State_Status (*LV2_State_Store_Function)( | |||
| LV2_State_Handle handle, | |||
| uint32_t key, | |||
| const void* value, | |||
| size_t size, | |||
| uint32_t type, | |||
| uint32_t flags); | |||
| /** | |||
| A host-provided function to retrieve a property. | |||
| @param handle Must be the handle passed to LV2_State_Interface.restore(). | |||
| @param key The key of the property to retrieve (URID). | |||
| @param size (Output) If non-NULL, set to the size of the restored value. | |||
| @param type (Output) If non-NULL, set to the type of the restored value. | |||
| @param flags (Output) If non-NULL, set to the flags for the restored value. | |||
| @return A pointer to the restored value (object), or NULL if no value | |||
| has been stored under @p key. | |||
| A callback of this type is passed by the host to | |||
| LV2_State_Interface.restore(). This callback is called repeatedly by the | |||
| plugin to retrieve any properties it requires to restore its state. | |||
| The returned value MUST remain valid until LV2_State_Interface.restore() | |||
| returns. The plugin MUST NOT attempt to use this function, or any value | |||
| returned from it, outside of the LV2_State_Interface.restore() context. | |||
| */ | |||
| typedef const void* (*LV2_State_Retrieve_Function)( | |||
| LV2_State_Handle handle, | |||
| uint32_t key, | |||
| size_t* size, | |||
| uint32_t* type, | |||
| uint32_t* flags); | |||
| /** | |||
| LV2 Plugin State Interface. | |||
| When the plugin's extension_data is called with argument | |||
| LV2_STATE__Interface, the plugin MUST return an LV2_State_Interface | |||
| structure, which remains valid for the lifetime of the plugin. | |||
| The host can use the contained function pointers to save and restore the | |||
| state of a plugin instance at any time, provided the threading restrictions | |||
| of the functions are met. | |||
| Stored data is only guaranteed to be compatible between instances of plugins | |||
| with the same URI (i.e. if a change to a plugin would cause a fatal error | |||
| when restoring state saved by a previous version of that plugin, the plugin | |||
| URI MUST change just as it must when ports change incompatibly). Plugin | |||
| authors should consider this possibility, and always store sensible data | |||
| with meaningful types to avoid such problems in the future. | |||
| */ | |||
| typedef struct _LV2_State_Interface { | |||
| /** | |||
| Save plugin state using a host-provided @p store callback. | |||
| @param instance The instance handle of the plugin. | |||
| @param store The host-provided store callback. | |||
| @param handle An opaque pointer to host data which MUST be passed as the | |||
| handle parameter to @p store if it is called. | |||
| @param flags Flags describing desired properties of this save. These | |||
| flags may be used to determine the most appropriate values to store. | |||
| @param features Extensible parameter for passing any additional | |||
| features to be used for this save. | |||
| The plugin is expected to store everything necessary to completely | |||
| restore its state later. Plugins SHOULD store simple POD data whenever | |||
| possible, and consider the possibility of state being restored much | |||
| later on a different machine. | |||
| The @p handle pointer and @p store function MUST NOT be used | |||
| beyond the scope of save(). | |||
| This function has its own special threading class: it may not be called | |||
| concurrently with any "Instantiation" function, but it may be called | |||
| concurrently with functions in any other class, unless the definition of | |||
| that class prohibits it (e.g. it may not be called concurrently with a | |||
| "Discovery" function, but it may be called concurrently with an "Audio" | |||
| function. The plugin is responsible for any locking or lock-free | |||
| techniques necessary to make this possible. | |||
| Note that in the simple case where state is only modified by restore(), | |||
| there are no synchronization issues since save() is never called | |||
| concurrently with restore() (though run() may read it during a save). | |||
| Plugins that dynamically modify state while running, however, must take | |||
| care to do so in such a way that a concurrent call to save() will save a | |||
| consistent representation of plugin state for a single instant in time. | |||
| */ | |||
| void (*save)(LV2_Handle instance, | |||
| LV2_State_Store_Function store, | |||
| LV2_State_Handle handle, | |||
| uint32_t flags, | |||
| const LV2_Feature *const * features); | |||
| /** | |||
| Restore plugin state using a host-provided @p retrieve callback. | |||
| @param instance The instance handle of the plugin. | |||
| @param retrieve The host-provided retrieve callback. | |||
| @param handle An opaque pointer to host data which MUST be passed as the | |||
| handle parameter to @p retrieve if it is called. | |||
| @param flags Currently unused. | |||
| @param features Extensible parameter for passing any additional | |||
| features to be used for this restore. | |||
| The plugin MAY assume a restored value was set by a previous call to | |||
| LV2_State_Interface.save() by a plugin with the same URI. | |||
| The plugin MUST gracefully fall back to a default value when a value can | |||
| not be retrieved. This allows the host to reset the plugin state with | |||
| an empty map. | |||
| The @p handle pointer and @p store function MUST NOT be used | |||
| beyond the scope of restore(). | |||
| This function is in the "Instantiation" threading class as defined by | |||
| LV2. This means it MUST NOT be called concurrently with any other | |||
| function on the same plugin instance. | |||
| */ | |||
| void (*restore)(LV2_Handle instance, | |||
| LV2_State_Retrieve_Function retrieve, | |||
| LV2_State_Handle handle, | |||
| uint32_t flags, | |||
| const LV2_Feature *const * features); | |||
| } LV2_State_Interface; | |||
| /** | |||
| Feature data for state:mapPath (LV2_STATE__mapPath). | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| Opaque host data. | |||
| */ | |||
| LV2_State_Map_Path_Handle handle; | |||
| /** | |||
| Map an absolute path to an abstract path for use in plugin state. | |||
| @param handle MUST be the @p handle member of this struct. | |||
| @param absolute_path The absolute path of a file. | |||
| @return An abstract path suitable for use in plugin state. | |||
| The plugin MUST use this function to map any paths that will be stored | |||
| in plugin state. The returned value is an abstract path which MAY not | |||
| be an actual file system path; @ref absolute_path() MUST be used to map | |||
| it to an actual path in order to use the file. | |||
| Plugins MUST NOT make any assumptions about abstract paths except that | |||
| they can be mapped back to the absolute path of the "same" file (though | |||
| not necessarily the same original path) using @ref absolute_path(). | |||
| This function may only be called within the context of | |||
| LV2_State_Interface methods. The caller is responsible for freeing the | |||
| returned value with free(). | |||
| */ | |||
| char* (*abstract_path)(LV2_State_Map_Path_Handle handle, | |||
| const char* absolute_path); | |||
| /** | |||
| Map an abstract path from plugin state to an absolute path. | |||
| @param handle MUST be the @p handle member of this struct. | |||
| @param abstract_path An abstract path (e.g. a path from plugin state). | |||
| @return An absolute file system path. | |||
| The plugin MUST use this function in order to actually open or otherwise | |||
| use any paths loaded from plugin state. | |||
| This function may only be called within the context of | |||
| LV2_State_Interface methods. The caller is responsible for freeing the | |||
| returned value with free(). | |||
| */ | |||
| char* (*absolute_path)(LV2_State_Map_Path_Handle handle, | |||
| const char* abstract_path); | |||
| } LV2_State_Map_Path; | |||
| /** | |||
| Feature data for state:makePath (@ref LV2_STATE__makePath). | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| Opaque host data. | |||
| */ | |||
| LV2_State_Make_Path_Handle handle; | |||
| /** | |||
| Return a path the plugin may use to create a new file. | |||
| @param handle MUST be the @p handle member of this struct. | |||
| @param path The path of the new file within a namespace unique to this | |||
| plugin instance. | |||
| @return The absolute path to use for the new file. | |||
| This function can be used by plugins to create files and directories, | |||
| either at state saving time (if this feature is passed to | |||
| LV2_State_Interface.save()) or any time (if this feature is passed to | |||
| LV2_Descriptor.instantiate()). | |||
| The host MUST do whatever is necessary for the plugin to be able to | |||
| create a file at the returned path (e.g. using fopen), including | |||
| creating any leading directories. | |||
| If this function is passed to LV2_Descriptor.instantiate(), it may be | |||
| called from any non-realtime context. If it is passed to | |||
| LV2_State_Interface.save(), it may only be called within the dynamic | |||
| scope of that function call. | |||
| The caller is responsible for freeing the returned value with free(). | |||
| */ | |||
| char* (*path)(LV2_State_Make_Path_Handle handle, | |||
| const char* path); | |||
| } LV2_State_Make_Path; | |||
| #ifdef __cplusplus | |||
| } /* extern "C" */ | |||
| #endif | |||
| #endif /* LV2_STATE_H */ | |||
| @@ -0,0 +1,399 @@ | |||
| /* | |||
| LV2 UI Extension | |||
| Copyright 2009-2012 David Robillard <d@drobilla.net> | |||
| Copyright 2006-2011 Lars Luthman <lars.luthman@gmail.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file ui.h | |||
| C header for the LV2 UI extension <http://lv2plug.in/ns/extensions/ui>. | |||
| */ | |||
| #ifndef LV2_UI_H | |||
| #define LV2_UI_H | |||
| #include <stdint.h> | |||
| #include "lv2.h" | |||
| #define LV2_UI_URI "http://lv2plug.in/ns/extensions/ui" | |||
| #define LV2_UI_PREFIX LV2_UI_URI "#" | |||
| #define LV2_UI__GtkUI LV2_UI_PREFIX "GtkUI" | |||
| #define LV2_UI__PortNotification LV2_UI_PREFIX "PortNotification" | |||
| #define LV2_UI__Qt4UI LV2_UI_PREFIX "Qt4UI" | |||
| #define LV2_UI__UI LV2_UI_PREFIX "UI" | |||
| #define LV2_UI__X11UI LV2_UI_PREFIX "X11UI" | |||
| #define LV2_UI__fixedSize LV2_UI_PREFIX "fixedSize" | |||
| #define LV2_UI__noUserResize LV2_UI_PREFIX "noUserResize" | |||
| #define LV2_UI__notifyType LV2_UI_PREFIX "notifyType" | |||
| #define LV2_UI__parent LV2_UI_PREFIX "parent" | |||
| #define LV2_UI__plugin LV2_UI_PREFIX "plugin" | |||
| #define LV2_UI__portIndex LV2_UI_PREFIX "portIndex" | |||
| #define LV2_UI__portMap LV2_UI_PREFIX "portMap" | |||
| #define LV2_UI__portNotification LV2_UI_PREFIX "portNotification" | |||
| #define LV2_UI__resize LV2_UI_PREFIX "resize" | |||
| #define LV2_UI__touch LV2_UI_PREFIX "touch" | |||
| /** | |||
| The index returned by LV2_UI_Port_Port::port_index() for unknown ports. | |||
| */ | |||
| #define LV2UI_INVALID_PORT_INDEX ((uint32_t)-1) | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| #else | |||
| # include <stdbool.h> | |||
| #endif | |||
| /** | |||
| A pointer to some widget or other type of UI handle. | |||
| The actual type is defined by the type of the UI. | |||
| */ | |||
| typedef void* LV2UI_Widget; | |||
| /** | |||
| A pointer to an instance of a UI. | |||
| It is valid to compare this to NULL (0 for C++) but otherwise the host MUST | |||
| not attempt to interpret it. The UI plugin may use it to reference internal | |||
| instance data. | |||
| */ | |||
| typedef void* LV2UI_Handle; | |||
| /** | |||
| A pointer to a controller provided by the host. | |||
| It is valid to compare this to NULL (0 for C++) but otherwise the UI plugin | |||
| MUST NOT attempt to interpret it. The host may use it to reference internal | |||
| instance data. | |||
| */ | |||
| typedef void* LV2UI_Controller; | |||
| /** | |||
| A pointer to opaque data for a feature. | |||
| */ | |||
| typedef void* LV2UI_Feature_Handle; | |||
| /** | |||
| The type of the host-provided function that the UI can use to | |||
| send data to a plugin's input ports. | |||
| The @c buffer parameter must point to a block of data, @c buffer_size bytes | |||
| large. The format of this data and how the host should use it is defined by | |||
| the @c port_protocol. This buffer is owned by the UI and is only valid for | |||
| the duration of this call. | |||
| The @c port_protocol parameter should either be 0 or the URID for a | |||
| ui:PortProtocol. If it is 0, the protocol is implicitly ui:floatProtocol, | |||
| the port must be an lv2:ControlPort input, @c buffer must point to a single | |||
| float value, and @c buffer_size must be sizeof(float). | |||
| The UI SHOULD NOT use a PortProtocol not supported by the host (i.e. one not | |||
| passed by the host as a feature), but the host MUST gracefully ignore any | |||
| port_protocol it does not understand. | |||
| */ | |||
| typedef void (*LV2UI_Write_Function)(LV2UI_Controller controller, | |||
| uint32_t port_index, | |||
| uint32_t buffer_size, | |||
| uint32_t port_protocol, | |||
| const void* buffer); | |||
| /** | |||
| The implementation of a UI. | |||
| A pointer to an object of this type is returned by the lv2ui_descriptor() | |||
| function. | |||
| */ | |||
| typedef struct _LV2UI_Descriptor { | |||
| /** | |||
| The URI for this UI (not for the plugin it controls). | |||
| */ | |||
| const char* URI; | |||
| /** | |||
| Create a new UI object and return a handle to it. This function works | |||
| similarly to the instantiate() member in LV2_Descriptor. | |||
| @param descriptor The descriptor for the UI that you want to instantiate. | |||
| @param plugin_uri The URI of the plugin that this UI will control. | |||
| @param bundle_path The path to the bundle containing the RDF data file | |||
| that references this shared object file, including the trailing '/'. | |||
| @param write_function A function provided by the host that the UI can use | |||
| to send data to the plugin's input ports. | |||
| @param controller A handle for the plugin instance that should be passed | |||
| as the first parameter of @c write_function. | |||
| @param widget A pointer to an LV2UI_Widget. The UI will write a widget | |||
| pointer to this location (what type of widget depends on the RDF class of | |||
| the UI) that will be the main UI widget. | |||
| @param features An array of LV2_Feature pointers. The host must pass all | |||
| feature URIs that it and the UI supports and any additional data, just | |||
| like in the LV2 plugin instantiate() function. Note that UI features and | |||
| plugin features are NOT necessarily the same, they just share the same | |||
| data structure - this will probably not be the same array as the one the | |||
| plugin host passes to a plugin. | |||
| */ | |||
| LV2UI_Handle (*instantiate)(const struct _LV2UI_Descriptor* descriptor, | |||
| const char* plugin_uri, | |||
| const char* bundle_path, | |||
| LV2UI_Write_Function write_function, | |||
| LV2UI_Controller controller, | |||
| LV2UI_Widget* widget, | |||
| const LV2_Feature* const* features); | |||
| /** | |||
| Destroy the UI object and the associated widget. The host must not try | |||
| to access the widget after calling this function. | |||
| */ | |||
| void (*cleanup)(LV2UI_Handle ui); | |||
| /** | |||
| Tell the UI that something interesting has happened at a plugin port. | |||
| What is interesting and how it is written to the buffer passed to this | |||
| function is defined by the @c format parameter, which has the same meaning | |||
| as in LV2UI_Write_Function. The only exception is ports of the class | |||
| lv2:ControlPort, for which this function should be called when the port | |||
| value changes (it does not have to be called for every single change if | |||
| the host's UI thread has problems keeping up with the thread the plugin is | |||
| running in), @c buffer_size should be 4, the buffer should contain a | |||
| single IEEE-754 float, and @c format should be 0. | |||
| By default, the host should only call this function for input ports of the | |||
| lv2:ControlPort class. However, the default setting can be modified by | |||
| using the following URIs in the UI's RDF data: | |||
| <pre> | |||
| uiext:portNotification | |||
| uiext:noPortNotification | |||
| uiext:plugin | |||
| uiext:portIndex | |||
| </pre> | |||
| For example, if you want the UI with uri | |||
| <code><http://my.pluginui></code> for the plugin with URI | |||
| <code><http://my.plugin></code> to get notified when the value of the | |||
| output control port with index 4 changes, you would use the following | |||
| in the RDF for your UI: | |||
| <pre> | |||
| <http://my.pluginui> uiext:portNotification [ uiext:plugin <http://my.plugin> ; | |||
| uiext:portIndex 4 ] . | |||
| </pre> | |||
| and similarly with <code>uiext:noPortNotification</code> if you wanted | |||
| to prevent notifications for a port for which it would be on by default | |||
| otherwise. The UI is not allowed to request notifications for ports of | |||
| types for which no transfer mechanism is specified, if it does it should | |||
| be considered broken and the host should not load it. | |||
| The @c buffer is only valid during the time of this function call, so if | |||
| the UI wants to keep it for later use it has to copy the contents to an | |||
| internal buffer. | |||
| This member may be set to NULL if the UI is not interested in any | |||
| port events. | |||
| */ | |||
| void (*port_event)(LV2UI_Handle ui, | |||
| uint32_t port_index, | |||
| uint32_t buffer_size, | |||
| uint32_t format, | |||
| const void* buffer); | |||
| /** | |||
| Return a data structure associated with an extension URI, for example | |||
| a struct containing additional function pointers. | |||
| Avoid returning function pointers directly since standard C/C++ has no | |||
| valid way of casting a void* to a function pointer. This member may be set | |||
| to NULL if the UI is not interested in supporting any extensions. This is | |||
| similar to the extension_data() member in LV2_Descriptor. | |||
| */ | |||
| const void* (*extension_data)(const char* uri); | |||
| } LV2UI_Descriptor; | |||
| /** | |||
| UI Resize Feature (LV2_UI__resize) | |||
| This structure may be used in two ways: as a feature passed by the host via | |||
| LV2UI_Descriptor::instantiate(), or as extension data provided by a UI via | |||
| LV2UI_Descriptor::extension_data()). | |||
| */ | |||
| typedef struct _LV2UI_Resize { | |||
| /** | |||
| Pointer to opaque data which must be passed to ui_resize(). | |||
| */ | |||
| LV2UI_Feature_Handle handle; | |||
| /** | |||
| Request or advertise a size change. | |||
| When this struct is provided by the host, the UI may call this | |||
| function to inform the host about the size of the UI. | |||
| When this struct is provided by the UI, the host may call this | |||
| function to notify the UI that it should change its size accordingly. | |||
| @return 0 on success. | |||
| */ | |||
| int (*ui_resize)(LV2UI_Feature_Handle handle, int width, int height); | |||
| } LV2UI_Resize; | |||
| /** | |||
| Port Map Feature (LV2_UI__portMap). | |||
| This feature can be used by the UI to get the index for a port with the | |||
| given symbol. This makes it possible to implement and distribute a UI | |||
| separately from the plugin (since symbol is a guaranteed stable port | |||
| identifier while index is not). | |||
| */ | |||
| typedef struct _LV2UI_Port_Map { | |||
| /** | |||
| Pointer to opaque data which must be passed to ui_resize(). | |||
| */ | |||
| LV2UI_Feature_Handle handle; | |||
| /** | |||
| Get the index for the port with the given @p symbol. | |||
| @return The index of the port, or LV2_UI_INVALID_PORT_INDEX if no such | |||
| port is found. | |||
| */ | |||
| uint32_t (*port_index)(LV2UI_Feature_Handle handle, const char* symbol); | |||
| } LV2UI_Port_Map; | |||
| /** | |||
| Port subscription feature (LV2_UI__portSubscribe); | |||
| */ | |||
| typedef struct _LV2UI_Port_Subscribe { | |||
| /** | |||
| Pointer to opaque data which must be passed to ui_resize(). | |||
| */ | |||
| LV2UI_Feature_Handle handle; | |||
| /** | |||
| Subscribe to updates for a port. | |||
| This means that the host will call the UI's port_event() function when | |||
| the port value changes (as defined by protocol). | |||
| Calling this function with the same @c port_index and @c port_protocol | |||
| as an already active subscription has no effect. | |||
| @param handle The handle field of this struct. | |||
| @param port_index The index of the port. | |||
| @param port_protocol The URID of the ui:PortProtocol. | |||
| @param data Extra data as defined by the port protocol, or NULL. | |||
| */ | |||
| void (*subscribe)(LV2UI_Feature_Handle handle, | |||
| uint32_t port_index, | |||
| uint32_t port_protocol, | |||
| const void* options); | |||
| /** | |||
| Unsubscribe from updates for a port. | |||
| This means that the host will cease calling calling port_event() when | |||
| the port value changes. | |||
| Calling this function with a @c port_index and @c port_protocol that | |||
| does not refer to an active port subscription has no effect. | |||
| @param handle The handle field of this struct. | |||
| @param port_index The index of the port. | |||
| @param port_protocol The URID of the ui:PortProtocol. | |||
| @param data Extra data as defined by the port protocol, or NULL. | |||
| */ | |||
| void (*unsubscribe)(LV2UI_Feature_Handle handle, | |||
| uint32_t port_index, | |||
| uint32_t port_protocol, | |||
| const void* options); | |||
| } LV2UI_Port_Subscribe; | |||
| /** | |||
| A feature to notify the host the user has grabbed a UI control. | |||
| */ | |||
| typedef struct _LV2UI_Touch { | |||
| /** | |||
| Pointer to opaque data which must be passed to ui_resize(). | |||
| */ | |||
| LV2UI_Feature_Handle handle; | |||
| /** | |||
| Notify the host that a control has been grabbed or released. | |||
| @param handle The handle field of this struct. | |||
| @param port_index The index of the port associated with the control. | |||
| @param grabbed If true, the control has been grabbed, otherwise the | |||
| control has been released. | |||
| */ | |||
| void (*touch)(LV2UI_Feature_Handle handle, | |||
| uint32_t port_index, | |||
| bool grabbed); | |||
| } LV2UI_Touch; | |||
| /** | |||
| Peak data for a slice of time, the update format for ui:peakProtocol. | |||
| */ | |||
| typedef struct _LV2UI_Peak_Data { | |||
| /** | |||
| The start of the measurement period. This is just a running counter | |||
| that is only meaningful in comparison to previous values and must not be | |||
| interpreted as an absolute time. | |||
| */ | |||
| uint32_t period_start; | |||
| /** | |||
| The size of the measurement period, in the same units as period_start. | |||
| */ | |||
| uint32_t period_size; | |||
| /** | |||
| The peak value for the measurement period. This should be the maximal | |||
| value for abs(sample) over all the samples in the period. | |||
| */ | |||
| float peak; | |||
| } LV2UI_Peak_Data; | |||
| /** | |||
| A plugin UI programmer must include a function called "lv2ui_descriptor" | |||
| with the following function prototype within the shared object file. This | |||
| function will have C-style linkage (if you are using C++ this is taken care | |||
| of by the 'extern "C"' clause at the top of the file). This function is | |||
| loaded from the library by the UI host and called to get a | |||
| LV2UI_Descriptor for the wanted plugin. | |||
| Just like lv2_descriptor(), this function takes an index parameter. The | |||
| index should only be used for enumeration and not as any sort of ID number - | |||
| the host should just iterate from 0 and upwards until the function returns | |||
| NULL or a descriptor with an URI matching the one the host is looking for. | |||
| */ | |||
| const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index); | |||
| /** | |||
| The type of the lv2ui_descriptor() function. | |||
| */ | |||
| typedef const LV2UI_Descriptor* (*LV2UI_DescriptorFunction)(uint32_t index); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| #endif /* LV2_UI_H */ | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file | |||
| C header for the LV2 URI Map extension <http://lv2plug.in/ns/ext/uri-map>. | |||
| This extension defines a simple mechanism for plugins to map URIs to | |||
| integers, usually for performance reasons (e.g. processing events typed by | |||
| URIs in real time). The expected use case is for plugins to map URIs to | |||
| integers for things they 'understand' at instantiation time, and store those | |||
| values for use in the audio thread without doing any string comparison. | |||
| This allows the extensibility of RDF with the performance of integers (or | |||
| centrally defined enumerations). | |||
| */ | |||
| #ifndef LV2_URI_MAP_H | |||
| #define LV2_URI_MAP_H | |||
| #define LV2_URI_MAP_URI "http://lv2plug.in/ns/ext/uri-map" | |||
| #include <stdint.h> | |||
| /** | |||
| Opaque pointer to host data. | |||
| */ | |||
| typedef void* LV2_URI_Map_Callback_Data; | |||
| /** | |||
| URI Map Feature. | |||
| To support this feature the host must pass an LV2_Feature struct to the | |||
| plugin's instantiate method with URI "http://lv2plug.in/ns/ext/uri-map" | |||
| and data pointed to an instance of this struct. | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| Opaque pointer to host data. | |||
| The plugin MUST pass this to any call to functions in this struct. | |||
| Otherwise, it must not be interpreted in any way. | |||
| */ | |||
| LV2_URI_Map_Callback_Data callback_data; | |||
| /** | |||
| Get the numeric ID of a URI from the host. | |||
| @param callback_data Must be the callback_data member of this struct. | |||
| @param map The 'context' of this URI. Certain extensions may define a | |||
| URI that must be passed here with certain restrictions on the return | |||
| value (e.g. limited range). This value may be NULL if the plugin needs | |||
| an ID for a URI in general. Extensions SHOULD NOT define a context | |||
| unless there is a specific need to do so, e.g. to restrict the range of | |||
| the returned value. | |||
| @param uri The URI to be mapped to an integer ID. | |||
| This function is referentially transparent; any number of calls with the | |||
| same arguments is guaranteed to return the same value over the life of a | |||
| plugin instance (though the same URI may return different values with a | |||
| different map parameter). However, this function is not necessarily very | |||
| fast: plugins SHOULD cache any IDs they might need in performance | |||
| critical situations. | |||
| The return value 0 is reserved and indicates that an ID for that URI | |||
| could not be created for whatever reason. Extensions MAY define more | |||
| precisely what this means in a certain context, but in general plugins | |||
| SHOULD handle this situation as gracefully as possible. However, hosts | |||
| SHOULD NOT return 0 from this function in non-exceptional circumstances | |||
| (e.g. the URI map SHOULD be dynamic). Hosts that statically support only | |||
| a fixed set of URIs should not expect plugins to function correctly. | |||
| */ | |||
| uint32_t (*uri_to_id)(LV2_URI_Map_Callback_Data callback_data, | |||
| const char* map, | |||
| const char* uri); | |||
| } LV2_URI_Map_Feature; | |||
| #endif /* LV2_URI_MAP_H */ | |||
| @@ -0,0 +1,121 @@ | |||
| /* | |||
| Copyright 2011 Gabriel M. Beddingfield <gabrbedd@gmail.com> | |||
| Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| copyright notice and this permission notice appear in all copies. | |||
| THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
| WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
| MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
| ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
| OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| /** | |||
| @file | |||
| C header for the LV2 URID extension <http://lv2plug.in/ns/ext/urid> | |||
| */ | |||
| #ifndef LV2_URID_H | |||
| #define LV2_URID_H | |||
| #define LV2_URID_URI "http://lv2plug.in/ns/ext/urid" | |||
| #define LV2_URID_PREFIX LV2_URID_URI "#" | |||
| #define LV2_URID__map LV2_URID_PREFIX "map" | |||
| #define LV2_URID__unmap LV2_URID_PREFIX "unmap" | |||
| /* Legacy defines */ | |||
| #define LV2_URID_MAP_URI LV2_URID__map | |||
| #define LV2_URID_UNMAP_URI LV2_URID__unmap | |||
| #include <stdint.h> | |||
| /** | |||
| Opaque pointer to host data for LV2_URID_Map. | |||
| */ | |||
| typedef void* LV2_URID_Map_Handle; | |||
| /** | |||
| Opaque pointer to host data for LV2_URID_Unmap. | |||
| */ | |||
| typedef void* LV2_URID_Unmap_Handle; | |||
| /** | |||
| URI mapped to an integer. | |||
| */ | |||
| typedef uint32_t LV2_URID; | |||
| /** | |||
| URI Map (http://lv2plug.in/ns/ext/urid#map). | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| Opaque pointer to host data. | |||
| This MUST be passed to map_uri() whenever it is called. | |||
| Otherwise, it must not be interpreted in any way. | |||
| */ | |||
| LV2_URID_Map_Handle handle; | |||
| /** | |||
| Get the numeric ID of a URI. | |||
| If the ID does not already exist, it will be created. | |||
| This function is referentially transparent; any number of calls with the | |||
| same arguments is guaranteed to return the same value over the life of a | |||
| plugin instance. Note, however, that several URIs MAY resolve to the | |||
| same ID if the host considers those URIs equivalent. | |||
| This function is not necessarily very fast or RT-safe: plugins SHOULD | |||
| cache any IDs they might need in performance critical situations. | |||
| The return value 0 is reserved and indicates that an ID for that URI | |||
| could not be created for whatever reason. However, hosts SHOULD NOT | |||
| return 0 from this function in non-exceptional circumstances (i.e. the | |||
| URI map SHOULD be dynamic). | |||
| @param handle Must be the callback_data member of this struct. | |||
| @param uri The URI to be mapped to an integer ID. | |||
| */ | |||
| LV2_URID (*map)(LV2_URID_Map_Handle handle, | |||
| const char* uri); | |||
| } LV2_URID_Map; | |||
| /** | |||
| URI Unmap (http://lv2plug.in/ns/ext/urid#unmap). | |||
| */ | |||
| typedef struct { | |||
| /** | |||
| Opaque pointer to host data. | |||
| This MUST be passed to unmap() whenever it is called. | |||
| Otherwise, it must not be interpreted in any way. | |||
| */ | |||
| LV2_URID_Unmap_Handle handle; | |||
| /** | |||
| Get the URI for a previously mapped numeric ID. | |||
| Returns NULL if @c urid is not yet mapped. Otherwise, the corresponding | |||
| URI is returned in a canonical form. This MAY not be the exact same | |||
| string that was originally passed to LV2_URID_Map::map(), but it MUST be | |||
| an identical URI according to the URI syntax specification (RFC3986). A | |||
| non-NULL return for a given @c urid will always be the same for the life | |||
| of the plugin. Plugins that intend to perform string comparison on | |||
| unmapped URIs SHOULD first canonicalise URI strings with a call to | |||
| map_uri() followed by a call to unmap_uri(). | |||
| @param handle Must be the callback_data member of this struct. | |||
| @param urid The ID to be mapped back to the URI string. | |||
| */ | |||
| const char* (*unmap)(LV2_URID_Unmap_Handle handle, | |||
| LV2_URID urid); | |||
| } LV2_URID_Unmap; | |||
| #endif /* LV2_URID_H */ | |||
| @@ -258,6 +258,7 @@ class SearchPluginsThread(QThread): | |||
| def run(self): | |||
| # TODO - split across several fuctions | |||
| global LADSPA_PATH, DSSI_PATH, LV2_PATH, VST_PATH, SF2_PATH | |||
| blacklist = toList(self.settings_db.value("Plugins/Blacklisted", [])) | |||
| bins = [] | |||
| @@ -451,16 +452,16 @@ class SearchPluginsThread(QThread): | |||
| last_value += percent_value | |||
| ## ----- LV2 | |||
| #if (self.check_lv2 and haveRDF): | |||
| #self.disccover_skip_kill = "" | |||
| #self.pluginLook(self.last_value, "LV2 bundles...") | |||
| #lv2_rdf_info = lv2_rdf.recheck_all_plugins(self) | |||
| #for info in lv2_rdf_info: | |||
| #plugins = checkPluginLV2(info) | |||
| #if (plugins != None): | |||
| #lv2_plugins.append(plugins) | |||
| if (self.check_lv2 and haveRDF): | |||
| self.pluginLook(last_value, "LV2 bundles...") | |||
| lv2_rdf.set_rdf_path(LV2_PATH) | |||
| lv2_rdf_info = lv2_rdf.recheck_all_plugins(self, last_value, percent_value) | |||
| for info in lv2_rdf_info: | |||
| plugins = checkPluginLV2(info) | |||
| if (plugins != None): | |||
| lv2_plugins.append(plugins) | |||
| #self.last_value += self.percent_value | |||
| last_value += percent_value | |||
| # ----- VST | |||
| if (self.check_vst): | |||
| @@ -574,11 +575,11 @@ class SearchPluginsThread(QThread): | |||
| json.dump(ladspa_rdf_info, f_ladspa) | |||
| f_ladspa.close() | |||
| #if (self.check_lv2): | |||
| #f_lv2 = open(os.path.join(SettingsDir, "lv2_rdf.db"), 'w') | |||
| #if (f_lv2): | |||
| #json.dump(lv2_rdf_info, f_lv2) | |||
| #f_lv2.close() | |||
| if (self.check_lv2): | |||
| f_lv2 = open(os.path.join(SettingsDir, "lv2_rdf.db"), 'w') | |||
| if (f_lv2): | |||
| json.dump(lv2_rdf_info, f_lv2) | |||
| f_lv2.close() | |||
| # Plugin Refresh Dialog | |||
| class PluginRefreshW(QDialog, ui_carla_refresh.Ui_PluginRefreshW): | |||
| @@ -1996,35 +1997,37 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
| self.edit_dialog.hide() | |||
| self.edit_dialog_geometry = None | |||
| #if (self.pinfo['hints'] & PLUGIN_HAS_GUI): | |||
| #gui_data = CarlaHost.get_gui_data(self.plugin_id) | |||
| #self.gui_dialog_type = gui_data['type'] | |||
| if (self.pinfo['hints'] & PLUGIN_HAS_GUI): | |||
| gui_info = CarlaHost.get_gui_info(self.plugin_id) | |||
| self.gui_dialog_type = gui_info['type'] | |||
| #if (self.gui_dialog_type in (GUI_INTERNAL_QT4, GUI_INTERNAL_X11)): | |||
| if (self.gui_dialog_type in (GUI_INTERNAL_QT4, GUI_INTERNAL_X11)): | |||
| self.gui_dialog = None | |||
| #self.gui_dialog = PluginGUI(self, self.pinfo['name'], gui_data) | |||
| #self.gui_dialog.hide() | |||
| #self.gui_dialog_geometry = None | |||
| self.gui_dialog_geometry = None | |||
| #self.connect(self.gui_dialog, SIGNAL("finished(int)"), self.gui_dialog_closed) | |||
| #CarlaHost.set_gui_data(self.plugin_id, Display, unwrapinstance(self.gui_dialog)) | |||
| #elif (self.gui_dialog_type in (GUI_EXTERNAL_OSC, GUI_EXTERNAL_LV2)): | |||
| #self.gui_dialog = None | |||
| elif (self.gui_dialog_type in (GUI_EXTERNAL_OSC, GUI_EXTERNAL_LV2)): | |||
| self.gui_dialog = None | |||
| #else: | |||
| #self.gui_dialog = None | |||
| #self.b_gui.setEnabled(False) | |||
| else: | |||
| self.gui_dialog = None | |||
| self.gui_dialog_type = GUI_NONE | |||
| self.b_gui.setEnabled(False) | |||
| #else: | |||
| self.gui_dialog = None | |||
| self.gui_dialog_type = GUI_NONE | |||
| else: | |||
| self.gui_dialog = None | |||
| self.gui_dialog_type = GUI_NONE | |||
| self.connect(self.led_enable, SIGNAL("clicked(bool)"), SLOT("slot_setActive(bool)")) | |||
| self.connect(self.dial_drywet, SIGNAL("sliderMoved(int)"), SLOT("slot_setDryWet(int)")) | |||
| self.connect(self.dial_vol, SIGNAL("sliderMoved(int)"), SLOT("slot_setVolume(int)")) | |||
| self.connect(self.dial_b_left, SIGNAL("sliderMoved(int)"), SLOT("slot_setBalanceLeft(int)")) | |||
| self.connect(self.dial_b_right, SIGNAL("sliderMoved(int)"), SLOT("slot_setBalanceRight(int)")) | |||
| self.connect(self.b_gui, SIGNAL("clicked(bool)"), SLOT("slot_guiClicked(bool")) | |||
| self.connect(self.b_gui, SIGNAL("clicked(bool)"), SLOT("slot_guiClicked(bool)")) | |||
| self.connect(self.b_edit, SIGNAL("clicked(bool)"), SLOT("slot_editClicked(bool)")) | |||
| self.connect(self.b_remove, SIGNAL("clicked()"), SLOT("slot_removeClicked()")) | |||
| @@ -2163,7 +2166,7 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
| def recheck_hints(self, hints): | |||
| self.pinfo['hints'] = hints | |||
| self.dial_drywet.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_DRYWET) | |||
| self.dial_vol.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_VOL) | |||
| self.dial_vol.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_VOLUME) | |||
| self.dial_b_left.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_BALANCE) | |||
| self.dial_b_right.setEnabled(self.pinfo['hints'] & PLUGIN_CAN_BALANCE) | |||
| self.b_gui.setEnabled(self.pinfo['hints'] & PLUGIN_HAS_GUI) | |||
| @@ -2523,21 +2526,9 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
| def slot_setBalanceRight(self, value): | |||
| self.set_balance_right(value, False, True) | |||
| @pyqtSlot(bool) | |||
| def slot_editClicked(self, show): | |||
| if (show): | |||
| if (self.edit_dialog_geometry): | |||
| self.edit_dialog.restoreGeometry(self.edit_dialog_geometry) | |||
| else: | |||
| self.edit_dialog_geometry = self.edit_dialog.saveGeometry() | |||
| self.edit_dialog.setVisible(show) | |||
| @pyqtSlot() | |||
| def slot_editClosed(self): | |||
| self.b_edit.setChecked(False) | |||
| @pyqtSlot(bool) | |||
| def slot_guiClicked(self, show): | |||
| print("slot_guiClicked", show) | |||
| if (self.gui_dialog_type in (GUI_INTERNAL_QT4, GUI_INTERNAL_X11)): | |||
| if (show): | |||
| if (self.gui_dialog_geometry): | |||
| @@ -2551,6 +2542,20 @@ class PluginWidget(QFrame, ui_carla_plugin.Ui_PluginWidget): | |||
| def slot_guiClosed(self): | |||
| self.b_gui.setChecked(False) | |||
| @pyqtSlot(bool) | |||
| def slot_editClicked(self, show): | |||
| print("slot_editClicked", show) | |||
| if (show): | |||
| if (self.edit_dialog_geometry): | |||
| self.edit_dialog.restoreGeometry(self.edit_dialog_geometry) | |||
| else: | |||
| self.edit_dialog_geometry = self.edit_dialog.saveGeometry() | |||
| self.edit_dialog.setVisible(show) | |||
| @pyqtSlot() | |||
| def slot_editClosed(self): | |||
| self.b_edit.setChecked(False) | |||
| @pyqtSlot() | |||
| def slot_removeClicked(self): | |||
| gui.remove_plugin(self.plugin_id, True) | |||
| @@ -2921,18 +2926,21 @@ class CarlaMainW(QMainWindow, ui_carla.Ui_CarlaMainW): | |||
| elif (ptype == PLUGIN_DSSI): | |||
| if (plugin['hints'] & PLUGIN_HAS_GUI): | |||
| return findDSSIGUI(plugin['binary'], plugin['name'], plugin['label']) | |||
| gui = findDSSIGUI(plugin['binary'], plugin['name'], plugin['label']) | |||
| if (gui): | |||
| return gui.encode("utf-8") | |||
| return c_nullptr | |||
| elif (ptype == PLUGIN_LV2): | |||
| p_uri = plugin['label'].encode("utf-8") | |||
| print("TEST", p_uri) | |||
| for rdf_item in self.lv2_rdf_list: | |||
| print(rdf_item.URI, p_uri) | |||
| if (rdf_item.URI == p_uri): | |||
| return pointer(rdf_item) | |||
| else: | |||
| return c_nullptr | |||
| #elif (ptype == PLUGIN_LV2): | |||
| #p_uri = plugin['label'] | |||
| #for rdf_item in self.lv2_rdf_list: | |||
| #if (rdf_item.URI == p_uri): | |||
| #return pointer(rdf_item) | |||
| #else: | |||
| #return c_nullptr | |||
| #elif (ptype == PLUGIN_WINVST): | |||
| ## Store object so we can return a pointer | |||
| #if (self.winvst_info == None): | |||
| @@ -3177,19 +3185,19 @@ class CarlaMainW(QMainWindow, ui_carla.Ui_CarlaMainW): | |||
| #self.ladspa_rdf_list = [] | |||
| fr_ladspa.close() | |||
| #fr_lv2_file = os.path.join(SettingsDir, "lv2_rdf.db") | |||
| #if (os.path.exists(fr_lv2_file)): | |||
| #fr_lv2 = open(fr_lv2_file, 'r') | |||
| #if (fr_lv2): | |||
| fr_lv2_file = os.path.join(SettingsDir, "lv2_rdf.db") | |||
| if (os.path.exists(fr_lv2_file)): | |||
| fr_lv2 = open(fr_lv2_file, 'r') | |||
| if (fr_lv2): | |||
| #try: | |||
| #self.lv2_rdf_list = lv2_rdf.get_c_lv2_rdfs(json.load(fr_lv2)) | |||
| self.lv2_rdf_list = lv2_rdf.get_c_lv2_rdfs(json.load(fr_lv2)) | |||
| #except: | |||
| #self.lv2_rdf_list = [] | |||
| #fr_lv2.close() | |||
| fr_lv2.close() | |||
| else: | |||
| self.ladspa_rdf_list = [] | |||
| #self.lv2_rdf_list = [] | |||
| self.lv2_rdf_list = [] | |||
| @pyqtSlot() | |||
| def slot_file_new(self): | |||
| @@ -3282,6 +3290,8 @@ class CarlaMainW(QMainWindow, ui_carla.Ui_CarlaMainW): | |||
| VST_PATH = toList(self.settings.value("Paths/VST", VST_PATH)) | |||
| SF2_PATH = toList(self.settings.value("Paths/SF2", SF2_PATH)) | |||
| print(LV2_PATH) | |||
| def timerEvent(self, event): | |||
| if (event.timerId() == self.TIMER_GUI_STUFF): | |||
| for pwidget in self.m_plugin_list: | |||
| @@ -12,7 +12,7 @@ CARLA_BUILD_FLAGS += -DDEBUG -O0 -g | |||
| # CARLA_BUILD_FLAGS += -DNDEBUG -DQT_NO_DEBUG -DQT_NO_DEBUG_STREAM -DQT_NO_DEBUG_OUTPUT -O2 -fvisibility=hidden -ffast-math -fomit-frame-pointer -mtune=generic -msse | |||
| CARLA_LINK_FLAGS = -shared -fPIC -ldl `pkg-config --libs jack fluidsynth liblo QtCore QtGui` $(LDFLAGS) | |||
| OBJS = carla_backend.o carla_bridge.o carla_threads.o jack.o osc.o ladspa.o dssi.o lv2.o vst.o sf2.o | |||
| OBJS = carla_backend.o carla_bridge.o carla_jack.o carla_osc.o carla_threads.o ladspa.o dssi.o lv2.o vst.o sf2.o | |||
| # lv2-rtmempool/rtmempool.o | |||
| @@ -16,8 +16,10 @@ | |||
| */ | |||
| #include "carla_backend.h" | |||
| #include "carla_threads.h" | |||
| #include "carla_osc.h" | |||
| #include "carla_plugin.h" | |||
| #include "carla_threads.h" | |||
| #include <cstring> | |||
| #include <ostream> | |||
| @@ -41,15 +43,22 @@ CarlaPlugin* CarlaPlugins[MAX_PLUGINS] = { nullptr }; | |||
| volatile double ains_peak[MAX_PLUGINS*2] = { 0.0 }; | |||
| volatile double aouts_peak[MAX_PLUGINS*2] = { 0.0 }; | |||
| // Global JACK client | |||
| // Global JACK stuff | |||
| jack_client_t* carla_jack_client = nullptr; | |||
| jack_nframes_t carla_buffer_size = 512; | |||
| jack_nframes_t carla_sample_rate = 44100; | |||
| // Global OSC stuff | |||
| lo_server_thread global_osc_server_thread = nullptr; | |||
| const char* global_osc_server_path = nullptr; | |||
| OscData global_osc_data = { nullptr, nullptr, nullptr }; | |||
| // Global options | |||
| carla_options_t carla_options = { | |||
| /* _initiated */ false, | |||
| /* global_jack_client */ true | |||
| /* initiated */ false, | |||
| /* global_jack_client */ true, | |||
| /* use_dssi_chunks */ false, | |||
| /* prefer_ui_bridges */ true | |||
| }; | |||
| // jack.cpp | |||
| @@ -123,10 +132,8 @@ bool carla_init(const char* client_name) | |||
| //for (unsigned short i=0; i<MAX_MIDI_EVENTS; i++) | |||
| // ExternalMidiNotes[i].valid = false; | |||
| //osc_init(); | |||
| osc_init(); | |||
| carla_check_thread.start(QThread::HighPriority); | |||
| set_last_error("no error"); | |||
| } | |||
| @@ -162,11 +169,11 @@ bool carla_close() | |||
| carla_check_thread.quit(); | |||
| if (carla_check_thread.wait(2000)) // 2 secs | |||
| if (carla_check_thread.wait(2000) == false) // 2 secs | |||
| qWarning("Failed to properly stop global check thread"); | |||
| //osc_send_exit(&global_osc_data); | |||
| //osc_close(); | |||
| osc_send_exit(&global_osc_data); | |||
| osc_close(); | |||
| if (carla_client_name) | |||
| free((void*)carla_client_name); | |||
| @@ -486,6 +493,27 @@ MidiProgramInfo* get_midi_program_info(unsigned short plugin_id, uint32_t midi_p | |||
| return &info; | |||
| } | |||
| GuiInfo* get_gui_info(unsigned short plugin_id) | |||
| { | |||
| qDebug("get_gui_info(%i)", plugin_id); | |||
| static GuiInfo info = { GUI_NONE }; | |||
| info.type = GUI_NONE; | |||
| for (unsigned short i=0; i<MAX_PLUGINS; i++) | |||
| { | |||
| CarlaPlugin* plugin = CarlaPlugins[i]; | |||
| if (plugin && plugin->id() == plugin_id) | |||
| { | |||
| plugin->get_gui_info(&info); | |||
| return &info; | |||
| } | |||
| } | |||
| qCritical("get_gui_info(%i) - could not find plugin", plugin_id); | |||
| return &info; | |||
| } | |||
| ParameterData* get_parameter_data(unsigned short plugin_id, uint32_t parameter_id) | |||
| { | |||
| qDebug("get_parameter_data(%i, %i)", plugin_id, parameter_id); | |||
| @@ -600,23 +628,6 @@ const char* get_chunk_data(unsigned short plugin_id) | |||
| return chunk_data; | |||
| } | |||
| GuiData* get_gui_data(unsigned short plugin_id) | |||
| { | |||
| qDebug("get_gui_data(%i)", plugin_id); | |||
| static GuiData data = { GUI_NONE, false, false, 0, 0, nullptr, false }; | |||
| for (unsigned short i=0; i<MAX_PLUGINS; i++) | |||
| { | |||
| // CarlaPlugin* plugin = CarlaPlugins[i]; | |||
| // if (plugin && plugin->id() == plugin_id) | |||
| // return &plugin->gui; | |||
| } | |||
| qCritical("get_gui_data(%i) - could not find plugin", plugin_id); | |||
| return &data; | |||
| } | |||
| uint32_t get_parameter_count(unsigned short plugin_id) | |||
| { | |||
| qDebug("get_parameter_count(%i)", plugin_id); | |||
| @@ -806,7 +817,7 @@ double get_default_parameter_value(unsigned short plugin_id, uint32_t parameter_ | |||
| double get_current_parameter_value(unsigned short plugin_id, uint32_t parameter_id) | |||
| { | |||
| qDebug("get_current_parameter_value(%i, %i)", plugin_id, parameter_id); | |||
| //qDebug("get_current_parameter_value(%i, %i)", plugin_id, parameter_id); | |||
| for (unsigned short i=0; i<MAX_PLUGINS; i++) | |||
| { | |||
| @@ -1186,7 +1197,7 @@ const char* get_host_client_name() | |||
| const char* get_host_osc_url() | |||
| { | |||
| qDebug("get_host_osc_url()"); | |||
| return 0; //global_osc_server_path; | |||
| return global_osc_server_path; | |||
| } | |||
| uint32_t get_buffer_size() | |||
| @@ -1371,12 +1382,3 @@ void send_plugin_midi_note(unsigned short /*plugin_id*/, bool /*onoff*/, uint8_t | |||
| // End of helper functions | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| #if 0 | |||
| // Global OSC stuff | |||
| lo_server_thread global_osc_server_thread = nullptr; | |||
| const char* global_osc_server_path = nullptr; | |||
| OscData global_osc_data = { nullptr, nullptr, nullptr }; | |||
| #endif | |||
| @@ -18,7 +18,7 @@ | |||
| #ifndef CARLA_BACKEND_H | |||
| #define CARLA_BACKEND_H | |||
| #include "includes.h" | |||
| #include "carla_includes.h" | |||
| #define STR_MAX 255 | |||
| @@ -33,7 +33,7 @@ const unsigned int PLUGIN_IS_BRIDGE = 0x02; | |||
| const unsigned int PLUGIN_IS_SYNTH = 0x04; | |||
| const unsigned int PLUGIN_USES_CHUNKS = 0x08; | |||
| const unsigned int PLUGIN_CAN_DRYWET = 0x10; | |||
| const unsigned int PLUGIN_CAN_VOL = 0x20; | |||
| const unsigned int PLUGIN_CAN_VOLUME = 0x20; | |||
| const unsigned int PLUGIN_CAN_BALANCE = 0x40; | |||
| // parameter hints | |||
| @@ -95,7 +95,9 @@ enum GuiType { | |||
| }; | |||
| enum OptionsType { | |||
| OPTION_GLOBAL_JACK_CLIENT = 1 | |||
| OPTION_GLOBAL_JACK_CLIENT = 1, | |||
| OPTION_USE_DSSI_CHUNKS = 2, | |||
| OPTION_PREFER_UI_BRIDGES = 3 | |||
| }; | |||
| enum CallbackType { | |||
| @@ -139,16 +141,6 @@ struct CustomData { | |||
| const char* value; | |||
| }; | |||
| struct GuiData { | |||
| GuiType type; | |||
| bool visible; | |||
| bool resizable; | |||
| unsigned int width; | |||
| unsigned int height; | |||
| const char* name; // DSSI Filename; LV2 Window Title | |||
| bool show_now; | |||
| }; | |||
| struct PluginInfo { | |||
| bool valid; | |||
| PluginType type; | |||
| @@ -190,6 +182,10 @@ struct MidiProgramInfo { | |||
| const char* label; | |||
| }; | |||
| struct GuiInfo { | |||
| GuiType type; | |||
| }; | |||
| struct PluginBridgeInfo { | |||
| PluginCategory category; | |||
| unsigned int hints; | |||
| @@ -203,6 +199,8 @@ struct PluginBridgeInfo { | |||
| struct carla_options_t { | |||
| bool initiated; | |||
| bool global_jack_client; | |||
| bool use_dssi_chunks; | |||
| bool prefer_ui_bridges; | |||
| }; | |||
| typedef void (*CallbackFunc)(CallbackType action, unsigned short plugin_id, int value1, int value2, double value3); | |||
| @@ -210,8 +208,6 @@ typedef void (*CallbackFunc)(CallbackType action, unsigned short plugin_id, int | |||
| // ----------------------------------------------------- | |||
| // Exported symbols (API) | |||
| class CarlaPlugin; | |||
| CARLA_EXPORT bool carla_init(const char* client_name); | |||
| CARLA_EXPORT bool carla_close(); | |||
| CARLA_EXPORT bool carla_is_engine_running(); | |||
| @@ -226,12 +222,12 @@ CARLA_EXPORT PortCountInfo* get_parameter_count_info(unsigned short plugin_id); | |||
| CARLA_EXPORT ParameterInfo* get_parameter_info(unsigned short plugin_id, uint32_t parameter_id); | |||
| CARLA_EXPORT ScalePointInfo* get_scalepoint_info(unsigned short plugin_id, uint32_t parameter_id, uint32_t scalepoint_id); | |||
| CARLA_EXPORT MidiProgramInfo* get_midi_program_info(unsigned short plugin_id, uint32_t midi_program_id); | |||
| CARLA_EXPORT GuiInfo* get_gui_info(unsigned short plugin_id); | |||
| CARLA_EXPORT ParameterData* get_parameter_data(unsigned short plugin_id, uint32_t parameter_id); | |||
| CARLA_EXPORT ParameterRanges* get_parameter_ranges(unsigned short plugin_id, uint32_t parameter_id); | |||
| CARLA_EXPORT CustomData* get_custom_data(unsigned short plugin_id, uint32_t custom_data_id); | |||
| CARLA_EXPORT const char* get_chunk_data(unsigned short plugin_id); | |||
| CARLA_EXPORT GuiData* get_gui_data(unsigned short plugin_id); | |||
| CARLA_EXPORT uint32_t get_parameter_count(unsigned short plugin_id); | |||
| CARLA_EXPORT uint32_t get_program_count(unsigned short plugin_id); | |||
| @@ -287,6 +283,8 @@ CARLA_EXPORT double get_latency(); | |||
| // End of exported symbols | |||
| // ----------------------------------------------------- | |||
| class CarlaPlugin; | |||
| // Helper functions | |||
| const char* bool2str(bool yesno); | |||
| short get_new_plugin_id(); | |||
| @@ -17,7 +17,7 @@ | |||
| #include "carla_plugin.h" | |||
| // Global JACK client | |||
| // Global JACK stuff | |||
| extern jack_client_t* carla_jack_client; | |||
| extern jack_nframes_t carla_buffer_size; | |||
| extern jack_nframes_t carla_sample_rate; | |||
| @@ -0,0 +1,837 @@ | |||
| /* | |||
| * JACK Backend code for Carla | |||
| * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU General Public License as published by | |||
| * the Free Software Foundation; either version 2 of the License, or | |||
| * any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #include "carla_osc.h" | |||
| #include "carla_plugin.h" | |||
| // FIXME - check for std::isdigit() elsewhere | |||
| #include <iostream> | |||
| // Global variables | |||
| extern const char* carla_client_name; | |||
| size_t client_name_len; | |||
| // Global OSC stuff | |||
| extern lo_server_thread global_osc_server_thread; | |||
| extern const char* global_osc_server_path; | |||
| extern OscData global_osc_data; | |||
| void osc_init() | |||
| { | |||
| qDebug("osc_init()"); | |||
| client_name_len = strlen(carla_client_name); | |||
| // create new OSC thread | |||
| global_osc_server_thread = lo_server_thread_new(nullptr, osc_error_handler); | |||
| // get our full OSC server path | |||
| char* osc_thread_path = lo_server_thread_get_url(global_osc_server_thread); | |||
| char osc_path_tmp[strlen(osc_thread_path) + strlen(carla_client_name) + 1]; | |||
| strcpy(osc_path_tmp, osc_thread_path); | |||
| strcat(osc_path_tmp, carla_client_name); | |||
| free(osc_thread_path); | |||
| global_osc_server_path = strdup(osc_path_tmp); | |||
| // register message handler and start OSC thread | |||
| lo_server_thread_add_method(global_osc_server_thread, nullptr, nullptr, osc_message_handler, nullptr); | |||
| lo_server_thread_start(global_osc_server_thread); | |||
| // debug our server path just to make sure everything is ok | |||
| qDebug("Carla OSC -> %s\n", global_osc_server_path); | |||
| } | |||
| void osc_close() | |||
| { | |||
| qDebug("osc_close()"); | |||
| osc_clear_data(&global_osc_data); | |||
| lo_server_thread_stop(global_osc_server_thread); | |||
| lo_server_thread_del_method(global_osc_server_thread, nullptr, nullptr); | |||
| lo_server_thread_free(global_osc_server_thread); | |||
| free((void*)global_osc_server_path); | |||
| global_osc_server_path = nullptr; | |||
| } | |||
| void osc_clear_data(OscData* osc_data) | |||
| { | |||
| qDebug("osc_clear_data(%p)", osc_data); | |||
| if (osc_data->path) | |||
| free((void*)osc_data->path); | |||
| if (osc_data->source) | |||
| lo_address_free(osc_data->source); | |||
| if (osc_data->target) | |||
| lo_address_free(osc_data->target); | |||
| osc_data->path = nullptr; | |||
| osc_data->source = nullptr; | |||
| osc_data->target = nullptr; | |||
| } | |||
| void osc_error_handler(int num, const char* msg, const char* path) | |||
| { | |||
| qCritical("osc_error_handler(%i, %s, %s)", num, msg, path); | |||
| } | |||
| int osc_message_handler(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data) | |||
| { | |||
| //qDebug("osc_message_handler(%s, %s, %p, %i, %p, %p)", path, types, argv, argc, data, user_data); | |||
| // Initial path check | |||
| if (strcmp(path, "register") == 0) | |||
| { | |||
| lo_message message = lo_message(data); | |||
| lo_address source = lo_message_get_source(message); | |||
| return osc_handle_register(argv, source); | |||
| } | |||
| else if (strcmp(path, "unregister") == 0) | |||
| { | |||
| return osc_handle_unregister(); | |||
| } | |||
| else | |||
| { | |||
| // Check if message is for this client | |||
| if (strncmp(path+1, carla_client_name, client_name_len) != 0 && path[client_name_len+1] == '/') | |||
| { | |||
| qWarning("osc_message_handler() - message not for this client -> '%s'' != '/%s/'", path, carla_client_name); | |||
| return 1; | |||
| } | |||
| } | |||
| // Get id from message | |||
| int plugin_id = 0; | |||
| if (std::isdigit(path[client_name_len+2])) | |||
| plugin_id += path[client_name_len+2]-'0'; | |||
| if (std::isdigit(path[client_name_len+3])) | |||
| plugin_id += (path[client_name_len+3]-'0')*10; | |||
| if (plugin_id < 0 || plugin_id > MAX_PLUGINS) | |||
| { | |||
| qCritical("osc_message_handler() - failed to get plugin_id -> %i", plugin_id); | |||
| return 1; | |||
| } | |||
| CarlaPlugin* plugin = CarlaPlugins[plugin_id]; | |||
| if (plugin == nullptr || plugin->id() != plugin_id) | |||
| { | |||
| qWarning("osc_message_handler() - invalid plugin '%i', probably has been removed", plugin_id); | |||
| return 1; | |||
| } | |||
| // Get method from path (/Carla/i/method) | |||
| size_t mindex = client_name_len + 3; | |||
| mindex += (plugin_id >= 10) ? 2 : 1; | |||
| char method[24] = { 0 }; | |||
| for (size_t i=mindex; i < strlen(path) && i < mindex+24; i++) | |||
| method[i-mindex] = path[i]; | |||
| // // Internal OSC Stuff | |||
| // if (strcmp(method, "set_active") == 0) | |||
| // return osc_set_active_handler(plugin, argv); | |||
| // else if (strcmp(method, "set_drywet") == 0) | |||
| // return osc_set_drywet_handler(plugin, argv); | |||
| // else if (strcmp(method, "set_vol") == 0) | |||
| // return osc_set_vol_handler(plugin, argv); | |||
| // else if (strcmp(method, "set_balance_left") == 0) | |||
| // return osc_set_balance_left_handler(plugin, argv); | |||
| // else if (strcmp(method, "set_balance_right") == 0) | |||
| // return osc_set_balance_right_handler(plugin, argv); | |||
| // else if (strcmp(method, "set_parameter") == 0) | |||
| // return osc_set_parameter_handler(plugin, argv); | |||
| // else if (strcmp(method, "set_program") == 0) | |||
| // return osc_set_program_handler(plugin, argv); | |||
| // else if (strcmp(method, "note_on") == 0) | |||
| // return osc_note_on_handler(plugin, argv); | |||
| // else if (strcmp(method, "note_off") == 0) | |||
| // return osc_note_off_handler(plugin, argv); | |||
| // // Plugin Bridges | |||
| // else if (strcmp(method, "bridge_audio_count") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeAudioCountInfo, argv); | |||
| // else if (strcmp(method, "bridge_midi_count") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeMidiCountInfo, argv); | |||
| // else if (strcmp(method, "bridge_param_count") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeParameterCountInfo, argv); | |||
| // else if (strcmp(method, "bridge_program_count") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeProgramCountInfo, argv); | |||
| // else if (strcmp(method, "bridge_midi_program_count") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeMidiProgramCountInfo, argv); | |||
| // else if (strcmp(method, "bridge_plugin_info") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgePluginInfo, argv); | |||
| // else if (strcmp(method, "bridge_param_info") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeParameterInfo, argv); | |||
| // else if (strcmp(method, "bridge_param_data") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeParameterDataInfo, argv); | |||
| // else if (strcmp(method, "bridge_param_ranges") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeParameterRangesInfo, argv); | |||
| // else if (strcmp(method, "bridge_program_name") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeProgramName, argv); | |||
| // else if (strcmp(method, "bridge_ains_peak") == 0) | |||
| // return osc_bridge_ains_peak_handler(plugin, argv); | |||
| // else if (strcmp(method, "bridge_aouts_peak") == 0) | |||
| // return osc_bridge_aouts_peak_handler(plugin, argv); | |||
| // else if (strcmp(method, "bridge_update") == 0) | |||
| // return plugin->set_osc_bridge_info(OscBridgeUpdateNow, argv); | |||
| // // Misc Stuff | |||
| // else | |||
| // { | |||
| if (strcmp(method, "update") == 0) | |||
| { | |||
| lo_message message = lo_message(data); | |||
| lo_address source = lo_message_get_source(message); | |||
| return osc_handle_update(plugin, argv, source); | |||
| } | |||
| else if (strcmp(method, "configure") == 0) | |||
| return osc_handle_configure(plugin, argv); | |||
| else if (strcmp(method, "control") == 0) | |||
| return osc_handle_control(plugin, argv); | |||
| // else if (strcmp(method, "program") == 0) | |||
| // return (plugin->type == PLUGIN_DSSI) ? osc_midi_program_handler(plugin, argv) : osc_program_handler(plugin, argv); | |||
| // else if (strcmp(method, "midi") == 0) | |||
| // return osc_midi_handler(plugin, argv); | |||
| // else if (strcmp(method, "exiting") == 0) | |||
| // return osc_exiting_handler(plugin); | |||
| else | |||
| qWarning("osc_message_handler() - unsupported OSC method '%s'", method); | |||
| // } | |||
| return 1; | |||
| // Q_UNUSED(types); | |||
| // Q_UNUSED(argc); | |||
| // Q_UNUSED(user_data); | |||
| } | |||
| int osc_handle_register(lo_arg** argv, lo_address source) | |||
| { | |||
| qDebug("osc_handle_register()"); | |||
| if (global_osc_data.path == nullptr) | |||
| { | |||
| const char* url = (const char*)&argv[0]->s; | |||
| const char* host; | |||
| const char* port; | |||
| qDebug("osc_handle_register() - OSC backend registered to %s", url); | |||
| host = lo_address_get_hostname(source); | |||
| port = lo_address_get_port(source); | |||
| global_osc_data.source = lo_address_new(host, port); | |||
| host = lo_url_get_hostname(url); | |||
| port = lo_url_get_port(url); | |||
| global_osc_data.target = lo_address_new(host, port); | |||
| global_osc_data.path = lo_url_get_path(url); | |||
| free((void*)host); | |||
| free((void*)port); | |||
| for (unsigned short i=0; i<MAX_PLUGINS; i++) | |||
| { | |||
| //CarlaPlugin* plugin = CarlaPlugins[i]; | |||
| //if (plugin && plugin->id() >= 0) | |||
| // osc_new_plugin(plugin); | |||
| } | |||
| return 0; | |||
| } | |||
| else | |||
| qCritical("osc_handle_register() - OSC backend already registered to %s", global_osc_data.path); | |||
| return 1; | |||
| } | |||
| int osc_handle_unregister() | |||
| { | |||
| qDebug("osc_handle_unregister()"); | |||
| if (global_osc_data.path) | |||
| { | |||
| osc_clear_data(&global_osc_data); | |||
| return 0; | |||
| } | |||
| else | |||
| qCritical("osc_handle_unregister() - OSC backend is not registered yet"); | |||
| return 1; | |||
| } | |||
| //int osc_set_active_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_set_active_handler()"); | |||
| // bool value = (bool)argv[0]->i; | |||
| // plugin->set_active(value, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_set_drywet_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_set_drywet_handler()"); | |||
| // double value = argv[0]->f; | |||
| // plugin->set_drywet(value, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_set_vol_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_set_vol_handler()"); | |||
| // double value = argv[0]->f; | |||
| // plugin->set_vol(value, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_set_balance_left_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_set_balance_left_handler()"); | |||
| // double value = argv[0]->f; | |||
| // plugin->set_balance_left(value, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_set_balance_right_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_set_balance_right_handler()"); | |||
| // double value = argv[0]->f; | |||
| // plugin->set_balance_right(value, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_set_parameter_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_set_parameter_handler()"); | |||
| // uint32_t parameter_id = argv[0]->i; | |||
| // double value = argv[1]->f; | |||
| // plugin->set_parameter_value(parameter_id, value, true, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_set_program_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_set_program_handler()"); | |||
| // uint32_t program_id = argv[0]->i; | |||
| // plugin->set_program(program_id, true, false, true, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_note_on_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_note_on_handler()"); | |||
| // int note = argv[0]->i; | |||
| // int velo = argv[1]->i; | |||
| // send_plugin_midi_note(plugin->id, true, note, velo, true, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_note_off_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // qDebug("osc_note_off_handler()"); | |||
| // int note = argv[0]->i; | |||
| // int velo = argv[1]->i; | |||
| // send_plugin_midi_note(plugin->id, false, note, velo, true, false, true); | |||
| // return 0; | |||
| //} | |||
| //int osc_bridge_ains_peak_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // int index = argv[0]->i; | |||
| // double value = argv[1]->f; | |||
| // ains_peak[(plugin->id*2)+index-1] = value; | |||
| // return 0; | |||
| //} | |||
| //int osc_bridge_aouts_peak_handler(AudioPlugin* plugin, lo_arg** argv) | |||
| //{ | |||
| // int index = argv[0]->i; | |||
| // double value = argv[1]->f; | |||
| // aouts_peak[(plugin->id*2)+index-1] = value; | |||
| // return 0; | |||
| //} | |||
| int osc_handle_update(CarlaPlugin* plugin, lo_arg** argv, lo_address source) | |||
| { | |||
| qDebug("osc_handle_update()"); | |||
| const char* url = (const char*)&argv[0]->s; | |||
| plugin->update_osc_data(source, url); | |||
| return 0; | |||
| } | |||
| int osc_handle_configure(CarlaPlugin* plugin, lo_arg** argv) | |||
| { | |||
| //qDebug("osc_handle_configure()"); | |||
| const char* key = (const char*)&argv[0]->s; | |||
| const char* value = (const char*)&argv[1]->s; | |||
| plugin->set_custom_data("string", key, value, false); | |||
| return 0; | |||
| } | |||
| int osc_handle_control(CarlaPlugin* plugin, lo_arg** argv) | |||
| { | |||
| qDebug("osc_handle_control()"); | |||
| int32_t rindex = argv[0]->i; | |||
| double value = argv[1]->f; | |||
| int32_t parameter_id = -1; | |||
| for (uint32_t i=0; i < plugin->param_count(); i++) | |||
| { | |||
| if (plugin->param_data(i)->rindex == rindex) | |||
| { | |||
| parameter_id = i; | |||
| break; | |||
| } | |||
| } | |||
| if (parameter_id >= 0) | |||
| plugin->set_parameter_value(parameter_id, value, false, true, true); | |||
| return 0; | |||
| } | |||
| void osc_new_plugin(CarlaPlugin* plugin) | |||
| { | |||
| qDebug("osc_new_plugin()"); | |||
| if (global_osc_data.target) | |||
| { | |||
| osc_send_add_plugin(&global_osc_data, plugin->id(), plugin->name()); | |||
| PluginInfo* info = get_plugin_info(plugin->id()); | |||
| PortCountInfo* audio_info = get_audio_port_count_info(plugin->id()); | |||
| PortCountInfo* midi_info = get_midi_port_count_info(plugin->id()); | |||
| PortCountInfo* param_info = get_parameter_count_info(plugin->id()); | |||
| osc_send_set_plugin_data(&global_osc_data, plugin->id(), info->type, info->category, info->hints, | |||
| get_real_plugin_name(plugin->id()), info->label, info->maker, info->copyright, info->unique_id); | |||
| osc_send_set_plugin_ports(&global_osc_data, plugin->id(), | |||
| audio_info->ins, audio_info->outs, | |||
| midi_info->ins, midi_info->outs, | |||
| param_info->ins, param_info->outs, param_info->total); | |||
| //osc_send_set_parameter_value(&global_osc_data, plugin->id, PARAMETER_ACTIVE, plugin->active ? 1.0f : 0.0f); | |||
| //osc_send_set_parameter_value(&global_osc_data, plugin->id, PARAMETER_DRYWET, plugin->x_drywet); | |||
| //osc_send_set_parameter_value(&global_osc_data, plugin->id, PARAMETER_VOLUME, plugin->x_vol); | |||
| //osc_send_set_parameter_value(&global_osc_data, plugin->id, PARAMETER_BALANCE_LEFT, plugin->x_bal_left); | |||
| //osc_send_set_parameter_value(&global_osc_data, plugin->id, PARAMETER_BALANCE_RIGHT, plugin->x_bal_right); | |||
| uint32_t i; | |||
| if (plugin->param_count() > 0 && plugin->param_count() < 200) | |||
| { | |||
| for (i=0; i < plugin->param_count(); i++) | |||
| { | |||
| ParameterInfo* info = get_parameter_info(plugin->id(), i); | |||
| ParameterData* data = plugin->param_data(i); | |||
| ParameterRanges* ranges = plugin->param_ranges(i); | |||
| osc_send_set_parameter_data(&global_osc_data, plugin->id(), i, data->type, data->hints, | |||
| info->name, info->label, | |||
| plugin->get_current_parameter_value(i), | |||
| ranges->min, ranges->max, ranges->def, | |||
| ranges->step, ranges->step_small, ranges->step_large); | |||
| } | |||
| } | |||
| osc_send_set_program_count(&global_osc_data, plugin->id(), plugin->prog_count()); | |||
| //for (i=0; i < plugin->prog_count(); i++) | |||
| // osc_send_set_program_name(&global_osc_data, plugin->id, i, plugin->prog.names[i]); | |||
| //osc_send_set_program(&global_osc_data, plugin->id, plugin->prog.current); | |||
| osc_send_set_midi_program_count(&global_osc_data, plugin->id(), plugin->midiprog_count()); | |||
| //for (i=0; i < plugin->midiprog.count; i++) | |||
| // osc_send_set_program_name(&global_osc_data, plugin->id, i, plugin->midiprog.names[i]); | |||
| //osc_send_set_midi_program(&global_osc_data, plugin->id, plugin->midiprog.current); | |||
| } | |||
| } | |||
| void osc_send_add_plugin(OscData* osc_data, int plugin_id, const char* plugin_name) | |||
| { | |||
| qDebug("osc_send_add_plugin(%i, %s)", plugin_id, plugin_name); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+12]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/add_plugin"); | |||
| lo_send(osc_data->target, target_path, "is", plugin_id, plugin_name); | |||
| } | |||
| } | |||
| void osc_send_remove_plugin(OscData* osc_data, int plugin_id) | |||
| { | |||
| qDebug("osc_send_remove_plugin(%i)", plugin_id); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+15]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/remove_plugin"); | |||
| lo_send(osc_data->target, target_path, "i", plugin_id); | |||
| } | |||
| } | |||
| void osc_send_set_plugin_data(OscData* osc_data, int plugin_id, int type, int category, int hints, const char* name, const char* label, const char* maker, const char* copyright, long unique_id) | |||
| { | |||
| qDebug("osc_send_set_plugin_data(%i, %i, %i, %i, %s, %s, %s, %s, %li)", plugin_id, type, category, hints, name, label, maker, copyright, unique_id); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+17]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_plugin_data"); | |||
| lo_send(osc_data->target, target_path, "iiiissssi", plugin_id, type, category, hints, name, label, maker, copyright, unique_id); | |||
| } | |||
| } | |||
| void osc_send_set_plugin_ports(OscData* osc_data, int plugin_id, int ains, int aouts, int mins, int mouts, int cins, int couts, int ctotals) | |||
| { | |||
| qDebug("osc_send_set_plugin_ports(%i, %i, %i, %i, %i, %i, %i, %i)", plugin_id, ains, aouts, mins, mouts, cins, couts, ctotals); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+18]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_plugin_ports"); | |||
| lo_send(osc_data->target, target_path, "iiiiiiii", plugin_id, ains, aouts, mins, mouts, cins, couts, ctotals); | |||
| } | |||
| } | |||
| void osc_send_set_parameter_value(OscData* osc_data, int plugin_id, int param_id, double value) | |||
| { | |||
| //qDebug("osc_send_set_parameter_value(%i, %i, %f)", plugin_id, param_id, value); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+21]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_parameter_value"); | |||
| lo_send(osc_data->target, target_path, "iif", plugin_id, param_id, value); | |||
| } | |||
| } | |||
| void osc_send_set_parameter_data(OscData* osc_data, int plugin_id, int param_id, int ptype, int hints, const char* name, const char* label, double current, double x_min, double x_max, double x_def, double x_step, double x_step_small, double x_step_large) | |||
| { | |||
| qDebug("osc_send_set_parameter_data(%i, %i, %i, %i, %s, %s, %f, %f, %f, %f, %f, %f, %f)", plugin_id, param_id, ptype, hints, name, label, current, x_min, x_max, x_def, x_step, x_step_small, x_step_large); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+20]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_parameter_data"); | |||
| lo_send(osc_data->target, target_path, "iiiissfffffff", plugin_id, param_id, ptype, hints, name, label, current, x_min, x_max, x_def, x_step, x_step_small, x_step_large); | |||
| } | |||
| } | |||
| void osc_send_set_parameter_midi_channel(OscData* osc_data, int plugin_id, int parameter_id, int midi_channel) | |||
| { | |||
| qDebug("osc_send_set_parameter_midi_channel(%i, %i, %i)", plugin_id, parameter_id, midi_channel); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+28]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_parameter_midi_channel"); | |||
| lo_send(osc_data->target, target_path, "iii", plugin_id, parameter_id, midi_channel); | |||
| } | |||
| } | |||
| void osc_send_set_parameter_midi_cc(OscData* osc_data, int plugin_id, int parameter_id, int midi_cc) | |||
| { | |||
| qDebug("osc_send_set_parameter_midi_cc(%i, %i, %i)", plugin_id, parameter_id, midi_cc); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+23]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_parameter_midi_cc"); | |||
| lo_send(osc_data->target, target_path, "iii", plugin_id, parameter_id, midi_cc); | |||
| } | |||
| } | |||
| void osc_send_set_default_value(OscData* osc_data, int plugin_id, int param_id, double value) | |||
| { | |||
| qDebug("osc_send_set_default_value(%i, %i, %f)", plugin_id, param_id, value); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+19]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_default_value"); | |||
| lo_send(osc_data->target, target_path, "iif", plugin_id, param_id, value); | |||
| } | |||
| } | |||
| void osc_send_set_input_peak_value(OscData* osc_data, int plugin_id, int port_id, double value) | |||
| { | |||
| qDebug("osc_send_set_input_peak_value(%i, %i, %f)", plugin_id, port_id, value); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+22]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_input_peak_value"); | |||
| lo_send(osc_data->target, target_path, "iif", plugin_id, port_id, value); | |||
| } | |||
| } | |||
| void osc_send_set_output_peak_value(OscData* osc_data, int plugin_id, int port_id, double value) | |||
| { | |||
| qDebug("osc_send_set_output_peak_value(%i, %i, %f)", plugin_id, port_id, value); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+23]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_output_peak_value"); | |||
| lo_send(osc_data->target, target_path, "iif", plugin_id, port_id, value); | |||
| } | |||
| } | |||
| void osc_send_set_program(OscData* osc_data, int plugin_id, int program_id) | |||
| { | |||
| qDebug("osc_send_set_program(%i, %i)", plugin_id, program_id); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+13]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_program"); | |||
| lo_send(osc_data->target, target_path, "ii", plugin_id, program_id); | |||
| } | |||
| } | |||
| void osc_send_set_program_count(OscData* osc_data, int plugin_id, int program_count) | |||
| { | |||
| qDebug("osc_send_set_program_count(%i, %i)", plugin_id, program_count); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+19]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_program_count"); | |||
| lo_send(osc_data->target, target_path, "ii", plugin_id, program_count); | |||
| } | |||
| } | |||
| void osc_send_set_program_name(OscData* osc_data, int plugin_id, int program_id, const char* program_name) | |||
| { | |||
| qDebug("osc_send_set_program_name(%i, %i, %s)", plugin_id, program_id, program_name); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+18]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_program_name"); | |||
| lo_send(osc_data->target, target_path, "iis", plugin_id, program_id, program_name); | |||
| } | |||
| } | |||
| void osc_send_set_midi_program(OscData* osc_data, int plugin_id, int midi_program_id) | |||
| { | |||
| qDebug("osc_send_set_midi_program(%i, %i)", plugin_id, midi_program_id); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+18]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_midi_program"); | |||
| lo_send(osc_data->target, target_path, "ii", plugin_id, midi_program_id); | |||
| } | |||
| } | |||
| void osc_send_set_midi_program_count(OscData* osc_data, int plugin_id, int midi_program_count) | |||
| { | |||
| qDebug("osc_send_set_midi_program_count(%i, %i)", plugin_id, midi_program_count); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+24]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_midi_program_count"); | |||
| lo_send(osc_data->target, target_path, "ii", plugin_id, midi_program_count); | |||
| } | |||
| } | |||
| void osc_send_set_midi_program_data(OscData* osc_data, int plugin_id, int midi_program_id, int bank_id, int program_id, const char* midi_program_name) | |||
| { | |||
| qDebug("osc_send_set_midi_program_data(%i, %i, %i, %i, %s)", plugin_id, midi_program_id, bank_id, program_id, midi_program_name); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+23]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/set_midi_program_data"); | |||
| lo_send(osc_data->target, target_path, "iiiis", plugin_id, midi_program_id, bank_id, program_id, midi_program_name); | |||
| } | |||
| } | |||
| void osc_send_note_on(OscData* osc_data, int plugin_id, int note, int velo) | |||
| { | |||
| qDebug("osc_send_note_on(%i, %i, %i)", plugin_id, note, velo); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+9]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/note_on"); | |||
| lo_send(osc_data->target, target_path, "iii", plugin_id, note, velo); | |||
| } | |||
| } | |||
| void osc_send_note_off(OscData* osc_data, int plugin_id, int note) | |||
| { | |||
| qDebug("osc_send_note_off(%i, %i)", plugin_id, note); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+10]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/note_off"); | |||
| lo_send(osc_data->target, target_path, "ii", plugin_id, note); | |||
| } | |||
| } | |||
| void osc_send_exit(OscData* osc_data) | |||
| { | |||
| qDebug("osc_send_exit()"); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+6]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/exit"); | |||
| lo_send(osc_data->target, target_path, ""); | |||
| } | |||
| } | |||
| void osc_send_configure(OscData* osc_data, const char* key, const char* value) | |||
| { | |||
| qDebug("osc_send_configure(%s, %s)", key, value); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+11]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/configure"); | |||
| lo_send(osc_data->target, target_path, "ss", key, value); | |||
| } | |||
| } | |||
| void osc_send_control(OscData* osc_data, int param, double value) | |||
| { | |||
| //qDebug("osc_send_control(%i, %f)", param, value); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+9]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/control"); | |||
| lo_send(osc_data->target, target_path, "if", param, value); | |||
| } | |||
| } | |||
| void osc_send_program(OscData* osc_data, int program_id) | |||
| { | |||
| qDebug("osc_send_program(%i)", program_id); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+9]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/program"); | |||
| lo_send(osc_data->target, target_path, "i", program_id); | |||
| } | |||
| } | |||
| void osc_send_program_as_midi(OscData* osc_data, int bank, int program) | |||
| { | |||
| qDebug("osc_send_program_as_midi(%i, %i)", bank, program); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+9]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/program"); | |||
| lo_send(osc_data->target, target_path, "ii", bank, program); | |||
| } | |||
| } | |||
| void osc_send_midi_program(OscData* osc_data, int bank, int program) | |||
| { | |||
| qDebug("osc_send_midi_program(%i, %i)", bank, program); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+9]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/midi_program"); | |||
| lo_send(osc_data->target, target_path, "ii", bank, program); | |||
| } | |||
| } | |||
| void osc_send_show(OscData* osc_data) | |||
| { | |||
| qDebug("osc_send_show()"); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+6]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/show"); | |||
| lo_send(osc_data->target, target_path, ""); | |||
| } | |||
| } | |||
| void osc_send_hide(OscData* osc_data) | |||
| { | |||
| qDebug("osc_send_hide()"); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+6]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/hide"); | |||
| lo_send(osc_data->target, target_path, ""); | |||
| } | |||
| } | |||
| void osc_send_quit(OscData* osc_data) | |||
| { | |||
| qDebug("osc_send_quit()"); | |||
| if (osc_data->target) | |||
| { | |||
| char target_path[strlen(osc_data->path)+6]; | |||
| strcpy(target_path, osc_data->path); | |||
| strcat(target_path, "/quit"); | |||
| lo_send(osc_data->target, target_path, ""); | |||
| } | |||
| } | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| * JACK Backend code for Carla | |||
| * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU General Public License as published by | |||
| * the Free Software Foundation; either version 2 of the License, or | |||
| * any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| #ifndef CARLA_OSC_H | |||
| #define CARLA_OSC_H | |||
| #include <lo/lo.h> | |||
| class CarlaPlugin; | |||
| struct OscData { | |||
| char* path; | |||
| lo_address source; | |||
| lo_address target; | |||
| }; | |||
| void osc_init(); | |||
| void osc_close(); | |||
| void osc_clear_data(OscData* osc_data); | |||
| void osc_error_handler(int num, const char* msg, const char* path); | |||
| int osc_message_handler(const char* path, const char* types, lo_arg** argv, int argc, void* data, void* user_data); | |||
| int osc_handle_register(lo_arg** argv, lo_address source); | |||
| int osc_handle_unregister(); | |||
| //int osc_set_active_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_set_drywet_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_set_volume_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_set_balance_left_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_set_balance_right_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_set_parameter_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_set_program_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_note_on_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_note_off_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_bridge_ains_peak_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_bridge_aouts_peak_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| int osc_handle_update(CarlaPlugin* plugin, lo_arg** argv, lo_address source); | |||
| int osc_handle_configure(CarlaPlugin* plugin, lo_arg** argv); | |||
| int osc_handle_control(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_program_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_midi_program_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_midi_handler(CarlaPlugin* plugin, lo_arg** argv); | |||
| //int osc_exiting_handler(CarlaPlugin* plugin); | |||
| void osc_new_plugin(CarlaPlugin* plugin); | |||
| void osc_send_add_plugin(OscData* osc_data, int plugin_id, const char* plugin_name); | |||
| void osc_send_remove_plugin(OscData* osc_data, int plugin_id); | |||
| void osc_send_set_plugin_data(OscData* osc_data, int plugin_id, int type, int category, int hints, const char* name, const char* label, const char* maker, const char* copyright, long unique_id); | |||
| void osc_send_set_plugin_ports(OscData* osc_data, int plugin_id, int ains, int aouts, int mins, int mouts, int cins, int couts, int ctotals); | |||
| void osc_send_set_parameter_value(OscData* osc_data, int plugin_id, int param_id, double value); | |||
| void osc_send_set_parameter_data(OscData* osc_data, int plugin_id, int param_id, int ptype, int hints, const char* name, const char* label, double current, double x_min, double x_max, double x_def, double x_step, double x_step_small, double x_step_large); | |||
| void osc_send_set_parameter_midi_channel(OscData* osc_data, int plugin_id, int parameter_id, int midi_channel); | |||
| void osc_send_set_parameter_midi_cc(OscData* osc_data, int plugin_id, int parameter_id, int midi_cc); | |||
| void osc_send_set_default_value(OscData* osc_data, int plugin_id, int param_id, double value); | |||
| void osc_send_set_input_peak_value(OscData* osc_data, int plugin_id, int port_id, double value); | |||
| void osc_send_set_output_peak_value(OscData* osc_data, int plugin_id, int port_id, double value); | |||
| void osc_send_set_program(OscData* osc_data, int plugin_id, int program_id); | |||
| void osc_send_set_program_count(OscData* osc_data, int plugin_id, int program_count); | |||
| void osc_send_set_program_name(OscData* osc_data, int plugin_id, int program_id, const char* program_name); | |||
| void osc_send_set_midi_program(OscData* osc_data, int plugin_id, int midi_program_id); | |||
| void osc_send_set_midi_program_count(OscData* osc_data, int plugin_id, int midi_program_count); | |||
| void osc_send_set_midi_program_data(OscData* osc_data, int plugin_id, int midi_program_id, int bank_id, int program_id, const char* midi_program_name); | |||
| void osc_send_note_on(OscData* osc_data, int plugin_id, int note, int velo); | |||
| void osc_send_note_off(OscData* osc_data, int plugin_id, int note); | |||
| void osc_send_exit(OscData* osc_data); | |||
| void osc_send_configure(OscData* osc_data, const char* key, const char* value); | |||
| void osc_send_control(OscData* osc_data, int param_id, double value); | |||
| void osc_send_program(OscData* osc_data, int program_id); | |||
| void osc_send_program_as_midi(OscData* osc_data, int bank, int program); | |||
| void osc_send_midi_program(OscData* osc_data, int bank, int program); | |||
| void osc_send_show(OscData* osc_data); | |||
| void osc_send_hide(OscData* osc_data); | |||
| void osc_send_quit(OscData* osc_data); | |||
| #endif // CARLA_OSC_H | |||
| @@ -19,9 +19,11 @@ | |||
| #define CARLA_PLUGIN_H | |||
| #include "carla_backend.h" | |||
| #include "carla_osc.h" | |||
| #include <cmath> | |||
| #include <cstring> | |||
| #include <unistd.h> | |||
| #include <jack/jack.h> | |||
| #include <jack/midiport.h> | |||
| @@ -30,11 +32,16 @@ | |||
| #define CARLA_PROCESS_CONTINUE_CHECK if (m_id != plugin_id) { return callback_action(CALLBACK_DEBUG, plugin_id, m_id, 0, 0.0); } | |||
| class CarlaPluginThread; | |||
| const unsigned short MAX_POSTEVENTS = 128; | |||
| // Global JACK client | |||
| extern jack_client_t* carla_jack_client; | |||
| // Global OSC stuff | |||
| extern OscData global_osc_data; | |||
| // jack.cpp | |||
| int carla_jack_process_callback(jack_nframes_t nframes, void* arg); | |||
| @@ -118,6 +125,11 @@ public: | |||
| param.port_cin = nullptr; | |||
| param.port_cout = nullptr; | |||
| osc.data.path = nullptr; | |||
| osc.data.source = nullptr; | |||
| osc.data.target = nullptr; | |||
| osc.thread = nullptr; | |||
| for (unsigned short i=0; i < MAX_POSTEVENTS; i++) | |||
| post_events.data[i].valid = false; | |||
| } | |||
| @@ -132,6 +144,11 @@ public: | |||
| // Delete data | |||
| delete_buffers(); | |||
| osc.data.path = nullptr; | |||
| osc.data.source = nullptr; | |||
| osc.data.target = nullptr; | |||
| osc.thread = nullptr; | |||
| lib_close(); | |||
| if (m_name) | |||
| @@ -179,42 +196,54 @@ public: | |||
| return 0; | |||
| } | |||
| uint32_t ain_count() | |||
| { | |||
| return ain.count; | |||
| } | |||
| uint32_t aout_count() | |||
| { | |||
| return aout.count; | |||
| } | |||
| uint32_t param_count() | |||
| { | |||
| return param.count; | |||
| } | |||
| ParameterData* param_data(uint32_t index) | |||
| virtual uint32_t prog_count() | |||
| { | |||
| return ¶m.data[index]; | |||
| return 0; | |||
| } | |||
| ParameterRanges* param_ranges(uint32_t index) | |||
| virtual uint32_t midiprog_count() | |||
| { | |||
| return ¶m.ranges[index]; | |||
| return 0; | |||
| } | |||
| virtual uint32_t param_scalepoint_count(uint32_t index) | |||
| virtual uint32_t param_scalepoint_count(uint32_t) | |||
| { | |||
| Q_UNUSED(index); | |||
| return 0; | |||
| } | |||
| virtual double param_scalepoint_value(uint32_t pindex, uint32_t index) | |||
| virtual double param_scalepoint_value(uint32_t, uint32_t) | |||
| { | |||
| Q_UNUSED(index); | |||
| Q_UNUSED(pindex); | |||
| return 0.0; | |||
| } | |||
| virtual uint32_t prog_count() | |||
| ParameterData* param_data(uint32_t index) | |||
| { | |||
| return 0; | |||
| return ¶m.data[index]; | |||
| } | |||
| virtual uint32_t midiprog_count() | |||
| ParameterRanges* param_ranges(uint32_t index) | |||
| { | |||
| return 0; | |||
| return ¶m.ranges[index]; | |||
| } | |||
| OscData* osc_data() | |||
| { | |||
| return &osc.data; | |||
| } | |||
| virtual void get_label(char* buf_str) | |||
| @@ -298,6 +327,11 @@ public: | |||
| info->label = nullptr; | |||
| } | |||
| virtual void get_gui_info(GuiInfo* info) | |||
| { | |||
| info->type = GUI_NONE; | |||
| } | |||
| virtual int32_t get_chunk_data(void** data_ptr) | |||
| { | |||
| Q_UNUSED(data_ptr); | |||
| @@ -316,10 +350,10 @@ public: | |||
| if (osc_send) | |||
| { | |||
| //osc_send_set_parameter_value(&global_osc_data, id, PARAMETER_ACTIVE, value); | |||
| osc_send_set_parameter_value(&global_osc_data, m_id, PARAMETER_ACTIVE, value); | |||
| //if (hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(&osc.data, PARAMETER_ACTIVE, value); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_control(&osc.data, PARAMETER_ACTIVE, value); | |||
| } | |||
| if (callback_send) | |||
| @@ -337,10 +371,10 @@ public: | |||
| if (osc_send) | |||
| { | |||
| //osc_send_set_parameter_value(&global_osc_data, id, PARAMETER_DRYWET, value); | |||
| osc_send_set_parameter_value(&global_osc_data, m_id, PARAMETER_DRYWET, value); | |||
| //if (hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(&osc.data, PARAMETER_DRYWET, value); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_control(&osc.data, PARAMETER_DRYWET, value); | |||
| } | |||
| if (callback_send) | |||
| @@ -358,10 +392,10 @@ public: | |||
| if (osc_send) | |||
| { | |||
| //osc_send_set_parameter_value(&global_osc_data, id, PARAMETER_VOLUME, value); | |||
| osc_send_set_parameter_value(&global_osc_data, m_id, PARAMETER_VOLUME, value); | |||
| //if (hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(&osc.data, PARAMETER_VOLUME, value); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_control(&osc.data, PARAMETER_VOLUME, value); | |||
| } | |||
| if (callback_send) | |||
| @@ -379,10 +413,10 @@ public: | |||
| if (osc_send) | |||
| { | |||
| //osc_send_set_parameter_value(&global_osc_data, id, PARAMETER_BALANCE_LEFT, value); | |||
| osc_send_set_parameter_value(&global_osc_data, m_id, PARAMETER_BALANCE_LEFT, value); | |||
| //if (hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(&osc.data, PARAMETER_BALANCE_LEFT, value); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_control(&osc.data, PARAMETER_BALANCE_LEFT, value); | |||
| } | |||
| if (callback_send) | |||
| @@ -400,10 +434,10 @@ public: | |||
| if (osc_send) | |||
| { | |||
| //osc_send_set_parameter_value(&global_osc_data, id, PARAMETER_BALANCE_RIGHT, value); | |||
| osc_send_set_parameter_value(&global_osc_data, m_id, PARAMETER_BALANCE_RIGHT, value); | |||
| //if (hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(&osc.data, PARAMETER_BALANCE_RIGHT, value); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_control(&osc.data, PARAMETER_BALANCE_RIGHT, value); | |||
| } | |||
| if (callback_send) | |||
| @@ -415,63 +449,97 @@ public: | |||
| return param.ranges[index].def; | |||
| } | |||
| virtual double get_current_parameter_value(uint32_t index) | |||
| virtual double get_current_parameter_value(uint32_t) | |||
| { | |||
| //if (plugin->param.data[parameter_id].hints & PARAMETER_HAS_STRICT_BOUNDS) | |||
| // plugin->fix_parameter_value(value, plugin->param.ranges[parameter_id]); | |||
| Q_UNUSED(index); | |||
| return 0.0; | |||
| } | |||
| virtual void set_parameter_value(uint32_t index, double value, bool gui_send, bool osc_send, bool callback_send) | |||
| { | |||
| //fix_parameter_value(value, param.ranges[parameter_id]); | |||
| if (osc_send) | |||
| { | |||
| //osc_send_set_parameter_value(&global_osc_data, id, parameter_id, value); | |||
| osc_send_set_parameter_value(&global_osc_data, m_id, index, value); | |||
| //if (hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(&osc.data, parameter_id, value); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_control(&osc.data, index, value); | |||
| } | |||
| if (callback_send) | |||
| callback_action(CALLBACK_PARAMETER_CHANGED, m_id, index, 0, value); | |||
| Q_UNUSED(gui_send); | |||
| //x_set_parameter_value(parameter_id, value, gui_send); | |||
| } | |||
| void set_parameter_midi_channel(uint32_t index, uint8_t channel) | |||
| { | |||
| param.data[index].midi_channel = channel; | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_set_parameter_midi_channel(&plugin->osc.data, plugin->id, parameter_id, channel); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_set_parameter_midi_channel(&osc.data, m_id, index, channel); | |||
| } | |||
| void set_parameter_midi_cc(uint32_t index, int16_t midi_cc) | |||
| { | |||
| param.data[index].midi_cc = midi_cc; | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_set_parameter_midi_cc(&plugin->osc.data, plugin->id, parameter_id, midi_cc); | |||
| if (m_hints & PLUGIN_IS_BRIDGE) | |||
| osc_send_set_parameter_midi_cc(&osc.data, m_id, index, midi_cc); | |||
| } | |||
| virtual void set_custom_data(const char* type, const char* key, const char* value, bool gui_send) | |||
| { | |||
| //bool save_data = true; | |||
| //bool already_have = false; | |||
| // switch (dtype) | |||
| // { | |||
| // case CUSTOM_DATA_INVALID: | |||
| // save_data = false; | |||
| // break; | |||
| // case CUSTOM_DATA_STRING: | |||
| // // Ignore OSC keys | |||
| // if (QString(key).startsWith("OSC:", Qt::CaseSensitive)) | |||
| // save_data = false; | |||
| // break; | |||
| // default: | |||
| // break; | |||
| // } | |||
| // if (save_data) | |||
| // { | |||
| // Check if we already have this key | |||
| //for (int i=0; i < custom.count(); i++) | |||
| //{ | |||
| // if (strcmp(custom[i].key, key) == 0) | |||
| // { | |||
| // free((void*)custom[i].value); | |||
| // custom[i].value = strdup(value); | |||
| // already_have = true; | |||
| // break; | |||
| // } | |||
| //} | |||
| //if (already_have == false) | |||
| //{ | |||
| // CustomData new_data; | |||
| // new_data.type = dtype; | |||
| // new_data.key = strdup(key); | |||
| // new_data.value = strdup(value); | |||
| // custom.append(new_data); | |||
| //} | |||
| // } | |||
| } | |||
| virtual void set_chunk_data(const char* string_data) | |||
| virtual void set_chunk_data(const char*) | |||
| { | |||
| Q_UNUSED(string_data); | |||
| } | |||
| virtual void set_gui_data(int data, void* ptr) | |||
| virtual void set_gui_data(int, void*) | |||
| { | |||
| Q_UNUSED(data); | |||
| Q_UNUSED(ptr); | |||
| } | |||
| virtual void show_gui(bool yesno) | |||
| virtual void show_gui(bool) | |||
| { | |||
| Q_UNUSED(yesno); | |||
| } | |||
| virtual void idle_gui() | |||
| @@ -482,31 +550,90 @@ public: | |||
| { | |||
| } | |||
| virtual void reload_programs(bool init) | |||
| virtual void reload_programs(bool) | |||
| { | |||
| Q_UNUSED(init); | |||
| } | |||
| virtual void prepare_for_save() | |||
| { | |||
| } | |||
| virtual void process(jack_nframes_t nframes) | |||
| virtual void process(jack_nframes_t) | |||
| { | |||
| Q_UNUSED(nframes); | |||
| } | |||
| virtual void buffer_size_changed(jack_nframes_t new_buffer_size) | |||
| virtual void buffer_size_changed(jack_nframes_t) | |||
| { | |||
| Q_UNUSED(new_buffer_size); | |||
| } | |||
| // virtual int set_osc_bridge_info(PluginOscBridgeInfoType, lo_arg**) = 0; | |||
| void update_osc_data(lo_address source, const char* url) | |||
| { | |||
| const char* host; | |||
| const char* port; | |||
| osc_clear_data(&osc.data); | |||
| host = lo_address_get_hostname(source); | |||
| port = lo_address_get_port(source); | |||
| osc.data.source = lo_address_new(host, port); | |||
| host = lo_url_get_hostname(url); | |||
| port = lo_url_get_port(url); | |||
| osc.data.path = lo_url_get_path(url); | |||
| osc.data.target = lo_address_new(host, port); | |||
| free((void*)host); | |||
| free((void*)port); | |||
| //for (int i=0; i < plugin->custom.count(); i++) | |||
| //{ | |||
| // if (plugin->custom[i].type == CUSTOM_DATA_STRING) | |||
| // osc_send_configure(&plugin->osc.data, plugin->custom[i].key, plugin->custom[i].value); | |||
| //} | |||
| //if (plugin->prog.current >= 0) | |||
| // osc_send_program(&plugin->osc.data, plugin->prog.current); | |||
| // virtual void x_set_parameter_value(uint32_t parameter_id, double value, bool gui_send) = 0; | |||
| // virtual void x_set_program(uint32_t program_id, bool gui_send, bool block) = 0; | |||
| // virtual void x_set_midi_program(uint32_t midi_program_id, bool gui_send, bool block) = 0; | |||
| // virtual void x_set_custom_data(CustomDataType dtype, const char* key, const char* value, bool gui_send) = 0; | |||
| //if (plugin->midiprog.current >= 0) | |||
| //{ | |||
| // int32_t midi_id = plugin->midiprog.current; | |||
| // osc_send_midi_program(&plugin->osc.data, plugin->midiprog.data[midi_id].bank, plugin->midiprog.data[midi_id].program); | |||
| // if (plugin->type == PLUGIN_DSSI) | |||
| // osc_send_program_as_midi(&plugin->osc.data, plugin->midiprog.data[midi_id].bank, plugin->midiprog.data[midi_id].program); | |||
| //} | |||
| for (uint32_t i=0; i < param.count; i++) | |||
| osc_send_control(&osc.data, param.data[i].rindex, get_current_parameter_value(i)); | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| //{ | |||
| // osc_send_control(&plugin->osc.data, PARAMETER_ACTIVE, plugin->active ? 1.0 : 0.0); | |||
| // osc_send_control(&plugin->osc.data, PARAMETER_DRYWET, plugin->x_drywet); | |||
| // osc_send_control(&plugin->osc.data, PARAMETER_VOLUME, plugin->x_vol); | |||
| // osc_send_control(&plugin->osc.data, PARAMETER_BALANCE_LEFT, plugin->x_bal_left); | |||
| // osc_send_control(&plugin->osc.data, PARAMETER_BALANCE_RIGHT, plugin->x_bal_right); | |||
| //} | |||
| } | |||
| bool update_osc_gui() | |||
| { | |||
| // wait for UI 'update' call; 40 re-tries, 4 secs | |||
| for (short i=1; i<40; i++) | |||
| { | |||
| if (osc.data.target) | |||
| { | |||
| osc_send_show(&osc.data); | |||
| return true; | |||
| } | |||
| else | |||
| // 100 ms | |||
| usleep(100000); | |||
| } | |||
| return false; | |||
| } | |||
| void postpone_event(PluginPostEventType type, int32_t index, double value) | |||
| { | |||
| @@ -720,6 +847,11 @@ protected: | |||
| PluginParameterData param; | |||
| // Extra | |||
| struct { | |||
| OscData data; | |||
| CarlaPluginThread* thread; | |||
| } osc; | |||
| struct { | |||
| QMutex lock; | |||
| PluginPostEvent data[MAX_POSTEVENTS]; | |||
| @@ -16,6 +16,7 @@ | |||
| */ | |||
| #include "carla_threads.h" | |||
| #include "carla_plugin.h" | |||
| #include <QtCore/QProcess> | |||
| @@ -34,6 +35,7 @@ void CarlaCheckThread::run() | |||
| qDebug("CarlaCheckThread::run()"); | |||
| uint32_t j; | |||
| double value; | |||
| PluginPostEvent post_events[MAX_POSTEVENTS]; | |||
| while (carla_is_engine_running()) | |||
| @@ -61,54 +63,59 @@ void CarlaCheckThread::run() | |||
| break; | |||
| case PostEventParameterChange: | |||
| //osc_send_set_parameter_value(&global_osc_data, plugin->id, post_events[j].index, post_events[j].value); | |||
| osc_send_set_parameter_value(&global_osc_data, plugin->id(), post_events[j].index, post_events[j].value); | |||
| callback_action(CALLBACK_PARAMETER_CHANGED, plugin->id(), post_events[j].index, 0, post_events[j].value); | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(&plugin->osc.data, post_events[j].index, post_events[j].value); | |||
| // FIXME - can this happen? | |||
| //if (plugin->hints() & PLUGIN_IS_BRIDGE) | |||
| // osc_send_control(plugin->osc_data(), post_events[j].index, post_events[j].value); | |||
| break; | |||
| case PostEventProgramChange: | |||
| //osc_send_set_program(&global_osc_data, plugin->id, post_events[j].index); | |||
| osc_send_set_program(&global_osc_data, plugin->id(), post_events[j].index); | |||
| callback_action(CALLBACK_PROGRAM_CHANGED, plugin->id(), post_events[j].index, 0, 0.0); | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_program(&plugin->osc.data, post_events[j].index); | |||
| // FIXME - can this happen? | |||
| //if (plugin->hints() & PLUGIN_IS_BRIDGE) | |||
| // osc_send_program(plugin->osc_data(), post_events[j].index); | |||
| //for (uint32_t k=0; k < plugin->param.count; k++) | |||
| // osc_send_set_default_value(&global_osc_data, plugin->id, k, plugin->param.ranges[k].def); | |||
| for (uint32_t k=0; k < plugin->param_count(); k++) | |||
| osc_send_set_default_value(&global_osc_data, plugin->id(), k, plugin->param_ranges(k)->def); | |||
| break; | |||
| case PostEventMidiProgramChange: | |||
| //osc_send_set_midi_program(&global_osc_data, plugin->id, post_events[j].index); | |||
| osc_send_set_midi_program(&global_osc_data, plugin->id(), post_events[j].index); | |||
| callback_action(CALLBACK_MIDI_PROGRAM_CHANGED, plugin->id(), post_events[j].index, 0, 0.0); | |||
| //if (plugin->type == PLUGIN_DSSI) | |||
| // osc_send_program_as_midi(&plugin->osc.data, plugin->midiprog.data[post_events[j].index].bank, plugin->midiprog.data[post_events[j].index].program); | |||
| //if (plugin->type() == PLUGIN_DSSI) | |||
| // osc_send_program_as_midi(plugin->osc_data(), plugin->midiprog.data[post_events[j].index].bank, plugin->midiprog.data[post_events[j].index].program); | |||
| // FIXME - can this happen? | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_midi_program(&plugin->osc.data, plugin->midiprog.data[post_events[j].index].bank, plugin->midiprog.data[post_events[j].index].program); | |||
| //for (uint32_t k=0; k < plugin->param.count; k++) | |||
| // osc_send_set_default_value(&global_osc_data, plugin->id, k, plugin->param.ranges[k].def); | |||
| for (uint32_t k=0; k < plugin->param_count(); k++) | |||
| osc_send_set_default_value(&global_osc_data, plugin->id(), k, plugin->param_ranges(k)->def); | |||
| break; | |||
| case PostEventNoteOn: | |||
| //osc_send_note_on(&global_osc_data, plugin->id, post_events[j].index, post_events[j].value); | |||
| osc_send_note_on(&global_osc_data, plugin->id(), post_events[j].index, post_events[j].value); | |||
| callback_action(CALLBACK_NOTE_ON, plugin->id(), post_events[j].index, post_events[j].value, 0.0); | |||
| // FIXME - can this happen? | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_note_on(&plugin->osc.data, plugin->id, post_events[j].index, post_events[j].value); | |||
| break; | |||
| case PostEventNoteOff: | |||
| //osc_send_note_off(&global_osc_data, plugin->id, post_events[j].index, 0); | |||
| osc_send_note_off(&global_osc_data, plugin->id(), post_events[j].index); | |||
| callback_action(CALLBACK_NOTE_OFF, plugin->id(), post_events[j].index, 0, 0.0); | |||
| // FIXME - can this happen? | |||
| //if (plugin->hints & PLUGIN_IS_BRIDGE) | |||
| // osc_send_note_off(&plugin->osc.data, plugin->id, post_events[j].index, 0); | |||
| @@ -120,47 +127,45 @@ void CarlaCheckThread::run() | |||
| } | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Idle plugin | |||
| // if (plugin->gui.visible && plugin->gui.type != GUI_EXTERNAL_OSC) | |||
| // plugin->idle_gui(); | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Update ports | |||
| // Check if it needs update | |||
| // bool update_ports_gui = (plugin->gui.visible && plugin->gui.type == GUI_EXTERNAL_OSC && plugin->osc.data.target); | |||
| bool update_ports_gui = (plugin->osc_data()->target != nullptr); | |||
| // if (!global_osc_data.target && !update_ports_gui) | |||
| // continue; | |||
| if (global_osc_data.target == nullptr && update_ports_gui == false) | |||
| continue; | |||
| // // Update | |||
| // for (j=0; j < plugin->param.count; j++) | |||
| // { | |||
| // if (plugin->param.data[j].type == PARAMETER_OUTPUT && (plugin->param.data[j].hints & PARAMETER_IS_AUTOMABLE) > 0) | |||
| // { | |||
| // if (update_ports_gui) | |||
| // osc_send_control(&plugin->osc.data, plugin->param.data[j].rindex, plugin->param.buffers[j]); | |||
| // Update | |||
| for (j=0; j < plugin->param_count(); j++) | |||
| { | |||
| if (plugin->param_data(j)->type == PARAMETER_OUTPUT && (plugin->param_data(j)->hints & PARAMETER_IS_AUTOMABLE) > 0) | |||
| { | |||
| value = plugin->get_current_parameter_value(j); | |||
| if (update_ports_gui) | |||
| osc_send_control(plugin->osc_data(), plugin->param_data(j)->rindex, value); | |||
| // osc_send_set_parameter_value(&global_osc_data, plugin->id, j, plugin->param.buffers[j]); | |||
| // } | |||
| // } | |||
| osc_send_set_parameter_value(&global_osc_data, plugin->id(), j, value); | |||
| } | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Send peak values (OSC) | |||
| // if (global_osc_data.target) | |||
| // { | |||
| // if (plugin->ain.count > 0) | |||
| // { | |||
| // osc_send_set_input_peak_value(&global_osc_data, plugin->id, 1, ains_peak[(plugin->id*2)+0]); | |||
| // osc_send_set_input_peak_value(&global_osc_data, plugin->id, 2, ains_peak[(plugin->id*2)+1]); | |||
| // } | |||
| // if (plugin->aout.count > 0) | |||
| // { | |||
| // osc_send_set_output_peak_value(&global_osc_data, plugin->id, 1, aouts_peak[(plugin->id*2)+0]); | |||
| // osc_send_set_output_peak_value(&global_osc_data, plugin->id, 2, aouts_peak[(plugin->id*2)+1]); | |||
| // } | |||
| // } | |||
| if (global_osc_data.target) | |||
| { | |||
| if (plugin->ain_count() > 0) | |||
| { | |||
| osc_send_set_input_peak_value(&global_osc_data, plugin->id(), 1, ains_peak[ (plugin->id() * 2) + 0 ]); | |||
| osc_send_set_input_peak_value(&global_osc_data, plugin->id(), 2, ains_peak[ (plugin->id() * 2) + 1 ]); | |||
| } | |||
| if (plugin->aout_count() > 0) | |||
| { | |||
| osc_send_set_output_peak_value(&global_osc_data, plugin->id(), 1, aouts_peak[ (plugin->id() * 2) + 0 ]); | |||
| osc_send_set_output_peak_value(&global_osc_data, plugin->id(), 2, aouts_peak[ (plugin->id() * 2) + 1 ]); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| usleep(50000); // 50 ms | |||
| @@ -170,24 +175,80 @@ void CarlaCheckThread::run() | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // CarlaPluginThread | |||
| CarlaPluginThread::CarlaPluginThread(QObject *parent) : | |||
| QThread(parent) | |||
| CarlaPluginThread::CarlaPluginThread(CarlaPlugin* plugin, PluginThreadMode mode) : | |||
| QThread (nullptr), | |||
| m_plugin (plugin), | |||
| m_mode (mode) | |||
| { | |||
| qDebug("CarlaPluginThread::CarlaPluginThread(%p)", parent); | |||
| //m_process = new QProcess(parent); | |||
| qDebug("CarlaPluginThread::CarlaPluginThread(%p, %i)", plugin, mode); | |||
| //m_binary = nullptr; | |||
| //m_label = nullptr; | |||
| //m_run_now = false; | |||
| m_process = new QProcess(nullptr); | |||
| } | |||
| CarlaPluginThread::~CarlaPluginThread() | |||
| { | |||
| // TODO - kill process | |||
| //delete m_process; | |||
| delete m_process; | |||
| } | |||
| void CarlaPluginThread::set_plugin(CarlaPlugin* plugin) | |||
| void CarlaPluginThread::setOscData(const char* binary, const char* label) | |||
| { | |||
| m_plugin = plugin; | |||
| m_binary = QString(binary); | |||
| m_label = QString(label); | |||
| } | |||
| void CarlaPluginThread::run() | |||
| { | |||
| QStringList arguments; | |||
| switch (m_mode) | |||
| { | |||
| case PLUGIN_THREAD_DSSI_GUI: | |||
| arguments << QString("%1/%2").arg(get_host_osc_url()).arg(m_plugin->id()); | |||
| arguments << m_plugin->filename(); | |||
| arguments << m_label; | |||
| arguments << QString("%1 (GUI)").arg(m_plugin->name()); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| m_process->start(m_binary, arguments); | |||
| m_process->waitForStarted(); | |||
| switch (m_mode) | |||
| { | |||
| case PLUGIN_THREAD_DSSI_GUI: | |||
| if (m_plugin->update_osc_gui()) | |||
| { | |||
| m_process->waitForFinished(-1); | |||
| if (m_process->exitCode() == 0) | |||
| { | |||
| // Hide | |||
| callback_action(CALLBACK_SHOW_GUI, m_plugin->id(), 0, 0, 0.0); | |||
| qWarning("CarlaPluginThread::run() - GUI closed"); | |||
| } | |||
| else | |||
| { | |||
| // Kill | |||
| callback_action(CALLBACK_SHOW_GUI, m_plugin->id(), -1, 0, 0.0); | |||
| qWarning("CarlaPluginThread::run() - GUI crashed"); | |||
| break; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| qDebug("CarlaPluginThread::run() - GUI timeout"); | |||
| callback_action(CALLBACK_SHOW_GUI, m_plugin->id(), 0, 0, 0.0); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| @@ -39,14 +39,26 @@ public: | |||
| class CarlaPluginThread : public QThread | |||
| { | |||
| public: | |||
| CarlaPluginThread(QObject* parent=0); | |||
| enum PluginThreadMode { | |||
| PLUGIN_THREAD_DSSI_GUI, | |||
| PLUGIN_THREAD_LV2_GUI_BRIDGE | |||
| }; | |||
| CarlaPluginThread(CarlaPlugin* plugin, PluginThreadMode mode); | |||
| ~CarlaPluginThread(); | |||
| void set_plugin(CarlaPlugin* plugin); | |||
| void run(); | |||
| void setOscData(const char* binary, const char* label); | |||
| protected: | |||
| virtual void run(); | |||
| private: | |||
| CarlaPlugin* m_plugin; | |||
| PluginThreadMode m_mode; | |||
| QString m_binary; | |||
| QString m_label; | |||
| QProcess* m_process; | |||
| }; | |||
| @@ -16,6 +16,932 @@ | |||
| */ | |||
| #include "carla_plugin.h" | |||
| #include "carla_osc.h" | |||
| #include "carla_threads.h" | |||
| #include "dssi/dssi.h" | |||
| #include <QtCore/QByteArray> | |||
| #include <QtCore/QString> | |||
| class DssiPlugin : public CarlaPlugin | |||
| { | |||
| public: | |||
| DssiPlugin() : | |||
| CarlaPlugin() | |||
| { | |||
| qDebug("DssiPlugin::DssiPlugin()"); | |||
| m_type = PLUGIN_DSSI; | |||
| handle = nullptr; | |||
| descriptor = nullptr; | |||
| ldescriptor = nullptr; | |||
| memset(&midi_events, 0, sizeof(snd_seq_event_t)*MAX_MIDI_EVENTS); | |||
| } | |||
| virtual ~DssiPlugin() | |||
| { | |||
| qDebug("DssiPlugin::~DssiPlugin()"); | |||
| // close UI | |||
| if (m_hints & PLUGIN_HAS_GUI) | |||
| { | |||
| if (osc.data.path) | |||
| { | |||
| osc_send_hide(&osc.data); | |||
| osc_send_quit(&osc.data); | |||
| } | |||
| if (osc.thread) | |||
| { | |||
| if (osc.thread->isRunning()) | |||
| { | |||
| osc.thread->quit(); | |||
| if (osc.thread->wait(3000) == false) // 3 sec | |||
| qWarning("Failed to properly stop DSSI GUI thread"); | |||
| } | |||
| delete osc.thread; | |||
| } | |||
| osc_clear_data(&osc.data); | |||
| } | |||
| if (handle && ldescriptor->deactivate && m_active_before) | |||
| ldescriptor->deactivate(handle); | |||
| if (handle && ldescriptor->cleanup) | |||
| ldescriptor->cleanup(handle); | |||
| handle = nullptr; | |||
| descriptor = nullptr; | |||
| ldescriptor = nullptr; | |||
| } | |||
| virtual PluginCategory category() | |||
| { | |||
| if (min.count > 0 && aout.count > 0) | |||
| return PLUGIN_CATEGORY_SYNTH; | |||
| return PLUGIN_CATEGORY_NONE; | |||
| } | |||
| virtual long unique_id() | |||
| { | |||
| return ldescriptor->UniqueID; | |||
| } | |||
| virtual void get_label(char* buf_str) | |||
| { | |||
| strncpy(buf_str, ldescriptor->Label, STR_MAX); | |||
| } | |||
| virtual void get_maker(char* buf_str) | |||
| { | |||
| strncpy(buf_str, ldescriptor->Maker, STR_MAX); | |||
| } | |||
| virtual void get_copyright(char* buf_str) | |||
| { | |||
| strncpy(buf_str, ldescriptor->Copyright, STR_MAX); | |||
| } | |||
| virtual void get_real_name(char* buf_str) | |||
| { | |||
| strncpy(buf_str, ldescriptor->Name, STR_MAX); | |||
| } | |||
| virtual void get_parameter_name(uint32_t index, char* buf_str) | |||
| { | |||
| int32_t rindex = param.data[index].rindex; | |||
| strncpy(buf_str, ldescriptor->PortNames[rindex], STR_MAX); | |||
| } | |||
| virtual void get_gui_info(GuiInfo* info) | |||
| { | |||
| if (m_hints & PLUGIN_HAS_GUI) | |||
| info->type = GUI_EXTERNAL_OSC; | |||
| else | |||
| info->type = GUI_NONE; | |||
| } | |||
| virtual int32_t get_chunk_data(void** data_ptr) | |||
| { | |||
| unsigned long long_data_size = 0; | |||
| if (descriptor->get_custom_data(handle, data_ptr, &long_data_size)) | |||
| return long_data_size; | |||
| return 0; | |||
| } | |||
| virtual double get_current_parameter_value(uint32_t index) | |||
| { | |||
| return param_buffers[index]; | |||
| } | |||
| virtual void set_parameter_value(uint32_t index, double value, bool gui_send, bool osc_send, bool callback_send) | |||
| { | |||
| param_buffers[index] = value; | |||
| if (gui_send) | |||
| osc_send_control(&osc.data, param.data[index].rindex, value); | |||
| CarlaPlugin::set_parameter_value(index, value, gui_send, osc_send, callback_send); | |||
| } | |||
| virtual void set_custom_data(const char* type, const char* key, const char* value, bool gui_send) | |||
| { | |||
| descriptor->configure(handle, key, value); | |||
| if (gui_send) | |||
| osc_send_configure(&osc.data, key, value); | |||
| if (strcmp(key, "reloadprograms") == 0 || strcmp(key, "load") == 0 || strncmp(key, "patches", 7) == 0) | |||
| { | |||
| reload_programs(false); | |||
| } | |||
| else if (strcmp(key, "names") == 0) // Not in the API! | |||
| { | |||
| //if (prog.count > 0) | |||
| //{ | |||
| //osc_send_set_program_count(&global_osc_data, m_id, prog.count); | |||
| // // Parse names | |||
| // int j, k, last_str_n = 0; | |||
| // int str_len = strlen(value); | |||
| // char name[256]; | |||
| // for (uint32_t i=0; i < prog.count; i++) | |||
| // { | |||
| // for (j=0, k=last_str_n; j<256 && k+j<str_len; j++) | |||
| // { | |||
| // name[j] = value[k+j]; | |||
| // if (value[k+j] == ',') | |||
| // { | |||
| // name[j] = 0; | |||
| // last_str_n = k+j+1; | |||
| // free((void*)prog.names[i]); | |||
| // prog.names[i] = strdup(name); | |||
| // break; | |||
| // } | |||
| // } | |||
| // osc_send_set_program_name(&osc.data, id, i, prog.names[i]); | |||
| // } | |||
| // callback_action(CALLBACK_RELOAD_PROGRAMS, id, 0, 0, 0.0f); | |||
| //} | |||
| } | |||
| CarlaPlugin::set_custom_data(type, key, value, gui_send); | |||
| } | |||
| virtual void set_chunk_data(const char* string_data) | |||
| { | |||
| QByteArray chunk = QByteArray::fromBase64(string_data); | |||
| descriptor->set_custom_data(handle, chunk.data(), chunk.size()); | |||
| } | |||
| virtual void show_gui(bool yesno) | |||
| { | |||
| if (yesno) | |||
| { | |||
| osc.thread->start(); | |||
| } | |||
| else | |||
| { | |||
| osc_send_hide(&osc.data); | |||
| osc_send_quit(&osc.data); | |||
| osc_clear_data(&osc.data); | |||
| } | |||
| } | |||
| virtual void reload() | |||
| { | |||
| qDebug("DssiPlugin::reload()"); | |||
| short _id = m_id; | |||
| // Safely disable plugin for reload | |||
| carla_proc_lock(); | |||
| m_id = -1; | |||
| carla_proc_unlock(); | |||
| if (carla_options.global_jack_client == false && _id >= 0) | |||
| jack_deactivate(jack_client); | |||
| // Unregister previous jack ports | |||
| remove_from_jack(); | |||
| // Delete old data | |||
| delete_buffers(); | |||
| uint32_t ains, aouts, mins, params, j; | |||
| ains = aouts = mins = params = 0; | |||
| const unsigned long PortCount = ldescriptor->PortCount; | |||
| for (unsigned long i=0; i<PortCount; i++) | |||
| { | |||
| LADSPA_PortDescriptor PortType = ldescriptor->PortDescriptors[i]; | |||
| if (LADSPA_IS_PORT_AUDIO(PortType)) | |||
| { | |||
| if (LADSPA_IS_PORT_INPUT(PortType)) | |||
| ains += 1; | |||
| else if (LADSPA_IS_PORT_OUTPUT(PortType)) | |||
| aouts += 1; | |||
| } | |||
| else if (LADSPA_IS_PORT_CONTROL(PortType)) | |||
| params += 1; | |||
| } | |||
| if (descriptor->run_synth || descriptor->run_multiple_synths) | |||
| mins = 1; | |||
| if (ains > 0) | |||
| { | |||
| ain.rindexes = new uint32_t[ains]; | |||
| ain.ports = new jack_port_t*[ains]; | |||
| } | |||
| if (aouts > 0) | |||
| { | |||
| aout.rindexes = new uint32_t[aouts]; | |||
| aout.ports = new jack_port_t*[aouts]; | |||
| } | |||
| if (mins > 0) | |||
| { | |||
| min.ports = new jack_port_t*[mins]; | |||
| } | |||
| if (params > 0) | |||
| { | |||
| param.data = new ParameterData[params]; | |||
| param.ranges = new ParameterRanges[params]; | |||
| param_buffers = new float[params]; | |||
| } | |||
| const int port_name_size = jack_port_name_size(); | |||
| char port_name[port_name_size]; | |||
| bool needs_cin = false; | |||
| bool needs_cout = false; | |||
| for (unsigned long i=0; i<PortCount; i++) | |||
| { | |||
| LADSPA_PortDescriptor PortType = ldescriptor->PortDescriptors[i]; | |||
| LADSPA_PortRangeHint PortHint = ldescriptor->PortRangeHints[i]; | |||
| if (LADSPA_IS_PORT_AUDIO(PortType)) | |||
| { | |||
| if (carla_options.global_jack_client) | |||
| { | |||
| strcpy(port_name, m_name); | |||
| strcat(port_name, ":"); | |||
| strncat(port_name, ldescriptor->PortNames[i], port_name_size/2); | |||
| } | |||
| else | |||
| strncpy(port_name, ldescriptor->PortNames[i], port_name_size/2); | |||
| if (LADSPA_IS_PORT_INPUT(PortType)) | |||
| { | |||
| j = ain.count++; | |||
| ain.ports[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
| ain.rindexes[j] = i; | |||
| } | |||
| else if (LADSPA_IS_PORT_OUTPUT(PortType)) | |||
| { | |||
| j = aout.count++; | |||
| aout.ports[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
| aout.rindexes[j] = i; | |||
| needs_cin = true; | |||
| } | |||
| else | |||
| qWarning("WARNING - Got a broken Port (Audio, but not input or output)"); | |||
| } | |||
| else if (LADSPA_IS_PORT_CONTROL(PortType)) | |||
| { | |||
| j = param.count++; | |||
| param.data[j].index = j; | |||
| param.data[j].rindex = i; | |||
| param.data[j].hints = 0; | |||
| param.data[j].midi_channel = 0; | |||
| param.data[j].midi_cc = -1; | |||
| double min, max, def, step, step_small, step_large; | |||
| // min value | |||
| if (LADSPA_IS_HINT_BOUNDED_BELOW(PortHint.HintDescriptor)) | |||
| min = PortHint.LowerBound; | |||
| else | |||
| min = 0.0; | |||
| // max value | |||
| if (LADSPA_IS_HINT_BOUNDED_ABOVE(PortHint.HintDescriptor)) | |||
| max = PortHint.UpperBound; | |||
| else | |||
| max = 1.0; | |||
| if (min > max) | |||
| max = min; | |||
| else if (max < min) | |||
| min = max; | |||
| // default value | |||
| if (LADSPA_IS_HINT_HAS_DEFAULT(PortHint.HintDescriptor)) | |||
| { | |||
| switch (PortHint.HintDescriptor & LADSPA_HINT_DEFAULT_MASK) | |||
| { | |||
| case LADSPA_HINT_DEFAULT_MINIMUM: | |||
| def = min; | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_MAXIMUM: | |||
| def = max; | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_0: | |||
| def = 0.0; | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_1: | |||
| def = 1.0; | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_100: | |||
| def = 100.0; | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_440: | |||
| def = 440.0; | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_LOW: | |||
| if (LADSPA_IS_HINT_LOGARITHMIC(PortHint.HintDescriptor)) | |||
| def = exp((log(min)*0.75) + (log(max)*0.25)); | |||
| else | |||
| def = (min*0.75) + (max*0.25); | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_MIDDLE: | |||
| if (LADSPA_IS_HINT_LOGARITHMIC(PortHint.HintDescriptor)) | |||
| def = sqrt(min*max); | |||
| else | |||
| def = (min+max)/2; | |||
| break; | |||
| case LADSPA_HINT_DEFAULT_HIGH: | |||
| if (LADSPA_IS_HINT_LOGARITHMIC(PortHint.HintDescriptor)) | |||
| def = exp((log(min)*0.25) + (log(max)*0.75)); | |||
| else | |||
| def = (min*0.25) + (max*0.75); | |||
| break; | |||
| default: | |||
| if (min < 0.0 && max > 0.0) | |||
| def = 0.0; | |||
| else | |||
| def = min; | |||
| break; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // no default value | |||
| if (min < 0.0 && max > 0.0) | |||
| def = 0.0; | |||
| else | |||
| def = min; | |||
| } | |||
| if (def < min) | |||
| def = min; | |||
| else if (def > max) | |||
| def = max; | |||
| if (max - min <= 0.0) | |||
| { | |||
| qWarning("Broken plugin parameter -> max - min <= 0"); | |||
| max = min + 0.1; | |||
| } | |||
| if (LADSPA_IS_HINT_SAMPLE_RATE(PortHint.HintDescriptor)) | |||
| { | |||
| double sample_rate = get_sample_rate(); | |||
| min *= sample_rate; | |||
| max *= sample_rate; | |||
| def *= sample_rate; | |||
| param.data[j].hints |= PARAMETER_USES_SAMPLERATE; | |||
| } | |||
| if (LADSPA_IS_HINT_INTEGER(PortHint.HintDescriptor)) | |||
| { | |||
| step = 1.0; | |||
| step_small = 1.0; | |||
| step_large = 10.0; | |||
| } | |||
| else if (LADSPA_IS_HINT_TOGGLED(PortHint.HintDescriptor)) | |||
| { | |||
| step = max - min; | |||
| step_small = step; | |||
| step_large = step; | |||
| } | |||
| else | |||
| { | |||
| double range = max - min; | |||
| step = range/100.0; | |||
| step_small = range/1000.0; | |||
| step_large = range/10.0; | |||
| } | |||
| if (LADSPA_IS_PORT_INPUT(PortType)) | |||
| { | |||
| param.data[j].type = PARAMETER_INPUT; | |||
| param.data[j].hints |= PARAMETER_IS_ENABLED; | |||
| param.data[j].hints |= PARAMETER_IS_AUTOMABLE; | |||
| needs_cin = true; | |||
| // MIDI CC value | |||
| if (descriptor->get_midi_controller_for_port) | |||
| { | |||
| int cc = descriptor->get_midi_controller_for_port(handle, i); | |||
| if (DSSI_CONTROLLER_IS_SET(cc) && DSSI_IS_CC(cc)) | |||
| param.data[j].midi_cc = DSSI_CC_NUMBER(cc); | |||
| } | |||
| } | |||
| else if (LADSPA_IS_PORT_OUTPUT(PortType)) | |||
| { | |||
| param.data[j].type = PARAMETER_OUTPUT; | |||
| param.data[j].hints |= PARAMETER_IS_ENABLED; | |||
| if (strcmp(ldescriptor->PortNames[i], "latency") != 0 && strcmp(ldescriptor->PortNames[i], "_latency") != 0) | |||
| { | |||
| param.data[j].hints |= PARAMETER_IS_AUTOMABLE; | |||
| needs_cout = true; | |||
| } | |||
| else | |||
| { | |||
| // latency parameter | |||
| min = 0; | |||
| max = get_sample_rate(); | |||
| def = 0; | |||
| step = 1; | |||
| step_small = 1; | |||
| step_large = 1; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| param.data[j].type = PARAMETER_UNKNOWN; | |||
| qWarning("WARNING - Got a broken Port (Control, but not input or output)"); | |||
| } | |||
| param.ranges[j].min = min; | |||
| param.ranges[j].max = max; | |||
| param.ranges[j].def = def; | |||
| param.ranges[j].step = step; | |||
| param.ranges[j].step_small = step_small; | |||
| param.ranges[j].step_large = step_large; | |||
| // Start parameters in their default values | |||
| param_buffers[j] = def; | |||
| ldescriptor->connect_port(handle, i, ¶m_buffers[j]); | |||
| } | |||
| else | |||
| { | |||
| // Not Audio or Control | |||
| qCritical("ERROR - Got a broken Port (neither Audio or Control)"); | |||
| ldescriptor->connect_port(handle, i, nullptr); | |||
| } | |||
| } | |||
| if (needs_cin) | |||
| { | |||
| if (carla_options.global_jack_client) | |||
| { | |||
| strcpy(port_name, m_name); | |||
| strcat(port_name, ":control-in"); | |||
| } | |||
| else | |||
| strcpy(port_name, "control-in"); | |||
| param.port_cin = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
| } | |||
| if (needs_cout) | |||
| { | |||
| if (carla_options.global_jack_client) | |||
| { | |||
| strcpy(port_name, m_name); | |||
| strcat(port_name, ":control-out"); | |||
| } | |||
| else | |||
| strcpy(port_name, "control-out"); | |||
| param.port_cout = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||
| } | |||
| if (mins == 1) | |||
| { | |||
| if (carla_options.global_jack_client) | |||
| { | |||
| strcpy(port_name, m_name); | |||
| strcat(port_name, ":midi-in"); | |||
| } | |||
| else | |||
| strcpy(port_name, "midi-in"); | |||
| min.ports[0] = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
| } | |||
| ain.count = ains; | |||
| aout.count = aouts; | |||
| min.count = mins; | |||
| param.count = params; | |||
| // reload_programs(true); | |||
| // plugin checks | |||
| qDebug("Before: %i", m_hints); | |||
| m_hints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE); | |||
| qDebug("After: %i", m_hints); | |||
| if (min.count > 0 && aout.count > 0) | |||
| m_hints |= PLUGIN_IS_SYNTH; | |||
| if (/*carla_options.use_dssi_chunks &&*/ QString(ldescriptor->Name).endsWith(" VST", Qt::CaseSensitive)) | |||
| { | |||
| if (descriptor->get_custom_data && descriptor->set_custom_data) | |||
| m_hints |= PLUGIN_USES_CHUNKS; | |||
| } | |||
| if (aouts > 0 && (ains == aouts || ains == 1)) | |||
| m_hints |= PLUGIN_CAN_DRYWET; | |||
| if (aouts > 0) | |||
| m_hints |= PLUGIN_CAN_VOLUME; | |||
| if (aouts >= 2 && aouts%2 == 0) | |||
| m_hints |= PLUGIN_CAN_BALANCE; | |||
| carla_proc_lock(); | |||
| m_id = _id; | |||
| carla_proc_unlock(); | |||
| if (carla_options.global_jack_client == false) | |||
| jack_activate(jack_client); | |||
| } | |||
| virtual void process(jack_nframes_t nframes) | |||
| { | |||
| uint32_t i, k; | |||
| unsigned short plugin_id = m_id; | |||
| unsigned long midi_event_count = 0; | |||
| double ains_peak_tmp[2] = { 0.0 }; | |||
| double aouts_peak_tmp[2] = { 0.0 }; | |||
| jack_default_audio_sample_t* ains_buffer[ain.count]; | |||
| jack_default_audio_sample_t* aouts_buffer[aout.count]; | |||
| void* min_buffer; | |||
| for (i=0; i < ain.count; i++) | |||
| ains_buffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(ain.ports[i], nframes); | |||
| for (i=0; i < aout.count; i++) | |||
| aouts_buffer[i] = (jack_default_audio_sample_t*)jack_port_get_buffer(aout.ports[i], nframes); | |||
| if (min.count == 1) | |||
| min_buffer = jack_port_get_buffer(min.ports[0], nframes); | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Input VU | |||
| if (ain.count > 0) | |||
| { | |||
| short j2 = (ain.count == 1) ? 0 : 1; | |||
| for (k=0; k<nframes; k++) | |||
| { | |||
| if (ains_buffer[0][k] > ains_peak_tmp[0]) | |||
| ains_peak_tmp[0] = ains_buffer[0][k]; | |||
| if (ains_buffer[j2][k] > ains_peak_tmp[1]) | |||
| ains_peak_tmp[1] = ains_buffer[j2][k]; | |||
| } | |||
| } | |||
| CARLA_PROCESS_CONTINUE_CHECK; | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Parameters Input [Automation] | |||
| if (param.port_cin) | |||
| { | |||
| jack_default_audio_sample_t* pin_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cin, nframes); | |||
| jack_midi_event_t pin_event; | |||
| uint32_t n_pin_events = jack_midi_get_event_count(pin_buffer); | |||
| for (i=0; i<n_pin_events; i++) | |||
| { | |||
| if (jack_midi_event_get(&pin_event, pin_buffer, i) != 0) | |||
| break; | |||
| unsigned char channel = pin_event.buffer[0] & 0x0F; | |||
| unsigned char mode = pin_event.buffer[0] & 0xF0; | |||
| // Status change | |||
| if (mode == 0xB0) | |||
| { | |||
| unsigned char status = pin_event.buffer[1] & 0x7F; | |||
| unsigned char velo = pin_event.buffer[2] & 0x7F; | |||
| double value, velo_per = double(velo)/127; | |||
| // Control GUI stuff (channel 0 only) | |||
| if (channel == 0) | |||
| { | |||
| if (status == 0x78) | |||
| { | |||
| // All Sound Off | |||
| set_active(false, false, false); | |||
| postpone_event(PostEventParameterChange, PARAMETER_ACTIVE, 0.0); | |||
| break; | |||
| } | |||
| else if (status == 0x09 && (m_hints & PLUGIN_CAN_DRYWET) > 0) | |||
| { | |||
| // Dry/Wet (using '0x09', undefined) | |||
| set_drywet(velo_per, false, false); | |||
| postpone_event(PostEventParameterChange, PARAMETER_DRYWET, velo_per); | |||
| } | |||
| else if (status == 0x07 && (m_hints & PLUGIN_CAN_VOLUME) > 0) | |||
| { | |||
| // Volume | |||
| value = double(velo)/100; | |||
| set_volume(value, false, false); | |||
| postpone_event(PostEventParameterChange, PARAMETER_VOLUME, value); | |||
| } | |||
| else if (status == 0x08 && (m_hints & PLUGIN_CAN_BALANCE) > 0) | |||
| { | |||
| // Balance | |||
| double left, right; | |||
| value = (double(velo)-63.5)/63.5; | |||
| if (value < 0) | |||
| { | |||
| left = -1.0; | |||
| right = (value*2)+1.0; | |||
| } | |||
| else if (value > 0) | |||
| { | |||
| left = (value*2)-1.0; | |||
| right = 1.0; | |||
| } | |||
| else | |||
| { | |||
| left = -1.0; | |||
| right = 1.0; | |||
| } | |||
| set_balance_left(left, false, false); | |||
| set_balance_right(right, false, false); | |||
| postpone_event(PostEventParameterChange, PARAMETER_BALANCE_LEFT, left); | |||
| postpone_event(PostEventParameterChange, PARAMETER_BALANCE_RIGHT, right); | |||
| } | |||
| } | |||
| // Control plugin parameters | |||
| for (k=0; k < param.count; k++) | |||
| { | |||
| if (param.data[k].type == PARAMETER_INPUT && (param.data[k].hints & PARAMETER_IS_AUTOMABLE) > 0 && | |||
| param.data[k].midi_channel == channel && param.data[k].midi_cc == status) | |||
| { | |||
| value = (velo_per * (param.ranges[k].max - param.ranges[k].min)) + param.ranges[k].min; | |||
| set_parameter_value(k, value, false, false, false); | |||
| postpone_event(PostEventParameterChange, k, value); | |||
| } | |||
| } | |||
| } | |||
| // Program change | |||
| else if (mode == 0xC0) | |||
| { | |||
| // TODO | |||
| } | |||
| } | |||
| } // End of Parameters Input | |||
| CARLA_PROCESS_CONTINUE_CHECK; | |||
| // TODO - Midi Input | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Plugin processing | |||
| if (m_active) | |||
| { | |||
| if (m_active_before == false) | |||
| { | |||
| if (ldescriptor->activate) | |||
| ldescriptor->activate(handle); | |||
| } | |||
| for (i=0; i < ain.count; i++) | |||
| ldescriptor->connect_port(handle, ain.rindexes[i], ains_buffer[i]); | |||
| for (i=0; i < aout.count; i++) | |||
| ldescriptor->connect_port(handle, aout.rindexes[i], aouts_buffer[i]); | |||
| if (descriptor->run_synth) | |||
| { | |||
| descriptor->run_synth(handle, nframes, midi_events, midi_event_count); | |||
| } | |||
| else if (descriptor->run_multiple_synths) | |||
| { | |||
| snd_seq_event_t* dssi_events_ptr[] = { midi_events, nullptr }; | |||
| descriptor->run_multiple_synths(1, &handle, nframes, dssi_events_ptr, &midi_event_count); | |||
| } | |||
| else if (ldescriptor->run) | |||
| ldescriptor->run(handle, nframes); | |||
| } | |||
| else | |||
| { | |||
| if (m_active_before) | |||
| { | |||
| if (ldescriptor->deactivate) | |||
| ldescriptor->deactivate(handle); | |||
| } | |||
| } | |||
| CARLA_PROCESS_CONTINUE_CHECK; | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Post-processing (dry/wet, volume and balance) | |||
| if (m_active) | |||
| { | |||
| double bal_rangeL, bal_rangeR; | |||
| jack_default_audio_sample_t old_bal_left[nframes]; | |||
| for (i=0; i < aout.count; i++) | |||
| { | |||
| // Dry/Wet and Volume | |||
| for (k=0; k<nframes; k++) | |||
| { | |||
| if ((m_hints & PLUGIN_CAN_DRYWET) > 0 && x_drywet != 1.0) | |||
| { | |||
| if (aout.count == 1) | |||
| aouts_buffer[i][k] = (aouts_buffer[i][k]*x_drywet)+(ains_buffer[0][k]*(1.0-x_drywet)); | |||
| else | |||
| aouts_buffer[i][k] = (aouts_buffer[i][k]*x_drywet)+(ains_buffer[i][k]*(1.0-x_drywet)); | |||
| } | |||
| if (m_hints & PLUGIN_CAN_VOLUME) | |||
| aouts_buffer[i][k] *= x_vol; | |||
| } | |||
| // Balance | |||
| if (m_hints & PLUGIN_CAN_BALANCE) | |||
| { | |||
| if (i%2 == 0) | |||
| memcpy(&old_bal_left, aouts_buffer[i], sizeof(jack_default_audio_sample_t)*nframes); | |||
| bal_rangeL = (x_bal_left+1.0)/2; | |||
| bal_rangeR = (x_bal_right+1.0)/2; | |||
| for (k=0; k<nframes; k++) | |||
| { | |||
| if (i%2 == 0) | |||
| { | |||
| // left output | |||
| aouts_buffer[i][k] = old_bal_left[k]*(1.0-bal_rangeL); | |||
| aouts_buffer[i][k] += aouts_buffer[i+1][k]*(1.0-bal_rangeR); | |||
| } | |||
| else | |||
| { | |||
| // right | |||
| aouts_buffer[i][k] = aouts_buffer[i][k]*bal_rangeR; | |||
| aouts_buffer[i][k] += old_bal_left[k]*bal_rangeL; | |||
| } | |||
| } | |||
| } | |||
| // Output VU | |||
| if (i < 2) | |||
| { | |||
| for (k=0; k<nframes; k++) | |||
| { | |||
| if (aouts_buffer[i][k] > aouts_peak_tmp[i]) | |||
| aouts_peak_tmp[i] = aouts_buffer[i][k]; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // disable any output sound if not active | |||
| for (i=0; i < aout.count; i++) | |||
| memset(aouts_buffer[i], 0.0f, sizeof(jack_default_audio_sample_t)*nframes); | |||
| aouts_peak_tmp[0] = 0.0; | |||
| aouts_peak_tmp[1] = 0.0; | |||
| } // End of Post-processing | |||
| CARLA_PROCESS_CONTINUE_CHECK; | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Control Output | |||
| if (param.port_cout) | |||
| { | |||
| jack_default_audio_sample_t* cout_buffer = (jack_default_audio_sample_t*)jack_port_get_buffer(param.port_cout, nframes); | |||
| jack_midi_clear_buffer(cout_buffer); | |||
| double value_per; | |||
| for (k=0; k < param.count; k++) | |||
| { | |||
| if (param.data[k].type == PARAMETER_OUTPUT && param.data[k].midi_cc >= 0) | |||
| { | |||
| value_per = (param_buffers[k] - param.ranges[k].min)/(param.ranges[k].max - param.ranges[k].min); | |||
| jack_midi_data_t* event_buffer = jack_midi_event_reserve(cout_buffer, 0, 3); | |||
| event_buffer[0] = 0xB0 + param.data[k].midi_channel; | |||
| event_buffer[1] = param.data[k].midi_cc; | |||
| event_buffer[2] = 127*value_per; | |||
| } | |||
| } | |||
| } // End of Control Output | |||
| CARLA_PROCESS_CONTINUE_CHECK; | |||
| // -------------------------------------------------------------------------------------------------------- | |||
| // Peak Values | |||
| ains_peak[(plugin_id*2)+0] = ains_peak_tmp[0]; | |||
| ains_peak[(plugin_id*2)+1] = ains_peak_tmp[1]; | |||
| aouts_peak[(plugin_id*2)+0] = aouts_peak_tmp[0]; | |||
| aouts_peak[(plugin_id*2)+1] = aouts_peak_tmp[1]; | |||
| m_active_before = m_active; | |||
| } | |||
| bool init(const char* filename, const char* label, void* extra_stuff) | |||
| { | |||
| if (lib_open(filename)) | |||
| { | |||
| DSSI_Descriptor_Function descfn = (DSSI_Descriptor_Function)lib_symbol("dssi_descriptor"); | |||
| if (descfn) | |||
| { | |||
| unsigned long i = 0; | |||
| while ((descriptor = descfn(i++))) | |||
| { | |||
| ldescriptor = descriptor->LADSPA_Plugin; | |||
| if (strcmp(ldescriptor->Label, label) == 0) | |||
| break; | |||
| } | |||
| if (descriptor && ldescriptor) | |||
| { | |||
| handle = ldescriptor->instantiate(ldescriptor, get_sample_rate()); | |||
| if (handle) | |||
| { | |||
| m_filename = strdup(filename); | |||
| m_name = get_unique_name(ldescriptor->Name); | |||
| if (register_jack_plugin()) | |||
| { | |||
| if (extra_stuff) | |||
| { | |||
| // GUI Stuff | |||
| const char* gui_filename = (char*)extra_stuff; | |||
| osc.thread = new CarlaPluginThread(this, CarlaPluginThread::PLUGIN_THREAD_DSSI_GUI); | |||
| osc.thread->setOscData(gui_filename, ldescriptor->Label); | |||
| m_hints |= PLUGIN_HAS_GUI; | |||
| } | |||
| return true; | |||
| } | |||
| else | |||
| set_last_error("Failed to register plugin in JACK"); | |||
| } | |||
| else | |||
| set_last_error("Plugin failed to initialize"); | |||
| } | |||
| else | |||
| set_last_error("Could not find the requested plugin Label in the plugin library"); | |||
| } | |||
| else | |||
| set_last_error("Could not find the LASDPA Descriptor in the plugin library"); | |||
| } | |||
| else | |||
| set_last_error(lib_error()); | |||
| return false; | |||
| } | |||
| private: | |||
| LADSPA_Handle handle; | |||
| const LADSPA_Descriptor* ldescriptor; | |||
| const DSSI_Descriptor* descriptor; | |||
| float* param_buffers; | |||
| snd_seq_event_t midi_events[MAX_MIDI_EVENTS]; | |||
| }; | |||
| short add_plugin_dssi(const char* filename, const char* label, void* extra_stuff) | |||
| { | |||
| @@ -25,8 +951,23 @@ short add_plugin_dssi(const char* filename, const char* label, void* extra_stuff | |||
| if (id >= 0) | |||
| { | |||
| set_last_error("Not implemented yet"); | |||
| id = -1; | |||
| DssiPlugin* plugin = new DssiPlugin; | |||
| if (plugin->init(filename, label, extra_stuff)) | |||
| { | |||
| plugin->reload(); | |||
| plugin->set_id(id); | |||
| unique_names[id] = plugin->name(); | |||
| CarlaPlugins[id] = plugin; | |||
| //osc_new_plugin(plugin); | |||
| } | |||
| else | |||
| { | |||
| delete plugin; | |||
| id = -1; | |||
| } | |||
| } | |||
| else | |||
| set_last_error("Maximum number of plugins reached"); | |||
| @@ -582,7 +582,7 @@ public: | |||
| m_hints |= PLUGIN_CAN_DRYWET; | |||
| if (aouts > 0) | |||
| m_hints |= PLUGIN_CAN_VOL; | |||
| m_hints |= PLUGIN_CAN_VOLUME; | |||
| if (aouts >= 2 && aouts%2 == 0) | |||
| m_hints |= PLUGIN_CAN_BALANCE; | |||
| @@ -671,7 +671,7 @@ public: | |||
| set_drywet(velo_per, false, false); | |||
| postpone_event(PostEventParameterChange, PARAMETER_DRYWET, velo_per); | |||
| } | |||
| else if (status == 0x07 && (m_hints & PLUGIN_CAN_VOL) > 0) | |||
| else if (status == 0x07 && (m_hints & PLUGIN_CAN_VOLUME) > 0) | |||
| { | |||
| // Volume | |||
| value = double(velo)/100; | |||
| @@ -776,7 +776,7 @@ public: | |||
| aouts_buffer[i][k] = (aouts_buffer[i][k]*x_drywet)+(ains_buffer[i][k]*(1.0-x_drywet)); | |||
| } | |||
| if (m_hints & PLUGIN_CAN_VOL) | |||
| if (m_hints & PLUGIN_CAN_VOLUME) | |||
| aouts_buffer[i][k] *= x_vol; | |||
| } | |||
| @@ -17,6 +17,206 @@ | |||
| #include "carla_plugin.h" | |||
| #include "lv2/lv2.h" | |||
| #include "lv2/ui.h" | |||
| #include "lv2_rdf.h" | |||
| // static max values | |||
| const unsigned int MAX_EVENT_BUFFER = 0x7FFF; // 32767 | |||
| // feature ids | |||
| //const uint32_t lv2_feature_id_uri_map = 0; | |||
| //const uint32_t lv2_feature_id_urid_map = 1; | |||
| //const uint32_t lv2_feature_id_urid_unmap = 2; | |||
| //const uint32_t lv2_feature_id_event = 3; | |||
| //const uint32_t lv2_feature_id_rtmempool = 4; | |||
| //const uint32_t lv2_feature_id_data_access = 5; | |||
| //const uint32_t lv2_feature_id_instance_access = 6; | |||
| //const uint32_t lv2_feature_id_ui_resize = 7; | |||
| //const uint32_t lv2_feature_id_ui_parent = 8; | |||
| //const uint32_t lv2_feature_id_external_ui = 9; | |||
| //const uint32_t lv2_feature_id_external_ui_old = 10; | |||
| const uint32_t lv2_feature_count = 0; //11; | |||
| // extra plugin hints | |||
| const unsigned int PLUGIN_HAS_EXTENSION_STATE = 0x1000; | |||
| const unsigned int PLUGIN_HAS_EXTENSION_DYNPARAM = 0x2000; | |||
| class Lv2Plugin : public CarlaPlugin | |||
| { | |||
| public: | |||
| Lv2Plugin() : | |||
| CarlaPlugin() | |||
| { | |||
| qDebug("Lv2Plugin::Lv2Plugin()"); | |||
| m_type = PLUGIN_LV2; | |||
| handle = nullptr; | |||
| descriptor = nullptr; | |||
| rdf_descriptor = nullptr; | |||
| ui.lib = nullptr; | |||
| ui.handle = nullptr; | |||
| ui.descriptor = nullptr; | |||
| ui.rdf_descriptor = nullptr; | |||
| for (uint32_t i=0; i < lv2_feature_count+1; i++) | |||
| features[i] = nullptr; | |||
| } | |||
| virtual ~Lv2Plugin() | |||
| { | |||
| qDebug("Lv2Plugin::~Lv2Plugin()"); | |||
| if (handle && descriptor->deactivate && m_active_before) | |||
| descriptor->deactivate(handle); | |||
| if (handle && descriptor->cleanup) | |||
| descriptor->cleanup(handle); | |||
| //for (uint32_t i=0; i < lv2_feature_count && features[i]; i++) | |||
| // delete features[i]; | |||
| if (rdf_descriptor) | |||
| lv2_rdf_free(rdf_descriptor); | |||
| } | |||
| virtual PluginCategory category() | |||
| { | |||
| LV2_Property Category = rdf_descriptor->Type; | |||
| // Specific Types | |||
| if (Category & LV2_CLASS_REVERB) | |||
| return PLUGIN_CATEGORY_DELAY; | |||
| // Pre-set LV2 Types | |||
| else if (LV2_IS_GENERATOR(Category)) | |||
| return PLUGIN_CATEGORY_SYNTH; | |||
| else if (LV2_IS_UTILITY(Category)) | |||
| return PLUGIN_CATEGORY_UTILITY; | |||
| else if (LV2_IS_SIMULATOR(Category)) | |||
| return PLUGIN_CATEGORY_OUTRO; | |||
| else if (LV2_IS_DELAY(Category)) | |||
| return PLUGIN_CATEGORY_DELAY; | |||
| else if (LV2_IS_MODULATOR(Category)) | |||
| return PLUGIN_CATEGORY_MODULATOR; | |||
| else if (LV2_IS_FILTER(Category)) | |||
| return PLUGIN_CATEGORY_FILTER; | |||
| else if (LV2_IS_EQUALISER(Category)) | |||
| return PLUGIN_CATEGORY_EQ; | |||
| else if (LV2_IS_SPECTRAL(Category)) | |||
| return PLUGIN_CATEGORY_UTILITY; | |||
| else if (LV2_IS_DISTORTION(Category)) | |||
| return PLUGIN_CATEGORY_OUTRO; | |||
| else if (LV2_IS_DYNAMICS(Category)) | |||
| return PLUGIN_CATEGORY_DYNAMICS; | |||
| else | |||
| return PLUGIN_CATEGORY_NONE; | |||
| } | |||
| virtual long unique_id() | |||
| { | |||
| return rdf_descriptor->UniqueID; | |||
| } | |||
| void get_label(char* buf_str) | |||
| { | |||
| strncpy(buf_str, rdf_descriptor->URI, STR_MAX); | |||
| } | |||
| void get_maker(char* buf_str) | |||
| { | |||
| strncpy(buf_str, rdf_descriptor->Author, STR_MAX); | |||
| } | |||
| void get_copyright(char* buf_str) | |||
| { | |||
| strncpy(buf_str, rdf_descriptor->License, STR_MAX); | |||
| } | |||
| void get_real_name(char* buf_str) | |||
| { | |||
| strncpy(buf_str, rdf_descriptor->Name, STR_MAX); | |||
| } | |||
| bool init(const char* filename, const char* URI, void* extra_stuff) | |||
| { | |||
| LV2_RDF_Descriptor* rdf_descriptor_ = (LV2_RDF_Descriptor*)extra_stuff; | |||
| qDebug("INIT %s", URI); | |||
| if (rdf_descriptor_) | |||
| { | |||
| qDebug("INIT 002"); | |||
| if (lib_open(rdf_descriptor_->Binary)) | |||
| { | |||
| qDebug("INIT 003"); | |||
| LV2_Descriptor_Function descfn = (LV2_Descriptor_Function)lib_symbol("lv2_descriptor"); | |||
| if (descfn) | |||
| { | |||
| qDebug("INIT 004"); | |||
| uint32_t i = 0; | |||
| while ((descriptor = descfn(i++))) | |||
| { | |||
| qDebug("%s | %s", descriptor->URI, URI); | |||
| if (strcmp(descriptor->URI, URI) == 0) | |||
| break; | |||
| } | |||
| qDebug("INIT 005"); | |||
| if (descriptor) | |||
| { | |||
| // TODO - can continue | |||
| handle = descriptor->instantiate(descriptor, get_sample_rate(), rdf_descriptor_->Bundle, features); | |||
| if (handle) | |||
| { | |||
| m_filename = strdup(filename); | |||
| m_name = get_unique_name(rdf_descriptor_->Name); | |||
| rdf_descriptor = lv2_rdf_dup(rdf_descriptor_); | |||
| if (register_jack_plugin()) | |||
| return true; | |||
| else | |||
| set_last_error("Failed to register plugin in JACK"); | |||
| } | |||
| else | |||
| set_last_error("Plugin failed to initialize"); | |||
| } | |||
| else | |||
| set_last_error("Could not find the requested plugin URI in the plugin library"); | |||
| } | |||
| else | |||
| set_last_error("Could not find the LV2 Descriptor in the plugin library"); | |||
| } | |||
| else | |||
| set_last_error(lib_error()); | |||
| } | |||
| else | |||
| set_last_error("Failed to find the requested plugin in the LV2 Bundle"); | |||
| return false; | |||
| } | |||
| private: | |||
| LV2_Handle handle; | |||
| const LV2_Descriptor* descriptor; | |||
| const LV2_RDF_Descriptor* rdf_descriptor; | |||
| LV2_Feature* features[lv2_feature_count+1]; | |||
| struct { | |||
| void* lib; | |||
| LV2UI_Handle handle; | |||
| LV2UI_Widget widget; | |||
| const LV2UI_Descriptor* descriptor; | |||
| const LV2_RDF_UI* rdf_descriptor; | |||
| } ui; | |||
| }; | |||
| short add_plugin_lv2(const char* filename, const char* label, void* extra_stuff) | |||
| { | |||
| qDebug("add_plugin_lv2(%s, %s, %p)", filename, label, extra_stuff); | |||
| @@ -25,8 +225,23 @@ short add_plugin_lv2(const char* filename, const char* label, void* extra_stuff) | |||
| if (id >= 0) | |||
| { | |||
| set_last_error("Not implemented yet"); | |||
| id = -1; | |||
| Lv2Plugin* plugin = new Lv2Plugin; | |||
| if (plugin->init(filename, label, extra_stuff)) | |||
| { | |||
| plugin->reload(); | |||
| plugin->set_id(id); | |||
| unique_names[id] = plugin->name(); | |||
| CarlaPlugins[id] = plugin; | |||
| //osc_new_plugin(plugin); | |||
| } | |||
| else | |||
| { | |||
| delete plugin; | |||
| id = -1; | |||
| } | |||
| } | |||
| else | |||
| set_last_error("Maximum number of plugins reached"); | |||
| @@ -225,13 +225,15 @@ struct LV2_RDF_PresetPort { | |||
| #define LV2_PRESET_STATE_BOOL 0x1 | |||
| #define LV2_PRESET_STATE_INT 0x2 | |||
| #define LV2_PRESET_STATE_LONG 0x3 | |||
| #define LV2_PRESET_STATE_STRING 0x4 | |||
| #define LV2_PRESET_STATE_BINARY 0x5 | |||
| #define LV2_PRESET_STATE_FLOAT 0x4 | |||
| #define LV2_PRESET_STATE_STRING 0x5 | |||
| #define LV2_PRESET_STATE_BINARY 0x6 | |||
| #define LV2_IS_PRESET_STATE_NULL(x) ((x) == LV2_PRESET_STATE_NULL) | |||
| #define LV2_IS_PRESET_STATE_BOOL(x) ((x) == LV2_PRESET_STATE_BOOL) | |||
| #define LV2_IS_PRESET_STATE_INT(x) ((x) == LV2_PRESET_STATE_INT) | |||
| #define LV2_IS_PRESET_STATE_LONG(x) ((x) == LV2_PRESET_STATE_LONG) | |||
| #define LV2_IS_PRESET_STATE_FLOAT(x) ((x) == LV2_PRESET_STATE_FLOAT) | |||
| #define LV2_IS_PRESET_STATE_STRING(x) ((x) == LV2_PRESET_STATE_STRING) | |||
| #define LV2_IS_PRESET_STATE_BINARY(x) ((x) == LV2_PRESET_STATE_BINARY) | |||
| @@ -240,6 +242,7 @@ union LV2_RDF_PresetStateValue { | |||
| bool b; | |||
| int i; | |||
| long li; | |||
| float f; | |||
| const char* s; | |||
| }; | |||
| @@ -508,8 +511,32 @@ inline const LV2_RDF_Descriptor* lv2_rdf_dup(LV2_RDF_Descriptor* rdf_descriptor) | |||
| for (j=0; j < Preset->StateCount; j++) | |||
| { | |||
| Preset->States[j].Type = rdf_descriptor->Presets[i].States[j].Type; | |||
| Preset->States[j].Key = strdup(rdf_descriptor->Presets[i].States[j].Key); | |||
| Preset->States[j].Value = strdup(rdf_descriptor->Presets[i].States[j].Value); | |||
| switch (Preset->States[j].Type) | |||
| { | |||
| case LV2_PRESET_STATE_BOOL: | |||
| Preset->States[j].Value.b = rdf_descriptor->Presets[i].States[j].Value.b; | |||
| break; | |||
| case LV2_PRESET_STATE_INT: | |||
| Preset->States[j].Value.i = rdf_descriptor->Presets[i].States[j].Value.i; | |||
| break; | |||
| case LV2_PRESET_STATE_LONG: | |||
| Preset->States[j].Value.li = rdf_descriptor->Presets[i].States[j].Value.li; | |||
| break; | |||
| case LV2_PRESET_STATE_FLOAT: | |||
| Preset->States[j].Value.f = rdf_descriptor->Presets[i].States[j].Value.f; | |||
| break; | |||
| case LV2_PRESET_STATE_STRING: | |||
| case LV2_PRESET_STATE_BINARY: | |||
| Preset->States[j].Value.s = strdup(rdf_descriptor->Presets[i].States[j].Value.s); | |||
| break; | |||
| default: | |||
| // Invalid type | |||
| Preset->States[j].Type = LV2_PRESET_STATE_NULL; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| @@ -657,7 +684,9 @@ inline void lv2_rdf_free(const LV2_RDF_Descriptor* rdf_descriptor) | |||
| for (j=0; j < Preset->StateCount; j++) | |||
| { | |||
| free((void*)Preset->States[j].Key); | |||
| free((void*)Preset->States[j].Value); | |||
| if (Preset->States[j].Type == LV2_PRESET_STATE_STRING || Preset->States[j].Type == LV2_PRESET_STATE_BINARY) | |||
| free((void*)Preset->States[j].Value.s); | |||
| } | |||
| } | |||
| delete[] rdf_descriptor->Presets; | |||
| @@ -711,73 +740,73 @@ inline void lv2_rdf_free(const LV2_RDF_Descriptor* rdf_descriptor) | |||
| delete rdf_descriptor; | |||
| } | |||
| inline bool is_lv2_feature_supported(const char *uri) | |||
| inline bool is_lv2_feature_supported(const char* /*uri*/) | |||
| { | |||
| if (strcmp(uri, "http://lv2plug.in/ns/lv2core#hardRTCapable") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#inPlaceBroken") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#isLive") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/event") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#makePath") == 0) | |||
| return false; // TODO | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#mapPath") == 0) | |||
| return false; // TODO | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/uri-map") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#map") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#unmap") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://home.gna.org/lv2dynparam/rtmempool/v1") == 0) | |||
| return true; | |||
| else | |||
| // if (strcmp(uri, "http://lv2plug.in/ns/lv2core#hardRTCapable") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#inPlaceBroken") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#isLive") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/event") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#makePath") == 0) | |||
| // return false; // TODO | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#mapPath") == 0) | |||
| // return false; // TODO | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/uri-map") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#map") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#unmap") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://home.gna.org/lv2dynparam/rtmempool/v1") == 0) | |||
| // return true; | |||
| // else | |||
| return false; | |||
| } | |||
| inline bool is_lv2_ui_feature_supported(const char *uri) | |||
| inline bool is_lv2_ui_feature_supported(const char */*uri*/) | |||
| { | |||
| if (strcmp(uri, "http://lv2plug.in/ns/lv2core#hardRTCapable") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#inPlaceBroken") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#isLive") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/event") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#makePath") == 0) | |||
| return false; // TODO | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#mapPath") == 0) | |||
| return false; // TODO | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/uri-map") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#map") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#unmap") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/data-access") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/instance-access") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/ext/ui-resize") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#Events") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#makeResident") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#makeSONameResident") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#noUserResize") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#fixedSize") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#external") == 0) | |||
| return true; | |||
| else if (strcmp(uri, "http://nedko.arnaudov.name/lv2/external_ui/") == 0) | |||
| return true; | |||
| else | |||
| // if (strcmp(uri, "http://lv2plug.in/ns/lv2core#hardRTCapable") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#inPlaceBroken") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/lv2core#isLive") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/event") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#makePath") == 0) | |||
| // return false; // TODO | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/state#mapPath") == 0) | |||
| // return false; // TODO | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/uri-map") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#map") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/urid#unmap") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/data-access") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/instance-access") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/ext/ui-resize") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#Events") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#makeResident") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#makeSONameResident") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#noUserResize") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#fixedSize") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#external") == 0) | |||
| // return true; | |||
| // else if (strcmp(uri, "http://nedko.arnaudov.name/lv2/external_ui/") == 0) | |||
| // return true; | |||
| // else | |||
| return false; | |||
| } | |||
| @@ -1,16 +0,0 @@ | |||
| /* | |||
| * JACK Backend code for Carla | |||
| * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU General Public License as published by | |||
| * the Free Software Foundation; either version 2 of the License, or | |||
| * any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| @@ -1,16 +0,0 @@ | |||
| /* | |||
| * JACK Backend code for Carla | |||
| * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU General Public License as published by | |||
| * the Free Software Foundation; either version 2 of the License, or | |||
| * any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the COPYING file | |||
| */ | |||
| @@ -24,7 +24,7 @@ from subprocess import getoutput | |||
| # Imports (Custom) | |||
| try: | |||
| import ladspa_rdf | |||
| import ladspa_rdf, lv2_rdf | |||
| haveRDF = True | |||
| except: | |||
| print("RDF Support not available (LADSPA-RDF and LV2 will be disabled)") | |||
| @@ -496,65 +496,69 @@ def checkPluginVST(filename, tool, isWine=False): | |||
| def checkPluginSF2(filename, tool): | |||
| return runCarlaDiscovery(PLUGIN_SF2, "SF2", filename, tool) | |||
| #def checkPluginLV2(rdf_info): | |||
| #plugins = [] | |||
| #pinfo = deepcopy(PyPluginInfo) | |||
| #pinfo['type'] = PLUGIN_LV2 | |||
| #pinfo['category'] = PLUGIN_CATEGORY_NONE # TODO | |||
| #pinfo['hints'] = 0 | |||
| #pinfo['binary'] = rdf_info['Binary'] | |||
| #pinfo['name'] = rdf_info['Name'] | |||
| #pinfo['label'] = rdf_info['URI'] | |||
| #pinfo['maker'] = rdf_info['Author'] | |||
| #pinfo['copyright'] = rdf_info['License'] | |||
| #pinfo['id'] = str(rdf_info['UniqueID']) | |||
| #pinfo['audio.ins'] = 0 | |||
| #pinfo['audio.outs'] = 0 | |||
| #pinfo['audio.total'] = 0 | |||
| #pinfo['midi.ins'] = 0 | |||
| #pinfo['midi.outs'] = 0 | |||
| #pinfo['midi.total'] = 0 | |||
| #pinfo['parameters.ins'] = 0 | |||
| #pinfo['parameters.outs'] = 0 | |||
| #pinfo['parameters.total'] = 0 | |||
| #pinfo['programs.total'] = rdf_info['PresetCount'] | |||
| #if (not rdf_info['Bundle'] or pinfo['binary'] == "" or pinfo['name'] == ""): | |||
| #return None | |||
| #for i in range(rdf_info['PortCount']): | |||
| #PortType = rdf_info['Ports'][i]['Type'] | |||
| #PortProps = rdf_info['Ports'][i]['Properties'] | |||
| #if (PortType & lv2_rdf.LV2_PORT_AUDIO): | |||
| #pinfo['audio.total'] += 1 | |||
| #if (PortType & lv2_rdf.LV2_PORT_INPUT): | |||
| #pinfo['audio.ins'] += 1 | |||
| #elif (PortType & lv2_rdf.LV2_PORT_OUTPUT): | |||
| #pinfo['audio.outs'] += 1 | |||
| #elif (PortType & lv2_rdf.LV2_PORT_EVENT_MIDI): | |||
| #pinfo['midi.total'] += 1 | |||
| #if (PortType & lv2_rdf.LV2_PORT_INPUT): | |||
| #pinfo['midi.ins'] += 1 | |||
| #elif (PortType & lv2_rdf.LV2_PORT_OUTPUT): | |||
| #pinfo['midi.outs'] += 1 | |||
| #elif (PortType & lv2_rdf.LV2_PORT_CONTROL): | |||
| #pinfo['parameters.total'] += 1 | |||
| #if (PortType & lv2_rdf.LV2_PORT_INPUT): | |||
| #pinfo['parameters.ins'] += 1 | |||
| #elif (PortType & lv2_rdf.LV2_PORT_OUTPUT): | |||
| #if (not PortProps & lv2_rdf.LV2_PORT_LATENCY): | |||
| #pinfo['parameters.outs'] += 1 | |||
| #if (rdf_info['Type'] & lv2_rdf.LV2_GROUP_GENERATOR): | |||
| #pinfo['hints'] |= PLUGIN_IS_SYNTH | |||
| #if (rdf_info['UICount'] > 0): | |||
| #pinfo['hints'] |= PLUGIN_HAS_GUI | |||
| #plugins.append(pinfo) | |||
| #return plugins | |||
| def checkPluginLV2(rdf_info): | |||
| plugins = [] | |||
| pinfo = deepcopy(PyPluginInfo) | |||
| pinfo['type'] = PLUGIN_LV2 | |||
| pinfo['build'] = BINARY_NATIVE | |||
| pinfo['category'] = PLUGIN_CATEGORY_NONE # TODO | |||
| pinfo['hints'] = 0 | |||
| pinfo['binary'] = rdf_info['Binary'] | |||
| pinfo['name'] = rdf_info['Name'] | |||
| pinfo['label'] = rdf_info['URI'] | |||
| pinfo['maker'] = rdf_info['Author'] | |||
| pinfo['copyright'] = rdf_info['License'] | |||
| pinfo['unique_id'] = rdf_info['UniqueID'] | |||
| pinfo['audio.ins'] = 0 | |||
| pinfo['audio.outs'] = 0 | |||
| pinfo['audio.total'] = 0 | |||
| pinfo['midi.ins'] = 0 | |||
| pinfo['midi.outs'] = 0 | |||
| pinfo['midi.total'] = 0 | |||
| pinfo['parameters.ins'] = 0 | |||
| pinfo['parameters.outs'] = 0 | |||
| pinfo['parameters.total'] = 0 | |||
| pinfo['programs.total'] = 0 #rdf_info['PresetCount'] | |||
| if (pinfo['binary'] == "" or pinfo['name'] == "" or not rdf_info['Bundle']): | |||
| return None | |||
| for i in range(rdf_info['PortCount']): | |||
| PortType = rdf_info['Ports'][i]['Type'] | |||
| PortProps = rdf_info['Ports'][i]['Properties'] | |||
| if (PortType & lv2_rdf.LV2_PORT_AUDIO): | |||
| pinfo['audio.total'] += 1 | |||
| if (PortType & lv2_rdf.LV2_PORT_INPUT): | |||
| pinfo['audio.ins'] += 1 | |||
| elif (PortType & lv2_rdf.LV2_PORT_OUTPUT): | |||
| pinfo['audio.outs'] += 1 | |||
| elif (PortType & lv2_rdf.LV2_PORT_EVENT_MIDI): | |||
| pinfo['midi.total'] += 1 | |||
| if (PortType & lv2_rdf.LV2_PORT_INPUT): | |||
| pinfo['midi.ins'] += 1 | |||
| elif (PortType & lv2_rdf.LV2_PORT_OUTPUT): | |||
| pinfo['midi.outs'] += 1 | |||
| elif (PortType & lv2_rdf.LV2_PORT_CONTROL): | |||
| pinfo['parameters.total'] += 1 | |||
| if (PortType & lv2_rdf.LV2_PORT_INPUT): | |||
| pinfo['parameters.ins'] += 1 | |||
| elif (PortType & lv2_rdf.LV2_PORT_OUTPUT): | |||
| if (not PortProps & lv2_rdf.LV2_PORT_LATENCY): | |||
| pinfo['parameters.outs'] += 1 | |||
| if (rdf_info['Type'] & lv2_rdf.LV2_GROUP_GENERATOR): | |||
| pinfo['hints'] |= PLUGIN_IS_SYNTH | |||
| if (rdf_info['UICount'] > 0): | |||
| pinfo['hints'] |= PLUGIN_HAS_GUI | |||
| plugins.append(pinfo) | |||
| return plugins | |||
| # ------------------------------------------------------------------------------------------------ | |||
| # Backend C++ -> Python variables | |||
| @@ -573,7 +577,7 @@ PLUGIN_IS_BRIDGE = 0x02 | |||
| PLUGIN_IS_SYNTH = 0x04 | |||
| PLUGIN_USES_CHUNKS = 0x08 | |||
| PLUGIN_CAN_DRYWET = 0x10 | |||
| PLUGIN_CAN_VOL = 0x20 | |||
| PLUGIN_CAN_VOLUME = 0x20 | |||
| PLUGIN_CAN_BALANCE = 0x40 | |||
| # parameter hints | |||
| @@ -630,6 +634,8 @@ GUI_EXTERNAL_LV2 = 4 | |||
| # enum OptionsType | |||
| OPTION_GLOBAL_JACK_CLIENT = 1 | |||
| OPTION_USE_DSSI_CHUNKS = 2 | |||
| OPTION_PREFER_UI_BRIDGES = 3 | |||
| # enum CallbackType | |||
| CALLBACK_DEBUG = 0 | |||
| @@ -674,17 +680,6 @@ class CustomData(Structure): | |||
| ("value", c_char_p) | |||
| ] | |||
| class GuiData(Structure): | |||
| _fields_ = [ | |||
| ("type", c_enum), | |||
| ("visible", c_bool), | |||
| ("resizable", c_bool), | |||
| ("width", c_uint), | |||
| ("height", c_uint), | |||
| ("name", c_char_p), # DSSI Filename; LV2 Window Title | |||
| ("show_now", c_bool) | |||
| ] | |||
| class PluginInfo(Structure): | |||
| _fields_ = [ | |||
| ("valid", c_bool), | |||
| @@ -731,6 +726,11 @@ class MidiProgramInfo(Structure): | |||
| ("label", c_char_p) | |||
| ] | |||
| class GuiInfo(Structure): | |||
| _fields_ = [ | |||
| ("type", c_enum) | |||
| ] | |||
| class PluginBridgeInfo(Structure): | |||
| _fields_ = [ | |||
| ("category", c_enum), | |||
| @@ -806,6 +806,9 @@ class Host(object): | |||
| self.lib.get_midi_program_info.argtypes = [c_ushort, c_uint32] | |||
| self.lib.get_midi_program_info.restype = POINTER(MidiProgramInfo) | |||
| self.lib.get_gui_info.argtypes = [c_ushort] | |||
| self.lib.get_gui_info.restype = POINTER(GuiInfo) | |||
| self.lib.get_parameter_data.argtypes = [c_ushort, c_uint32] | |||
| self.lib.get_parameter_data.restype = POINTER(ParameterData) | |||
| @@ -818,9 +821,6 @@ class Host(object): | |||
| self.lib.get_chunk_data.argtypes = [c_ushort] | |||
| self.lib.get_chunk_data.restype = c_char_p | |||
| self.lib.get_gui_data.argtypes = [c_ushort] | |||
| self.lib.get_gui_data.restype = POINTER(GuiData) | |||
| self.lib.get_parameter_count.argtypes = [c_ushort] | |||
| self.lib.get_parameter_count.restype = c_uint32 | |||
| @@ -983,8 +983,8 @@ class Host(object): | |||
| def get_chunk_data(self, plugin_id): | |||
| return self.lib.get_chunk_data(plugin_id) | |||
| def get_gui_data(self, plugin_id): | |||
| return struct_to_dict(self.lib.get_gui_data(plugin_id).contents) | |||
| def get_gui_info(self, plugin_id): | |||
| return struct_to_dict(self.lib.get_gui_info(plugin_id).contents) | |||
| def get_parameter_count(self, plugin_id): | |||
| return self.lib.get_parameter_count(plugin_id) | |||
| @@ -1105,6 +1105,8 @@ class Host(object): | |||
| # ------------------------------------------------------------------------------------------------ | |||
| # Default Plugin Folders (set) | |||
| global LADSPA_PATH, DSSI_PATH, LV2_PATH, VST_PATH, SF2_PATH | |||
| LADSPA_PATH_env = os.getenv("LADSPA_PATH") | |||
| DSSI_PATH_env = os.getenv("DSSI_PATH") | |||
| LV2_PATH_env = os.getenv("LV2_PATH") | |||
| @@ -1141,4 +1143,4 @@ if (haveRDF): | |||
| if (LADSPA_RDF_PATH_env): | |||
| ladspa_rdf.set_rdf_path(LADSPA_RDF_PATH_env.split(splitter)) | |||
| #lv2_rdf.set_rdf_path(LV2_PATH) | |||
| lv2_rdf.set_rdf_path(LV2_PATH) | |||
| @@ -103,7 +103,7 @@ class ParamProgressBar(QProgressBar): | |||
| elif (value > self._maximum): | |||
| value = self._maximum | |||
| self.emit(SIGNAL("valueChangedFromBar(float)"), value) | |||
| self.emit(SIGNAL("valueChangedFromBar(double)"), value) | |||
| def mousePressEvent(self, event): | |||
| if (event.button() == Qt.LeftButton): | |||
| @@ -149,7 +149,7 @@ class ParamSpinBox(QAbstractSpinBox): | |||
| self.lineEdit().setVisible(False) | |||
| self.connect(self.bar, SIGNAL("valueChangedFromBar(float)"), self.handleValueChangedFromBar) | |||
| self.connect(self.bar, SIGNAL("valueChangedFromBar(double)"), self.handleValueChangedFromBar) | |||
| self.connect(self, SIGNAL("customContextMenuRequested(QPoint)"), self.showCustomMenu) | |||
| QTimer.singleShot(0, self.updateBarGeometry) | |||
| @@ -179,7 +179,7 @@ class ParamSpinBox(QAbstractSpinBox): | |||
| self.set_scalepoint_value(value) | |||
| if (send): | |||
| self.emit(SIGNAL("valueChanged(float)"), value) | |||
| self.emit(SIGNAL("valueChanged(double)"), value) | |||
| self.update() | |||
| @@ -161,19 +161,12 @@ MIDI_CC_LIST = ( | |||
| "0x5F FX 5 Depth [Phaser]" | |||
| ) | |||
| # Check if a string is a number (float support) | |||
| def isNumber(string): | |||
| if (string): | |||
| if (string.startswith("-")): | |||
| string = string.replace("-", "", 1) | |||
| sstring = string.split(".") | |||
| if (len(sstring) == 1 and sstring[0].isdigit()): | |||
| return True | |||
| elif (len(sstring) == 2 and sstring[0].isdigit() and sstring[1].isdigit()): | |||
| return True | |||
| else: | |||
| return False | |||
| else: | |||
| # Check if an object is a number (float support) | |||
| def isNumber(value): | |||
| try: | |||
| float(value) | |||
| return True | |||
| except: | |||
| return False | |||
| # Convert a value to a list | |||