Browse Source

More work

tags/v0.9.0
falkTX 13 years ago
parent
commit
949554ce41
32 changed files with 5224 additions and 750 deletions
  1. +1
    -1
      Makefile
  2. +56
    -0
      src/carla-includes/lv2/data-access.h
  3. +248
    -0
      src/carla-includes/lv2/event-helpers.h
  4. +280
    -0
      src/carla-includes/lv2/event.h
  5. +38
    -0
      src/carla-includes/lv2/instance-access.h
  6. +452
    -0
      src/carla-includes/lv2/lv2.h
  7. +67
    -0
      src/carla-includes/lv2/midi.h
  8. +357
    -0
      src/carla-includes/lv2/state.h
  9. +399
    -0
      src/carla-includes/lv2/ui.h
  10. +92
    -0
      src/carla-includes/lv2/uri-map.h
  11. +121
    -0
      src/carla-includes/lv2/urid.h
  12. +68
    -58
      src/carla.py
  13. +1
    -1
      src/carla/Makefile
  14. +40
    -38
      src/carla/carla_backend.cpp
  15. +14
    -16
      src/carla/carla_backend.h
  16. +0
    -0
      src/carla/carla_includes.h
  17. +1
    -1
      src/carla/carla_jack.cpp
  18. +837
    -0
      src/carla/carla_osc.cpp
  19. +92
    -0
      src/carla/carla_osc.h
  20. +192
    -60
      src/carla/carla_plugin.h
  21. +115
    -54
      src/carla/carla_threads.cpp
  22. +15
    -3
      src/carla/carla_threads.h
  23. +943
    -2
      src/carla/dssi.cpp
  24. +3
    -3
      src/carla/ladspa.cpp
  25. +217
    -2
      src/carla/lv2.cpp
  26. +95
    -66
      src/carla/lv2_rdf.h
  27. +0
    -16
      src/carla/osc.cpp
  28. +0
    -16
      src/carla/osc.h
  29. +80
    -78
      src/carla_backend.py
  30. +391
    -319
      src/lv2_rdf.py
  31. +3
    -3
      src/paramspinbox.py
  32. +6
    -13
      src/shared.py

+ 1
- 1
Makefile View File

@@ -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


+ 56
- 0
src/carla-includes/lv2/data-access.h View File

@@ -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 */

+ 248
- 0
src/carla-includes/lv2/event-helpers.h View File

@@ -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 */


+ 280
- 0
src/carla-includes/lv2/event.h View File

@@ -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 */

+ 38
- 0
src/carla-includes/lv2/instance-access.h View File

@@ -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 */


+ 452
- 0
src/carla-includes/lv2/lv2.h View File

@@ -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 */

+ 67
- 0
src/carla-includes/lv2/midi.h View File

@@ -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 */

+ 357
- 0
src/carla-includes/lv2/state.h View File

@@ -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 */

+ 399
- 0
src/carla-includes/lv2/ui.h View File

@@ -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 */

+ 92
- 0
src/carla-includes/lv2/uri-map.h View File

@@ -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 */

+ 121
- 0
src/carla-includes/lv2/urid.h View File

@@ -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 */

+ 68
- 58
src/carla.py View File

@@ -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:


+ 1
- 1
src/carla/Makefile View File

@@ -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




+ 40
- 38
src/carla/carla_backend.cpp View File

@@ -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

+ 14
- 16
src/carla/carla_backend.h View File

@@ -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();


src/carla/includes.h → src/carla/carla_includes.h View File


src/carla/jack.cpp → src/carla/carla_jack.cpp View File

@@ -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;

+ 837
- 0
src/carla/carla_osc.cpp View File

@@ -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, "");
}
}

+ 92
- 0
src/carla/carla_osc.h View File

@@ -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

+ 192
- 60
src/carla/carla_plugin.h View File

@@ -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 &param.data[index];
return 0;
}

ParameterRanges* param_ranges(uint32_t index)
virtual uint32_t midiprog_count()
{
return &param.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 &param.data[index];
}

virtual uint32_t midiprog_count()
ParameterRanges* param_ranges(uint32_t index)
{
return 0;
return &param.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];


+ 115
- 54
src/carla/carla_threads.cpp View File

@@ -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;
}
}

+ 15
- 3
src/carla/carla_threads.h View File

@@ -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;
};



+ 943
- 2
src/carla/dssi.cpp View File

@@ -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, &param_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");


+ 3
- 3
src/carla/ladspa.cpp View File

@@ -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;
}



+ 217
- 2
src/carla/lv2.cpp View File

@@ -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");


+ 95
- 66
src/carla/lv2_rdf.h View File

@@ -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;
}



+ 0
- 16
src/carla/osc.cpp View 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
*/

+ 0
- 16
src/carla/osc.h View 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
*/

+ 80
- 78
src/carla_backend.py View 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)

+ 391
- 319
src/lv2_rdf.py
File diff suppressed because it is too large
View File


+ 3
- 3
src/paramspinbox.py View File

@@ -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()



+ 6
- 13
src/shared.py View File

@@ -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


Loading…
Cancel
Save