Browse Source

More Carla work, generic LV2 stuff

tags/v0.9.0
falkTX 13 years ago
parent
commit
b117685403
8 changed files with 927 additions and 144 deletions
  1. +469
    -0
      src/carla-includes/lv2/lv2dynparam.h
  2. +9
    -2
      src/carla/carla_plugin.h
  3. +4
    -0
      src/carla/carla_threads.cpp
  4. +10
    -0
      src/carla/dssi.cpp
  5. +431
    -135
      src/carla/lv2.cpp
  6. +2
    -6
      src/carla/lv2_rdf.h
  7. +1
    -1
      src/carla/sf2.cpp
  8. +1
    -0
      src/carla/vst.cpp

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

@@ -0,0 +1,469 @@
/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*****************************************************************************
*
* This work is in public domain.
*
* This file 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.
*
* If you have questions, contact Nedko Arnaudov <nedko@arnaudov.name> or
* ask in #lad channel, FreeNode IRC network.
*
*****************************************************************************/

/**
* @file lv2dynparam.h
* @brief LV2 dynparam extension definition
*
* @par Purpose
*
* The purpose of this extension is to allow plugin parameters appear
* and disappear as response of existing parameter changes (i.e. number
* of voices) or executing commands (i.e. "add new voice"). It also
* allows grouping of parameters and groups. Groups can be used for
* things like ADSR abstraction, i.e. group of 4 float parameters.
*
* @par Architectural overview
*
* Plugin notifies host for changes through callbacks. During
* initialization, plugin notifies host about initial groups,
* parameters and commands through same callbacks used for later
* notification. There are callbacks to notify host for group,
* parameter and command disappears.
*
* Groups are containers of other groups, parameters and
* commands. Parameters and groups have URIs. Parameter URIs are
* used to describe type of parameter (i.e. boolean, integer,
* string, etc.). Parameters are as simple as possible. There is one
* predefined Group URI for "generic group" type, i.e. container
* that is just that - a container of other groups, parameters and
* commands. Other group types are just hints and ones that are
* unknown to host, can be looked as generic ones. Only generic
* groups can contain groups. Groups of other types can contain only
* parameters. There is always one, root group. Name of the root
* groop is expected to match name of the plugin.
*
* Groups, parameters and commands, have "name" containing short
* human readble description of object purpose.
*
* Parameter ports, are bidirectional. Parameters have values, and
* some of them (depending of type) - range. Data storage for
* current, min and max values is in plugin memory. Host gets
* pointers to that memory and accesses the data in type specific
* way.
*
* When plugin decides to change parameter value or range (as
* response to command execution or other parameter value change), it
* notifies host through callback.
*
* When host decides to change parameter value or execute command (as
* resoponse to user action, i.e. knob rotation/button press, or some
* kind of automation), it calls plugin callback. In case of
* parameter, it first changes the value in the plugin data storage
* for particular parameter. Host ensures that values being set are
* within current range (if range is defined for particular port
* type).
*
* Apart from initialization (host_attach), plugin may call host
* callbacks only as response to command execution or parameter
* change notification (from host).
*
* Host serializes calls to plugin dynparam callbacks and the
* run/connect_port lv2 callbacks. Thus plugin does not need to take
* special measures for thread safety. in callbacks called by host.
*
* Plugin can assume that host will never call dynamic parameter
* functions when lv2 plugin callbacks (like run and connect_port) are
* being called. I.e. calls are serialized, no need for locks in
* plugin. Plugin must not suspend execution (sleep/lock) while being
* called by host. If it needs to sleep to implement action requested
* by host, like allocation of data for new voice, the allocation
* should be done in background thread and when ready, transfered to
* the realtime code. During initialization (host_attach) plugin is
* allowed to sleep. Thus conventional memory allocation is allowed
* in host_attach.
*
* @par Intialization sequence
*
* -# Host discovers whether plugin supports the extension by
* inspecting the RDF Turtle file.
* -# Host calls lv2 extension_data callback, plugin returns pointer
* to struct lv2dynparam_plugin_callbacks containing pointers to
* several funtions, including host_attach.
* -# For each instantiated plugin supporting this extension, host
* calls host_attach function with parameters:
* - a LV2_Handle, plugin instance handle
* - pointer to struct lv2dynparam_host_callbacks, containing
* pointers to several functions, to be called by plugin.
* - instance host context, opaque pointer
* -# During initialization (host_attach), initial groups and
* parameters appear and host callbacks are called by plugin.
*
* @par Parameter types
* - float, with range
* - 32-bit 2's complement signed int, with range
* - midi note, value stored as byte, with range
* - string
* - filename
* - boolean, value stored as byte, non-zero means TRUE, zero means FALSE
*
* @par Notes:
* - if function fails, variables where output parameters are normally
* stored remain unmodified.
* - If host callback, called by plugin, fails - plugin should try the
* operation later.
*/


#ifndef LV2DYNPARAM_H__31DEB371_3874_44A0_A9F2_AAFB0360D8C5__INCLUDED
#define LV2DYNPARAM_H__31DEB371_3874_44A0_A9F2_AAFB0360D8C5__INCLUDED

#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* Adjust editor indent */
#endif

/** base URI to be used for composing real URIs (internal use only) */
#define LV2DYNPARAM_BASE_URI "http://home.gna.org/lv2dynparam/v1"

/** URI of the LV2 extension defined in this file */
#define LV2DYNPARAM_URI LV2DYNPARAM_BASE_URI

/** max size of name and type_uri buffers, including terminating zero char */
#define LV2DYNPARAM_MAX_STRING_SIZE 1024

/** handle identifying parameter, supplied by plugin */
typedef void * lv2dynparam_parameter_handle;

/** handle identifying group, supplied by plugin */
typedef void * lv2dynparam_group_handle;

/** handle identifying command, supplied by plugin */
typedef void * lv2dynparam_command_handle;

/**
* Structure containing set of hints.
*/
struct lv2dynparam_hints
{
unsigned char count; /**< Number of hints in the set. Size of @c names and @c values arrays. */
char ** names; /**< Hint names. Array of hint names with size @c count. */
char ** values; /**< Hint values. Array of hint values with size @c count. Element can be NULL if hint has no value. */
};

/**
* Structure containing poitners to functions called by
* plugin and implemented by host.
*/
struct lv2dynparam_host_callbacks
{
/**
* This function is called by plugin to notify host about new
* group.
*
* @param instance_host_context Host instance context, as supplied
* during initialization (host_attach).
* @param parent_group_host_context Host context of parent
* group. For the root group, parent context is NULL.
* @param group Plugin context for the group
* @param hints_ptr Pointer to structure representing hints set
* associated with appearing group.
* @param group_host_context Pointer to variable where host context
* for the new group will be stored.
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*group_appear)(
void * instance_host_context,
void * parent_group_host_context,
lv2dynparam_group_handle group,
const struct lv2dynparam_hints * hints_ptr,
void ** group_host_context);

/**
* This function is called by plugin to notify host about group
* removal.
*
* @param instance_host_context Host instance context, as supplied
* during initialization (host_attach).
* @param group_host_context Host context of the group
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*group_disappear)(
void * instance_host_context,
void * group_host_context);

/**
* This function is called by plugin to notify host about new
* parameter.
*
* @param instance_host_context Host instance context, as supplied
* during initialization (host_attach).
* @param group_host_context Host context of parent group.
* @param parameter Plugin context for the parameter
* @param hints_ptr Pointer to structure representing hints set
* associated with appearing parameter.
* @param parameter_host_context Pointer to variable where host
* context for the new parameter will be stored.
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*parameter_appear)(
void * instance_host_context,
void * group_host_context,
lv2dynparam_parameter_handle parameter,
const struct lv2dynparam_hints * hints_ptr,
void ** parameter_host_context);

/**
* This function is called by plugin to notify host about parameter
* removal.
*
* @param instance_host_context Host instance context, as supplied
* during initialization (host_attach).
* @param parameter_host_context Host context of the parameter
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*parameter_disappear)(
void * instance_host_context,
void * parameter_host_context);

/**
* This function is called by plugin to notify host about parameter
* value or range change.
*
* @param instance_host_context Host instance context, as supplied
* during initialization (host_attach).
* @param parameter_host_context Host context of the parameter
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*parameter_change)(
void * instance_host_context,
void * parameter_host_context);

/**
* This function is called by plugin to notify host about new commmand.
*
* @param instance_host_context Host instance context, as supplied
* during initialization (host_attach).
* @param group_host_context Host context of parent group.
* @param command Plugin context for the command
* @param hints_ptr Pointer to structure representing hints set
* associated with appearing command.
* @param command_host_context Pointer to variable where host
* context for the new command will be stored.
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*command_appear)(
void * instance_host_context,
void * group_host_context,
lv2dynparam_command_handle command,
const struct lv2dynparam_hints * hints_ptr,
void ** command_host_context);

/**
* This function is called by plugin to notify host about command
* removal.
*
* @param instance_host_context Host instance context, as supplied
* during initialization (host_attach).
* @param command_host_context Host context of the command
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*command_disappear)(
void * instance_host_context,
void * command_host_context);
};

/**
* Structure containing poitners to functions called by
* host and implemented by plugin.
* Pointer to this struct is returned by LV2 extension_data plugin callback
*/
struct lv2dynparam_plugin_callbacks
{
/**
* This callback is called by host during initialization.
* Plugin is allowed to suspend execution (sleep/lock).
* Thus conventional memory allocation is allowed.
*
* @param instance Handle of instantiated LV2 plugin
* @param host_callbacks Pointer to struncture containing pointer to
* functions implemented by host, to be called by plugin.
* @param instance_host_context Context to be supplied as parameter
* to callbacks implemented by host and called by plugin.
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error
*/
unsigned char (*host_attach)(
LV2_Handle instance,
struct lv2dynparam_host_callbacks * host_callbacks,
void * instance_host_context);

/**
* This function is called by host to retrieve name of group
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param group Group handle, as supplied by plugin
* @param buffer Pointer to buffer with size of
* LV2DYNPARAM_MAX_STRING_SIZE bytes, where ASCIIZ string containing
* name of the group will be stored.
*/
void (*group_get_name)(
lv2dynparam_group_handle group,
char * buffer);

/**
* This function is called by host to retrieve type URI of parameter
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param parameter Parameter handle, as supplied by plugin
* @param buffer Pointer to buffer with size of
* LV2DYNPARAM_MAX_STRING_SIZE bytes, where ASCIIZ string containing
* type URI of the parameter will be stored.
*/
void (*parameter_get_type_uri)(
lv2dynparam_parameter_handle parameter,
char * buffer);

/**
* This function is called by host to retrieve name of parameter
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param parameter Parameter handle, as supplied by plugin
* @param buffer Pointer to buffer with size of
* LV2DYNPARAM_MAX_STRING_SIZE bytes, where ASCIIZ string containing
* name of the parameter will be stored.
*/
void (*parameter_get_name)(
lv2dynparam_parameter_handle parameter,
char * buffer);

/**
* This funtion is called by host to retrieve pointer to memory
* where value data for particular parameter is stored.
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param parameter Parameter handle, as supplied by plugin
* @param value_buffer Pointer to variable where pointer to value
* data will be stored.
*/
void (*parameter_get_value)(
lv2dynparam_parameter_handle parameter,
void ** value_buffer);

/**
* This funtion is called by host to retrieve pointer to memory
* where range min and max values data for particular parameter are
* stored. Host calls this function only for parameter with types
* that have range.
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param parameter Parameter handle, as supplied by plugin
* @param value_min_buffer Pointer to variable where pointer to min
* value data will be stored.
* @param value_max_buffer Pointer to variable where pointer to max
* value data will be stored.
*/
void (*parameter_get_range)(
lv2dynparam_parameter_handle parameter,
void ** value_min_buffer,
void ** value_max_buffer);

/**
* This function is called by host to notify plugin about value
* change. For parameters with types that have range, value is
* guaranteed to be with the range. Before calling this function,
* host updates value data storage with the new value.
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param parameter Parameter handle, as supplied by plugin
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*parameter_change)(
lv2dynparam_parameter_handle parameter);

/**
* This function is called by host to retrieve name of command
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param command Command handle, as supplied by plugin
* @param buffer Pointer to buffer with size of
* LV2DYNPARAM_MAX_STRING_SIZE bytes, where ASCIIZ string containing
* name of the command will be stored.
*/
void (*command_get_name)(
lv2dynparam_command_handle command,
char * buffer);

/**
* This function is called by host to execute command defined by
* plugin.
* Plugin implementation must not suspend execution (sleep/lock).
*
* @param command Command handle, as supplied by plugin
*
* @return Success status
* @retval Non-zero - success
* @retval Zero - error, try later
*/
unsigned char (*command_execute)(
lv2dynparam_command_handle command);
};

/** URI for float parameter */
#define LV2DYNPARAM_PARAMETER_TYPE_FLOAT_URI LV2DYNPARAM_BASE_URI "#parameter_float"

/** URI for integer parameter */
#define LV2DYNPARAM_PARAMETER_TYPE_INT_URI LV2DYNPARAM_BASE_URI "#parameter_int"

/** URI for note parameter */
#define LV2DYNPARAM_PARAMETER_TYPE_NOTE_URI LV2DYNPARAM_BASE_URI "#parameter_note"

/** URI for string parameter */
#define LV2DYNPARAM_PARAMETER_TYPE_STRING_URI LV2DYNPARAM_BASE_URI "#parameter_string"

/** URI for filename parameter */
#define LV2DYNPARAM_PARAMETER_TYPE_FILENAME_URI LV2DYNPARAM_BASE_URI "#parameter_filename"

/** URI for boolean parameter */
#define LV2DYNPARAM_PARAMETER_TYPE_BOOLEAN_URI LV2DYNPARAM_BASE_URI "#parameter_boolean"

/** URI for enumeration parameter */
#define LV2DYNPARAM_PARAMETER_TYPE_ENUM_URI LV2DYNPARAM_BASE_URI "#parameter_enum"

#if 0
{ /* Adjust editor indent */
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* #ifndef LV2DYNPARAM_H__31DEB371_3874_44A0_A9F2_AAFB0360D8C5__INCLUDED */

+ 9
- 2
src/carla/carla_plugin.h View File

@@ -47,7 +47,8 @@ enum PluginPostEventType {
PostEventProgramChange,
PostEventMidiProgramChange,
PostEventNoteOn,
PostEventNoteOff
PostEventNoteOff,
PostEventCustom
};

enum PluginBridgeInfoType {
@@ -107,6 +108,7 @@ struct PluginPostEvent {
PluginPostEventType type;
int32_t index;
double value;
const void* cdata;
};

struct ExternalMidiNote {
@@ -878,7 +880,7 @@ public:
carla_midi_unlock();
}

void postpone_event(PluginPostEventType type, int32_t index, double value)
void postpone_event(PluginPostEventType type, int32_t index, double value, const void* cdata = nullptr)
{
post_events.lock.lock();

@@ -890,6 +892,7 @@ public:
post_events.data[i].type = type;
post_events.data[i].index = index;
post_events.data[i].value = value;
post_events.data[i].cdata = cdata;
break;
}
}
@@ -909,6 +912,10 @@ public:
post_events.lock.unlock();
}

virtual void run_custom_event(PluginPostEvent* /*event*/)
{
}

virtual int set_osc_bridge_info(PluginBridgeInfoType /*intoType*/, lo_arg** /*argv*/)
{
return 1;


+ 4
- 0
src/carla/carla_threads.cpp View File

@@ -144,6 +144,10 @@ void CarlaCheckThread::run()

break;

case PostEventCustom:
plugin->run_custom_event(&post_events[j]);
break;

default:
break;
}


+ 10
- 0
src/carla/dssi.cpp View File

@@ -166,7 +166,17 @@ public:

if (strcmp(key, "reloadprograms") == 0 || strcmp(key, "load") == 0 || strncmp(key, "patches", 7) == 0)
{
// Safely disable plugin for reload
carla_proc_lock();
short _id = m_id;
m_id = -1;
carla_proc_unlock();

reload_programs(false);

carla_proc_lock();
m_id = _id;
carla_proc_unlock();
}

CarlaPlugin::set_custom_data(dtype, key, value, gui_send);


+ 431
- 135
src/carla/lv2.cpp View File

@@ -24,6 +24,7 @@
#include "lv2/event.h"
#include "lv2/event-helpers.h"
#include "lv2/instance-access.h"
#include "lv2/log.h"
#include "lv2/midi.h"
#include "lv2/port-props.h"
#include "lv2/presets.h"
@@ -33,12 +34,14 @@
#include "lv2/units.h"
#include "lv2/uri-map.h"
#include "lv2/urid.h"
#include "lv2/worker.h"

#include "lv2/lv2dynparam.h"
#include "lv2/lv2-miditype.h"
#include "lv2/lv2-midifunctions.h"
#include "lv2/lv2_external_ui.h"
#include "lv2/lv2_programs.h"
#include "lv2/lv2_rtmempool.h"
#include "lv2/lv2_external_ui.h"

#include "lv2_rdf.h"

@@ -50,45 +53,55 @@ extern "C" {
#include <QtGui/QLayout>

// static max values
const unsigned int MAX_EVENT_BUFFER = 8192; // 0x7FFF; // 32767
const unsigned int MAX_EVENT_BUFFER = 8192; // 0x2000

// extra plugin hints
const unsigned int PLUGIN_HAS_EXTENSION_STATE = 0x1000;
const unsigned int PLUGIN_HAS_EXTENSION_DYNPARAM = 0x2000;
const unsigned int PLUGIN_HAS_EXTENSION_DYNPARAM = 0x1000;
const unsigned int PLUGIN_HAS_EXTENSION_PROGRAMS = 0x2000;
const unsigned int PLUGIN_HAS_EXTENSION_STATE = 0x4000;
const unsigned int PLUGIN_HAS_EXTENSION_WORKER = 0x8000;

// extra parameter hints
const unsigned int PARAMETER_IS_TRIGGER = 0x1000;
const unsigned int PARAMETER_IS_STRICT_BOUNDS = 0x2000;

// 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_parent = 7;
const uint32_t lv2_feature_id_ui_resize = 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 = 11;
const uint32_t lv2_feature_id_event = 0;
const uint32_t lv2_feature_id_logs = 1;
const uint32_t lv2_feature_id_uri_map = 2;
const uint32_t lv2_feature_id_urid_map = 3;
const uint32_t lv2_feature_id_urid_unmap = 4;
const uint32_t lv2_feature_id_worker = 5;
const uint32_t lv2_feature_id_programs = 6;
const uint32_t lv2_feature_id_rtmempool = 7;
const uint32_t lv2_feature_id_data_access = 8;
const uint32_t lv2_feature_id_instance_access = 9;
const uint32_t lv2_feature_id_ui_parent = 10;
const uint32_t lv2_feature_id_ui_port_map = 11;
const uint32_t lv2_feature_id_ui_resize = 12;
const uint32_t lv2_feature_id_external_ui = 13;
const uint32_t lv2_feature_id_external_ui_old = 14;
const uint32_t lv2_feature_count = 15;

// event data/types
const unsigned int CARLA_EVENT_DATA_ATOM = 0x01;
const unsigned int CARLA_EVENT_DATA_EVENT = 0x02;
const unsigned int CARLA_EVENT_DATA_MIDI_LL = 0x04;
const unsigned int CARLA_EVENT_TYPE_MIDI = 0x10;
const unsigned int CARLA_EVENT_TYPE_TIME = 0x20;
const unsigned int CARLA_EVENT_TYPE_TIME = 0x20; // FIXME

// pre-set uri[d] map ids
const uint32_t CARLA_URI_MAP_ID_NULL = 0;
const uint32_t CARLA_URI_MAP_ID_ATOM_CHUNK = 1;
const uint32_t CARLA_URI_MAP_ID_ATOM_SEQUENCE = 2;
const uint32_t CARLA_URI_MAP_ID_ATOM_STRING = 3;
const uint32_t CARLA_URI_MAP_ID_MIDI_EVENT = 4;
const uint32_t CARLA_URI_MAP_ID_TIME_POSITION = 5;
const uint32_t CARLA_URI_MAP_ID_COUNT = 6;
const uint32_t CARLA_URI_MAP_ID_LOG_ERROR = 4;
const uint32_t CARLA_URI_MAP_ID_LOG_NOTE = 5;
const uint32_t CARLA_URI_MAP_ID_LOG_TRACE = 6;
const uint32_t CARLA_URI_MAP_ID_LOG_WARNING = 7;
const uint32_t CARLA_URI_MAP_ID_MIDI_EVENT = 8;
const uint32_t CARLA_URI_MAP_ID_TIME_POSITION = 9; // TODO - full timePos support
const uint32_t CARLA_URI_MAP_ID_COUNT = 10;

enum Lv2ParameterDataType {
LV2_PARAMETER_TYPE_CONTROL,
@@ -139,8 +152,8 @@ int main()
{
short id = add_plugin_lv2("/usr/lib/lv2/Bitcrusher.lv2", "urn:distrho:Bitcrusher");
set_active(id, true);
carla_sleep(1);
remove_plugin(id);
//carla_log_printf(nullptr, CARLA_URI_MAP_ID_LOG_ERROR, "%s aaa %i", "ola", 90);
return 0;
}
#endif
@@ -158,8 +171,11 @@ public:
descriptor = nullptr;
rdf_descriptor = nullptr;

programs.plugin = nullptr;
programs.ui = nullptr;
ext.dynparam = nullptr;
ext.state = nullptr;
ext.worker = nullptr;
ext.programs = nullptr;
ext.uiprograms = nullptr;

ui.lib = nullptr;
ui.handle = nullptr;
@@ -253,6 +269,9 @@ public:
if (features[lv2_feature_id_data_access] && features[lv2_feature_id_data_access]->data)
delete (LV2_Extension_Data_Feature*)features[lv2_feature_id_data_access]->data;

if (features[lv2_feature_id_ui_port_map] && features[lv2_feature_id_ui_port_map]->data)
delete (LV2UI_Port_Map*)features[lv2_feature_id_ui_port_map]->data;

if (features[lv2_feature_id_ui_resize] && features[lv2_feature_id_ui_resize]->data)
delete (LV2UI_Resize*)features[lv2_feature_id_ui_resize]->data;

@@ -278,6 +297,12 @@ public:
descriptor = nullptr;
rdf_descriptor = nullptr;

if (features[lv2_feature_id_event] && features[lv2_feature_id_event]->data)
delete (LV2_Event_Feature*)features[lv2_feature_id_event]->data;

if (features[lv2_feature_id_logs] && features[lv2_feature_id_logs]->data)
delete (LV2_Log_Log*)features[lv2_feature_id_logs]->data;

if (features[lv2_feature_id_uri_map] && features[lv2_feature_id_uri_map]->data)
delete (LV2_URI_Map_Feature*)features[lv2_feature_id_uri_map]->data;

@@ -287,8 +312,11 @@ public:
if (features[lv2_feature_id_urid_unmap] && features[lv2_feature_id_urid_unmap]->data)
delete (LV2_URID_Unmap*)features[lv2_feature_id_urid_unmap]->data;

if (features[lv2_feature_id_event] && features[lv2_feature_id_event]->data)
delete (LV2_Event_Feature*)features[lv2_feature_id_event]->data;
if (features[lv2_feature_id_worker] && features[lv2_feature_id_worker]->data)
delete (LV2_Worker_Schedule*)features[lv2_feature_id_worker]->data;

if (features[lv2_feature_id_programs] && features[lv2_feature_id_programs]->data)
delete (LV2_Programs_Host*)features[lv2_feature_id_programs]->data;

if (features[lv2_feature_id_rtmempool] && features[lv2_feature_id_rtmempool]->data)
delete (lv2_rtsafe_memory_pool_provider*)features[lv2_feature_id_rtmempool]->data;
@@ -583,13 +611,8 @@ public:
{
CarlaPlugin::set_custom_data(dtype, key, value, gui_send);

if ((m_hints & PLUGIN_HAS_EXTENSION_STATE) > 0 && descriptor->extension_data)
{
LV2_State_Interface* state = (LV2_State_Interface*)descriptor->extension_data(LV2_STATE__interface);

if (state)
state->restore(handle, carla_lv2_state_retrieve, this, 0, features);
}
if (ext.state)
ext.state->restore(handle, carla_lv2_state_retrieve, this, 0, features);
}

void set_gui_data(int, void* ptr)
@@ -638,7 +661,7 @@ public:
if (carla_jack_on_freewheel())
{
if (block) carla_proc_lock();
programs.plugin->select_program(handle, midiprog.data[index].bank, midiprog.data[index].program);
ext.programs->select_program(handle, midiprog.data[index].bank, midiprog.data[index].program);
if (block) carla_proc_unlock();
}
else
@@ -652,7 +675,7 @@ public:
carla_proc_unlock();
}

programs.plugin->select_program(handle, midiprog.data[index].bank, midiprog.data[index].program);
ext.programs->select_program(handle, midiprog.data[index].bank, midiprog.data[index].program);

if (block)
{
@@ -669,8 +692,8 @@ public:
osc_send_program_as_midi(&osc.data, midiprog.data[index].bank, midiprog.data[index].program);
else
#endif
if (programs.ui)
programs.ui->select_program(ui.handle, midiprog.data[index].bank, midiprog.data[index].program);
if (ext.uiprograms)
ext.uiprograms->select_program(ui.handle, midiprog.data[index].bank, midiprog.data[index].program);
}
}

@@ -842,13 +865,6 @@ public:
qDebug("Unknown port type found, index: %i, name: %s", i, rdf_descriptor->Ports[i].Name);
}

// if (params == 0 && (hints & PLUGIN_HAS_EXTENSION_DYNPARAM) > 0)
// {
// dynparam_plugin = (lv2dynparam_plugin_callbacks*)descriptor->extension_data(LV2DYNPARAM_URI);
// if (dynparam_plugin)
// dynparam_plugin->host_attach(handle, &dynparam_host, this);
// }

if (ains > 0)
{
ain.ports = new jack_port_t*[ains];
@@ -1304,6 +1320,30 @@ public:
if (aouts >= 2 && aouts%2 == 0)
m_hints |= PLUGIN_CAN_BALANCE;

// check extensions
ext.dynparam = nullptr;
ext.state = nullptr;
ext.worker = nullptr;
ext.programs = nullptr;

if (descriptor->extension_data)
{
if (m_hints & PLUGIN_HAS_EXTENSION_DYNPARAM)
ext.dynparam = (lv2dynparam_plugin_callbacks*)descriptor->extension_data(LV2DYNPARAM_URI);

if (m_hints & PLUGIN_HAS_EXTENSION_PROGRAMS)
ext.programs = (LV2_Programs_Interface*)descriptor->extension_data(LV2_PROGRAMS__Interface);

if (m_hints & PLUGIN_HAS_EXTENSION_STATE)
ext.state = (LV2_State_Interface*)descriptor->extension_data(LV2_STATE__interface);

if (m_hints & PLUGIN_HAS_EXTENSION_WORKER)
ext.worker = (LV2_Worker_Interface*)descriptor->extension_data(LV2_WORKER__interface);
}

//if (ext.dynparam)
// ext.dynparam->host_attach(handle, &dynparam_host, this);

carla_proc_lock();
m_id = _id;
carla_proc_unlock();
@@ -1334,14 +1374,9 @@ public:
midiprog.data = nullptr;

// Query new programs
if (descriptor->extension_data) // FIXME - check for lv2:extensionData program
programs.plugin = (LV2_Programs_Interface*)descriptor->extension_data(LV2_PROGRAMS__Interface);
else
programs.plugin = nullptr;

if (programs.plugin)
if (ext.programs)
{
while (programs.plugin->get_program(handle, midiprog.count))
while (ext.programs->get_program(handle, midiprog.count))
midiprog.count += 1;
}

@@ -1351,7 +1386,7 @@ public:
// Update data
for (i=0; i < midiprog.count; i++)
{
const LV2_Program_Descriptor* pdesc = programs.plugin->get_program(handle, i);
const LV2_Program_Descriptor* pdesc = ext.programs->get_program(handle, i);
if (pdesc)
{
midiprog.data[i].bank = pdesc->bank;
@@ -1420,13 +1455,8 @@ public:

void prepare_for_save()
{
if ((m_hints & PLUGIN_HAS_EXTENSION_STATE) > 0 && descriptor->extension_data)
{
LV2_State_Interface* state = (LV2_State_Interface*)descriptor->extension_data(LV2_STATE__interface);

if (state)
state->save(handle, carla_lv2_state_store, this, 0, features);
}
if (ext.state)
ext.state->save(handle, carla_lv2_state_store, this, 0, features);
}

void process(jack_nframes_t nframes)
@@ -2090,6 +2120,15 @@ public:
qDebug("Lv2Plugin::remove_from_jack() - end");
}

void run_custom_event(PluginPostEvent* event)
{
if (ext.worker)
{
ext.worker->work(handle, carla_lv2_worker_respond, this, event->index, event->cdata);
ext.worker->end_run(handle);
}
}

uint32_t get_custom_uri_id(const char* uri)
{
qDebug("Lv2Plugin::get_custom_uri_id(%s)", uri);
@@ -2114,6 +2153,42 @@ public:
return nullptr;
}

void update_program(int32_t index)
{
if (index == -1)
{
carla_proc_lock();
short _id = m_id;
m_id = -1;
carla_proc_unlock();

reload_programs(false);

carla_proc_lock();
m_id = _id;
carla_proc_unlock();
}
else
{
if (ext.programs && index < (int32_t)prog.count)
{
const char* prog_name = ext.programs->get_program(handle, index)->name;

if (prog_name && !(prog.names[index] && strcmp(prog_name, prog.names[index]) == 0))
{
if (prog.names[index])
free((void*)prog.names[index]);

prog.names[index] = strdup(prog_name);
}
}
}

#ifndef BUILD_BRIDGE
callback_action(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0);
#endif
}

bool is_ui_resizable()
{
if (ui.rdf_descriptor)
@@ -2148,7 +2223,6 @@ public:
void reinit_external_ui()
{
qDebug("Lv2Plugin::reinit_external_ui()");

ui.widget = nullptr;
ui.handle = ui.descriptor->instantiate(ui.descriptor, descriptor->URI, ui.rdf_descriptor->Bundle, carla_lv2_ui_write_function, this, &ui.widget, features);

@@ -2169,16 +2243,16 @@ public:
void update_ui()
{
qDebug("Lv2Plugin::update_ui()");
programs.ui = nullptr;
ext.uiprograms = nullptr;

if (ui.handle && ui.descriptor)
{
if (ui.descriptor->extension_data)
{
programs.ui = (LV2_Programs_UI_Interface*)ui.descriptor->extension_data(LV2_PROGRAMS__UIInterface);
ext.uiprograms = (LV2_Programs_UI_Interface*)ui.descriptor->extension_data(LV2_PROGRAMS__UIInterface);

if (programs.ui)
programs.ui->select_program(ui.handle, midiprog.data[midiprog.current].bank, midiprog.data[midiprog.current].program);
if (ext.uiprograms)
ext.uiprograms->select_program(ui.handle, midiprog.data[midiprog.current].bank, midiprog.data[midiprog.current].program);
}

if (ui.descriptor->port_event)
@@ -2190,8 +2264,6 @@ public:
ui.descriptor->port_event(ui.handle, param.data[i].rindex, sizeof(float), 0, &value);
}
}

qDebug("Lv2Plugin::update_ui() - %p", programs.ui);
}
}

@@ -2246,13 +2318,17 @@ public:
}
}

// Check extensions (...)
// Check extensions
for (i=0; i < rdf_descriptor->ExtensionCount; i++)
{
if (strcmp(rdf_descriptor->Extensions[i], LV2_STATE__interface) == 0)
if (strcmp(rdf_descriptor->Extensions[i], LV2DYNPARAM_URI) == 0)
m_hints |= PLUGIN_HAS_EXTENSION_DYNPARAM;
else if (strcmp(rdf_descriptor->Extensions[i], LV2_PROGRAMS__Interface) == 0)
m_hints |= PLUGIN_HAS_EXTENSION_PROGRAMS;
else if (strcmp(rdf_descriptor->Extensions[i], LV2_STATE__interface) == 0)
m_hints |= PLUGIN_HAS_EXTENSION_STATE;
//else if (strcmp(rdf_descriptor->Extensions[i], LV2DYNPARAM_URI) == 0)
// plugin->hints |= PLUGIN_HAS_EXTENSION_DYNPARAM;
else if (strcmp(rdf_descriptor->Extensions[i], LV2_WORKER__interface) == 0)
m_hints |= PLUGIN_HAS_EXTENSION_WORKER;
else
qDebug("Plugin has non-supported extension: '%s'", rdf_descriptor->Extensions[i]);
}
@@ -2260,6 +2336,16 @@ public:
if (can_continue)
{
// Initialize features
LV2_Event_Feature* Event_Feature = new LV2_Event_Feature;
Event_Feature->callback_data = this;
Event_Feature->lv2_event_ref = carla_lv2_event_ref;
Event_Feature->lv2_event_unref = carla_lv2_event_unref;

LV2_Log_Log* Log_Feature = new LV2_Log_Log;
Log_Feature->handle = this;
Log_Feature->printf = carla_lv2_log_printf;
Log_Feature->vprintf = carla_lv2_log_vprintf;

LV2_URI_Map_Feature* URI_Map_Feature = new LV2_URI_Map_Feature;
URI_Map_Feature->callback_data = this;
URI_Map_Feature->uri_to_id = carla_lv2_uri_to_id;
@@ -2272,29 +2358,44 @@ public:
URID_Unmap_Feature->handle = this;
URID_Unmap_Feature->unmap = carla_lv2_urid_unmap;

LV2_Event_Feature* Event_Feature = new LV2_Event_Feature;
Event_Feature->callback_data = this;
Event_Feature->lv2_event_ref = nullptr;
Event_Feature->lv2_event_unref = nullptr;
LV2_Worker_Schedule* Worker_Feature = new LV2_Worker_Schedule;
Worker_Feature->handle = this;
Worker_Feature->schedule_work = carla_lv2_worker_schedule;

LV2_Programs_Host* Programs_Feature = new LV2_Programs_Host;
Programs_Feature->handle = this;
Programs_Feature->program_changed = carla_lv2_program_changed;

lv2_rtsafe_memory_pool_provider* RT_MemPool_Feature = new lv2_rtsafe_memory_pool_provider;
rtmempool_allocator_init(RT_MemPool_Feature);

features[lv2_feature_id_event] = new LV2_Feature;
features[lv2_feature_id_event]->URI = LV2_EVENT_URI;
features[lv2_feature_id_event]->data = Event_Feature;

features[lv2_feature_id_logs] = new LV2_Feature;
features[lv2_feature_id_logs]->URI = LV2_LOG__log;
features[lv2_feature_id_logs]->data = Log_Feature;

features[lv2_feature_id_uri_map] = new LV2_Feature;
features[lv2_feature_id_uri_map]->URI = LV2_URI_MAP_URI;
features[lv2_feature_id_uri_map]->data = URI_Map_Feature;

features[lv2_feature_id_urid_map] = new LV2_Feature;
features[lv2_feature_id_urid_map]->URI = LV2_URID_MAP_URI;
features[lv2_feature_id_urid_map]->URI = LV2_URID__map;
features[lv2_feature_id_urid_map]->data = URID_Map_Feature;

features[lv2_feature_id_urid_unmap] = new LV2_Feature;
features[lv2_feature_id_urid_unmap]->URI = LV2_URID_UNMAP_URI;
features[lv2_feature_id_urid_unmap]->URI = LV2_URID__unmap;
features[lv2_feature_id_urid_unmap]->data = URID_Unmap_Feature;

features[lv2_feature_id_event] = new LV2_Feature;
features[lv2_feature_id_event]->URI = LV2_EVENT_URI;
features[lv2_feature_id_event]->data = Event_Feature;
features[lv2_feature_id_worker] = new LV2_Feature;
features[lv2_feature_id_worker]->URI = LV2_WORKER__schedule;
features[lv2_feature_id_worker]->data = Worker_Feature;

features[lv2_feature_id_programs] = new LV2_Feature;
features[lv2_feature_id_programs]->URI = LV2_PROGRAMS__Host;
features[lv2_feature_id_programs]->data = Programs_Feature;

features[lv2_feature_id_rtmempool] = new LV2_Feature;
features[lv2_feature_id_rtmempool]->URI = LV2_RTSAFE_MEMORY_POOL_URI;
@@ -2420,16 +2521,20 @@ public:
else
{
// Initialize UI features
LV2_Extension_Data_Feature* UI_Data_Feature = new LV2_Extension_Data_Feature;
UI_Data_Feature->data_access = descriptor->extension_data;
LV2_Extension_Data_Feature* UI_Data_Feature = new LV2_Extension_Data_Feature;
UI_Data_Feature->data_access = descriptor->extension_data;

LV2UI_Port_Map* UI_PortMap_Feature = new LV2UI_Port_Map;
UI_PortMap_Feature->handle = this;
UI_PortMap_Feature->port_index = carla_lv2_ui_port_map;

lv2_external_ui_host* External_UI_Feature = new lv2_external_ui_host;
External_UI_Feature->ui_closed = carla_lv2_external_ui_closed;
External_UI_Feature->plugin_human_id = strdup(gui_title.toUtf8().constData()); // NOTE
LV2UI_Resize* UI_Resize_Feature = new LV2UI_Resize;
UI_Resize_Feature->handle = this;
UI_Resize_Feature->ui_resize = carla_lv2_ui_resize;

LV2UI_Resize* UI_Resize_Feature = new LV2UI_Resize;
UI_Resize_Feature->handle = this;
UI_Resize_Feature->ui_resize = carla_lv2_ui_resize;
lv2_external_ui_host* External_UI_Feature = new lv2_external_ui_host;
External_UI_Feature->ui_closed = carla_lv2_external_ui_closed;
External_UI_Feature->plugin_human_id = strdup(gui_title.toUtf8().constData());

features[lv2_feature_id_data_access] = new LV2_Feature;
features[lv2_feature_id_data_access]->URI = LV2_DATA_ACCESS_URI;
@@ -2443,6 +2548,10 @@ public:
features[lv2_feature_id_ui_parent]->URI = LV2_UI__parent;
features[lv2_feature_id_ui_parent]->data = nullptr;

features[lv2_feature_id_ui_port_map] = new LV2_Feature;
features[lv2_feature_id_ui_port_map]->URI = LV2_UI__portMap;
features[lv2_feature_id_ui_port_map]->data = UI_PortMap_Feature;

features[lv2_feature_id_ui_resize] = new LV2_Feature;
features[lv2_feature_id_ui_resize]->URI = LV2_UI__resize;
features[lv2_feature_id_ui_resize]->data = UI_Resize_Feature;
@@ -2520,8 +2629,6 @@ public:
m_hints |= PLUGIN_HAS_GUI;
#endif

qDebug("-------------------------------------------- %p", programs.ui);

return true;
}
else
@@ -2600,31 +2707,93 @@ public:
#endif
}

// ----------------- Event Feature ---------------------------------------------------
static uint32_t carla_lv2_event_ref(LV2_Event_Callback_Data callback_data, LV2_Event* event)
{
qDebug("Lv2Plugin::carla_lv2_event_ref(%p, %p)", callback_data, event);
return 0;
}

static uint32_t carla_lv2_event_unref(LV2_Event_Callback_Data callback_data, LV2_Event* event)
{
qDebug("Lv2Plugin::carla_lv2_event_unref(%p, %p)", callback_data, event);
return 0;
}

// ----------------- Logs Feature ----------------------------------------------------
static int carla_lv2_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list ap)
{
qDebug("Lv2Plugin::carla_lv2_log_vprintf(%p, %i, %s, ...)", handle, type, fmt);

char buf[8196];
vsprintf(buf, fmt, ap);

switch (type)
{
case CARLA_URI_MAP_ID_LOG_ERROR:
qCritical("%s", buf);
break;
case CARLA_URI_MAP_ID_LOG_NOTE:
printf("%s", buf);
break;
case CARLA_URI_MAP_ID_LOG_TRACE:
qDebug("%s", buf);
break;
case CARLA_URI_MAP_ID_LOG_WARNING:
qWarning("%s", buf);
break;
default:
break;
}

return 0;
}

static int carla_lv2_log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...)
{
qDebug("Lv2Plugin::carla_lv2_log_printf(%p, %i, %s, ...)", handle, type, fmt);

va_list args;
va_start(args, fmt);
const int ret = carla_lv2_log_vprintf(handle, type, fmt, args);
va_end(args);

return ret;
}

// ----------------- URI-Map Feature -------------------------------------------------
static uint32_t carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char* map, const char* uri)
{
qDebug("Lv2Plugin::carla_lv2_uri_to_id(%p, %s, %s)", data, map, uri);

// Event types
if (map && strcmp(map, LV2_EVENT_URI) == 0)
{
// Event types
if (strcmp(uri, "http://lv2plug.in/ns/ext/midi#MidiEvent") == 0)
if (strcmp(uri, LV2_MIDI__MidiEvent) == 0)
return CARLA_URI_MAP_ID_MIDI_EVENT;
else if (strcmp(uri, "http://lv2plug.in/ns/ext/time#Position") == 0)
else if (strcmp(uri, LV2_TIME__Position) == 0)
return CARLA_URI_MAP_ID_TIME_POSITION;
}

// Atom types
else if (strcmp(uri, LV2_ATOM__Chunk) == 0)
{
return CARLA_URI_MAP_ID_ATOM_CHUNK;
}
else if (strcmp(uri, LV2_ATOM__Sequence) == 0)
{
return CARLA_URI_MAP_ID_ATOM_SEQUENCE;
}
else if (strcmp(uri, LV2_ATOM__String) == 0)
{
return CARLA_URI_MAP_ID_ATOM_STRING;
}

// Log types
else if (strcmp(uri, LV2_LOG__Error) == 0)
return CARLA_URI_MAP_ID_LOG_ERROR;
else if (strcmp(uri, LV2_LOG__Note) == 0)
return CARLA_URI_MAP_ID_LOG_NOTE;
else if (strcmp(uri, LV2_LOG__Trace) == 0)
return CARLA_URI_MAP_ID_LOG_TRACE;
else if (strcmp(uri, LV2_LOG__Warning) == 0)
return CARLA_URI_MAP_ID_LOG_WARNING;

// TODO - position types

// Custom types
if (data)
@@ -2641,10 +2810,13 @@ public:
{
qDebug("Lv2Plugin::carla_lv2_urid_map(%p, %s)", handle, uri);

if (strcmp(uri, "http://lv2plug.in/ns/ext/midi#MidiEvent") == 0)
// Event types
if (strcmp(uri, LV2_MIDI__MidiEvent) == 0)
return CARLA_URI_MAP_ID_MIDI_EVENT;
else if (strcmp(uri, "http://lv2plug.in/ns/ext/time#Position") == 0)
else if (strcmp(uri, LV2_TIME__Position) == 0)
return CARLA_URI_MAP_ID_TIME_POSITION;

// Atom types
else if (strcmp(uri, LV2_ATOM__Chunk) == 0)
return CARLA_URI_MAP_ID_ATOM_CHUNK;
else if (strcmp(uri, LV2_ATOM__Sequence) == 0)
@@ -2652,6 +2824,18 @@ public:
else if (strcmp(uri, LV2_ATOM__String) == 0)
return CARLA_URI_MAP_ID_ATOM_STRING;

// Log types
else if (strcmp(uri, LV2_LOG__Error) == 0)
return CARLA_URI_MAP_ID_LOG_ERROR;
else if (strcmp(uri, LV2_LOG__Note) == 0)
return CARLA_URI_MAP_ID_LOG_NOTE;
else if (strcmp(uri, LV2_LOG__Trace) == 0)
return CARLA_URI_MAP_ID_LOG_TRACE;
else if (strcmp(uri, LV2_LOG__Warning) == 0)
return CARLA_URI_MAP_ID_LOG_WARNING;

// TODO - position types

// Custom types
if (handle)
{
@@ -2666,10 +2850,13 @@ public:
{
qDebug("Lv2Plugin::carla_lv2_urid_unmap(%p, %i)", handle, urid);

// Event types
if (urid == CARLA_URI_MAP_ID_MIDI_EVENT)
return "http://lv2plug.in/ns/ext/midi#MidiEvent";
return LV2_MIDI__MidiEvent;
else if (urid == CARLA_URI_MAP_ID_TIME_POSITION)
return "http://lv2plug.in/ns/ext/time#Position";
return LV2_TIME__Position;

// Atom types
else if (urid == CARLA_URI_MAP_ID_ATOM_CHUNK)
return LV2_ATOM__Chunk;
else if (urid == CARLA_URI_MAP_ID_ATOM_SEQUENCE)
@@ -2677,6 +2864,16 @@ public:
else if (urid == CARLA_URI_MAP_ID_ATOM_STRING)
return LV2_ATOM__String;

// Log types
else if (urid == CARLA_URI_MAP_ID_LOG_ERROR)
return LV2_LOG__Error;
else if (urid == CARLA_URI_MAP_ID_LOG_NOTE)
return LV2_LOG__Note;
else if (urid == CARLA_URI_MAP_ID_LOG_TRACE)
return LV2_LOG__Trace;
else if (urid == CARLA_URI_MAP_ID_LOG_WARNING)
return LV2_LOG__Warning;

// Custom types
if (handle)
{
@@ -2697,7 +2894,7 @@ public:
Lv2Plugin* plugin = (Lv2Plugin*)handle;
const char* uri_key = plugin->get_custom_uri_string(key);

if (uri_key > 0 && (flags & LV2_STATE_IS_POD) > 0)
if (uri_key > 0 && (flags & LV2_STATE_IS_POD) > 0 && value)
{
qDebug("Lv2Plugin::carla_lv2_state_store(%p, %i, %p, " P_SIZE ", %i, %i) - Got uri_key and flags", handle, key, value, size, type, flags);

@@ -2705,12 +2902,12 @@ public:

if (type == CARLA_URI_MAP_ID_ATOM_STRING)
dtype = CUSTOM_DATA_STRING;
else if (type >= CARLA_URI_MAP_ID_COUNT)
else if (type == CARLA_URI_MAP_ID_ATOM_CHUNK || type >= CARLA_URI_MAP_ID_COUNT)
dtype = CUSTOM_DATA_BINARY;
else
dtype = CUSTOM_DATA_INVALID;

if (value && dtype != CUSTOM_DATA_INVALID)
if (dtype != CUSTOM_DATA_INVALID)
{
// Check if we already have this key
for (int i=0; i < plugin->custom.count(); i++)
@@ -2720,7 +2917,9 @@ public:
free((void*)plugin->custom[i].value);

if (dtype == CUSTOM_DATA_STRING)
{
plugin->custom[i].value = strdup((const char*)value);
}
else
{
QByteArray chunk((const char*)value, size);
@@ -2737,7 +2936,9 @@ public:
new_data.key = strdup(uri_key);

if (dtype == CUSTOM_DATA_STRING)
{
new_data.value = strdup((const char*)value);
}
else
{
QByteArray chunk((const char*)value, size);
@@ -2756,7 +2957,7 @@ public:
}
else
{
qWarning("Lv2Plugin::carla_lv2_state_store(%p, %i, %p, " P_SIZE ", %i, %i) - Invalid attributes", handle, key, value, size, type, flags);
qWarning("Lv2Plugin::carla_lv2_state_store(%p, %i, %p, " P_SIZE ", %i, %i) - Invalid key, flags or value", handle, key, value, size, type, flags);
return LV2_STATE_ERR_BAD_FLAGS;
}
}
@@ -2826,41 +3027,121 @@ public:
return nullptr;
}

// ----------------- External UI Feature ---------------------------------------------
static void carla_lv2_external_ui_closed(LV2UI_Controller controller)
// ----------------- Worker Feature --------------------------------------------------
static LV2_Worker_Status carla_lv2_worker_schedule(LV2_Worker_Schedule_Handle handle, uint32_t size, const void* data)
{
qDebug("Lv2Plugin::carla_lv2_external_ui_closed(%p)", controller);
qDebug("Lv2Plugin::carla_lv2_worker_schedule(%p, %i, %p)", handle, size, data);

if (controller)
if (handle)
{
Lv2Plugin* plugin = (Lv2Plugin*)controller;
plugin->gui.visible = false;
Lv2Plugin* plugin = (Lv2Plugin*)handle;

if (plugin->ui.descriptor->cleanup)
plugin->ui.descriptor->cleanup(plugin->ui.handle);
if (carla_jack_on_freewheel())
{
PluginPostEvent event;
event.valid = true;
event.type = PostEventCustom;
event.index = size;
event.value = 0.0;
event.cdata = data;
plugin->run_custom_event(&event);
}
else
plugin->postpone_event(PostEventCustom, size, 0.0, data);

plugin->ui.handle = nullptr;
callback_action(CALLBACK_SHOW_GUI, plugin->id(), 0, 0, 0.0);
return LV2_WORKER_SUCCESS;
}

return LV2_WORKER_ERR_UNKNOWN;
}

static LV2_Worker_Status carla_lv2_worker_respond(LV2_Worker_Respond_Handle handle, uint32_t size, const void* data)
{
qDebug("Lv2Plugin::carla_lv2_worker_respond(%p, %i, %p)", handle, size, data);

if (handle)
{
Lv2Plugin* plugin = (Lv2Plugin*)handle;

if (plugin->ext.worker)
{
plugin->ext.worker->work_response(plugin->handle, size, data);
return LV2_WORKER_SUCCESS;
}
}

return LV2_WORKER_ERR_UNKNOWN;
}

// ----------------- DynParam Feature ------------------------------------------------
// TODO

// ----------------- Programs Feature ------------------------------------------------
static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index)
{
qDebug("Lv2Plugin::carla_lv2_program_changed(%p, %i)", handle, index);

if (handle)
{
Lv2Plugin* plugin = (Lv2Plugin*)handle;
plugin->update_program(index);
}
}

// ----------------- UI Port-Map Feature ---------------------------------------------
static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol)
{
qDebug("Lv2Plugin::carla_lv2_ui_port_map(%p, %s)", handle, symbol);

if (handle)
{
Lv2Plugin* plugin = (Lv2Plugin*)handle;

for (uint32_t i=0; i < plugin->rdf_descriptor->PortCount; i++)
{
if (strcmp(plugin->rdf_descriptor->Ports[i].Symbol, symbol) == 0)
return i;
}
}

return 0;
}

// ----------------- UI Resize Feature -----------------------------------------------
static int carla_lv2_ui_resize(LV2UI_Feature_Handle data, int width, int height)
static int carla_lv2_ui_resize(LV2UI_Feature_Handle handle, int width, int height)
{
qDebug("Lv2Plugin::carla_lv2_ui_resized(%p, %i, %i)", data, width, height);
qDebug("Lv2Plugin::carla_lv2_ui_resize(%p, %i, %i)", handle, width, height);

if (data)
if (handle)
{
Lv2Plugin* plugin = (Lv2Plugin*)data;
Lv2Plugin* plugin = (Lv2Plugin*)handle;
plugin->gui.width = width;
plugin->gui.height = height;
callback_action(CALLBACK_RESIZE_GUI, plugin->id(), width, height, 0.0);
callback_action(CALLBACK_RESIZE_GUI, plugin->m_id, width, height, 0.0);
return 0;
}

return 1;
}

// ----------------- External UI Feature ---------------------------------------------
static void carla_lv2_external_ui_closed(LV2UI_Controller controller)
{
qDebug("Lv2Plugin::carla_lv2_external_ui_closed(%p)", controller);

if (controller)
{
Lv2Plugin* plugin = (Lv2Plugin*)controller;
plugin->gui.visible = false;

if (plugin->ui.handle && plugin->ui.descriptor && plugin->ui.descriptor->cleanup)
plugin->ui.descriptor->cleanup(plugin->ui.handle);

plugin->ui.handle = nullptr;
callback_action(CALLBACK_SHOW_GUI, plugin->m_id, 0, 0, 0.0);
}
}

// ----------------- UI Extension ----------------------------------------------------
static void carla_lv2_ui_write_function(LV2UI_Controller controller, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
{
@@ -2870,22 +3151,34 @@ public:
{
Lv2Plugin* plugin = (Lv2Plugin*)controller;

if (format == 0 && buffer_size == sizeof(float))
if (format == 0)
{
int32_t param_id = -1;
float value = *(float*)buffer;

for (uint32_t i=0; i < plugin->param.count; i++)
if (buffer_size == sizeof(float))
{
if (plugin->param.data[i].rindex == (int32_t)port_index)
{
param_id = i; //plugin->param.data[i].index;
break;
}
float value = *(float*)buffer;
plugin->set_parameter_value_rindex(port_index, value, false, true, true);
}
}
else if (format == CARLA_URI_MAP_ID_MIDI_EVENT)
{
const uint8_t* data = (const uint8_t*)buffer;
uint8_t status = data[0];

if (param_id > -1) // && plugin->ctrl.data[param_id].type == PARAMETER_INPUT
plugin->set_parameter_value(param_id, value, false, true, true);
// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && data[2] == 0)
status -= 0x10;

if (MIDI_IS_STATUS_NOTE_OFF(status))
{
uint8_t note = data[2];
plugin->send_midi_note(false, note, 0, false, true, true);
}
else if (MIDI_IS_STATUS_NOTE_ON(status))
{
uint8_t note = data[2];
uint8_t velo = data[3];
plugin->send_midi_note(true, note, velo, false, true, true);
}
}
}
}
@@ -2897,9 +3190,12 @@ private:
LV2_Feature* features[lv2_feature_count+1];

struct {
LV2_Programs_Interface* plugin;
LV2_Programs_UI_Interface* ui;
} programs;
lv2dynparam_plugin_callbacks* dynparam;
LV2_State_Interface* state;
LV2_Worker_Interface* worker;
LV2_Programs_Interface* programs;
LV2_Programs_UI_Interface* uiprograms;
} ext;

struct {
void* lib;


+ 2
- 6
src/carla/lv2_rdf.h View File

@@ -18,7 +18,7 @@
#ifndef LV2_RDF_INCLUDED
#define LV2_RDF_INCLUDED

#include <stdint.h>
#include <cstdint>

// Base Types
typedef float LV2_Data;
@@ -1144,8 +1144,6 @@ inline const LV2_RDF_Descriptor* lv2_rdf_new(const char* URI)

rdf_descriptor->PresetCount = Presets.size();

qDebug("-------------------- preset count %i", rdf_descriptor->PresetCount);

if (rdf_descriptor->PresetCount > 0)
{
rdf_descriptor->Presets = new LV2_RDF_Preset [rdf_descriptor->PresetCount];
@@ -1173,8 +1171,6 @@ inline const LV2_RDF_Descriptor* lv2_rdf_new(const char* URI)
else
RDF_Preset->Label = nullptr;

qDebug("-------------------- preset @%i -> %s | %s", h, RDF_Preset->URI, RDF_Preset->Label);

// ------------------------------------------
// Set Preset Ports

@@ -1204,7 +1200,7 @@ inline const LV2_RDF_Descriptor* lv2_rdf_new(const char* URI)
RDF_Preset->Ports = nullptr;

// ------------------------------------------
// Set Preset States
// Set Preset States, TODO

RDF_Preset->StateCount = 0;
}


+ 1
- 1
src/carla/sf2.cpp View File

@@ -1014,7 +1014,7 @@ public:

if (m_active)
{
bool do_balance = (m_hints & PLUGIN_CAN_BALANCE) > 0 && (x_bal_left != -1.0 || x_bal_right != 1.0);
bool do_balance = (x_bal_left != -1.0 || x_bal_right != 1.0);

double bal_rangeL, bal_rangeR;
jack_audio_sample_t old_bal_left[nframes];


+ 1
- 0
src/carla/vst.cpp View File

@@ -50,6 +50,7 @@
#define kPlugCategGenerator 11
#define kVstProcessLevelUser 1
#define kVstProcessLevelRealtime 2
#define kVstProcessLevelOffline 4
#define kVstProcessPrecision32 0
#define kVstTransportChanged 1
#define kVstVersion 2400


Loading…
Cancel
Save