Browse Source

Continue work on carla-native plugins, basic FX now working

tags/1.9.4
falkTX 11 years ago
parent
commit
6b1cda235c
5 changed files with 796 additions and 63 deletions
  1. +4
    -3
      source/backend/plugin/NativePlugin.cpp
  2. +6
    -0
      source/plugin/Makefile
  3. +3
    -8
      source/plugin/carla-native-base.cpp
  4. +45
    -20
      source/plugin/carla-native-export.cpp
  5. +738
    -32
      source/plugin/carla-native-plugin.cpp

+ 4
- 3
source/backend/plugin/NativePlugin.cpp View File

@@ -224,10 +224,11 @@ public:
#endif

carla_zeroStruct< ::MidiEvent>(fMidiEvents, MAX_MIDI_EVENTS*2);
carla_zeroStruct< ::TimeInfo>(fTimeInfo);

fHost.handle = this;
fHost.resource_dir = carla_strdup((const char*)engine->getOptions().resourceDir);
fHost.ui_name = nullptr;
fHost.handle = this;
fHost.resourceDir = carla_strdup((const char*)engine->getOptions().resourceDir);
fHost.uiName = nullptr;

fHost.get_buffer_size = carla_host_get_buffer_size;
fHost.get_sample_rate = carla_host_get_sample_rate;


+ 6
- 0
source/plugin/Makefile View File

@@ -8,6 +8,12 @@ include ../Makefile.mk

BUILD_CXX_FLAGS += -I../backend -I../includes -I../modules -I../modules/utils

ifeq ($(HAVE_QT4),true)
BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore QtGui)
else
BUILD_CXX_FLAGS += $(shell pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets)
endif

# --------------------------------------------------------------

ifeq ($(HAVE_OPENGL),true)


+ 3
- 8
source/plugin/carla-native-base.cpp View File

@@ -35,10 +35,8 @@ void carla_register_native_plugin_midiTranspose();
void carla_register_native_plugin_nekofilter();
//void carla_register_native_plugin_sunvoxfile();

#if 0 //ndef BUILD_BRIDGE
// Carla
void carla_register_native_plugin_carla();
#endif
//void carla_register_native_plugin_carla();

#ifdef WANT_AUDIOFILE
// AudioFile
@@ -84,10 +82,8 @@ struct PluginListManager {
carla_register_native_plugin_nekofilter();
//carla_register_native_plugin_sunvoxfile(); // unfinished

#if 0 //ndef BUILD_BRIDGE
// Carla
carla_register_native_plugin_carla(); // kinda unfinished
#endif
//carla_register_native_plugin_carla(); // kinda unfinished

#ifdef WANT_AUDIOFILE
// AudioFile
@@ -119,10 +115,9 @@ struct PluginListManager {

~PluginListManager()
{
for (auto it = lv2Descs.begin(); it.valid(); it.next())
for (NonRtList<const LV2_Descriptor*>::Itenerator it = lv2Descs.begin(); it.valid(); it.next())
{
const LV2_Descriptor*& lv2Desc(*it);

delete[] lv2Desc->URI;
delete lv2Desc;
}


+ 45
- 20
source/plugin/carla-native-export.cpp View File

@@ -223,30 +223,52 @@ void writePluginFile(const PluginDescriptor* const pluginDesc)
text += "\n";
}

// -------------------------------------------------------------------
// First MIDI/Time port

text += " lv2:port [\n";
text += " a lv2:InputPort, atom:AtomPort ;\n";
text += " atom:bufferType atom:Sequence ;\n";

if (pluginDesc->midiIns > 0)
{
text += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n";
text += " <" LV2_TIME__Position "> ;\n";
}
else
{
text += " atom:supports <" LV2_TIME__Position "> ;\n";
}

text += " lv2:designation lv2:control ;\n";
text += " lv2:index 0" + String(portIndex++) + " ;\n";

if (pluginDesc->midiIns > 1)
{
text += " lv2:symbol \"lv2_events_in_1\" ;\n";
text += " lv2:name \"Events Input #1\" ;\n";
}
else
{
text += " lv2:symbol \"lv2_events_in\" ;\n";
text += " lv2:name \"Events Input\" ;\n";
}

text += " ] ;\n\n";

// -------------------------------------------------------------------
// MIDI inputs

for (uint32_t i=0; i < pluginDesc->midiIns; ++i)
for (uint32_t i=1; i < pluginDesc->midiIns; ++i)
{
if (i == 0)
if (i == 1)
text += " lv2:port [\n";
else
text += " [\n";

text += " a lv2:InputPort, atom:AtomPort ;\n";
text += " atom:bufferType atom:Sequence ;\n";

if (i == 0)
{
text += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n";
text += " <" LV2_TIME__Position "> ;\n";
text += " lv2:designation lv2:control ;\n";
}
else
{
text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
}

text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
text += " lv2:index " + String(portIndex++) + " ;\n";

if (pluginDesc->midiIns > 1)
@@ -370,9 +392,8 @@ void writePluginFile(const PluginDescriptor* const pluginDesc)
for (uint32_t i=0; i < paramCount; ++i)
{
const Parameter* paramInfo(pluginDesc->get_parameter_info(pluginHandle, i));
const String paramName(paramInfo->name);
const String paramName(paramInfo->name != nullptr ? paramInfo->name : "");
const String paramUnit(paramInfo->unit != nullptr ? paramInfo->unit : "");
const float paramValue(pluginDesc->get_parameter_value(pluginHandle, i));

CARLA_SAFE_ASSERT_RETURN(paramInfo != nullptr,)

@@ -381,7 +402,11 @@ void writePluginFile(const PluginDescriptor* const pluginDesc)
else
text += " [\n";

text += " a lv2:InputPort, lv2:ControlPort ;\n";
if (paramInfo->hints & PARAMETER_IS_OUTPUT)
text += " a lv2:OutputPort, lv2:ControlPort ;\n";
else
text += " a lv2:InputPort, lv2:ControlPort ;\n";

text += " lv2:index " + String(portIndex++) + " ;\n";
text += " lv2:symbol \"" + nameToSymbol(paramName, i) + "\" ;\n";

@@ -390,9 +415,9 @@ void writePluginFile(const PluginDescriptor* const pluginDesc)
else
text += " lv2:name \"Port " + String(i+1) + "\" ;\n";

text += " lv2:default " + String::formatted("%f", paramValue) + " ;\n";
text += " lv2:minimum 0.0 ;\n";
text += " lv2:maximum 1.0 ;\n";
text += " lv2:default " + String::formatted("%f", paramInfo->ranges.def) + " ;\n";
text += " lv2:minimum " + String::formatted("%f", paramInfo->ranges.min) + " ;\n";
text += " lv2:maximum " + String::formatted("%f", paramInfo->ranges.max) + " ;\n";

if (paramUnit.isNotEmpty())
{


+ 738
- 32
source/plugin/carla-native-plugin.cpp View File

@@ -19,26 +19,725 @@

#include "CarlaString.hpp"

#include "lv2/atom.h"
#include "lv2/buf-size.h"
#include "lv2/options.h"
#include "lv2/state.h"
#include "lv2/ui.h"

#include <QtCore/Qt>

#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
# include <QtWidgets/QFileDialog>
#else
# include <QtGui/QFileDialog>
#endif

// -----------------------------------------------------------------------
// LV2 descriptor functions

class NativePlugin
{
public:
static const uint32_t kMaxMidiEvents = 512;

NativePlugin(const PluginDescriptor* const desc, const double sampleRate, const char* const bundlePath, const LV2_Feature* const* features)
: fHandle(nullptr),
fDescriptor(desc),
fIsProcessing(false),
fIsUiVisible(false),
fMidiEventCount(0),
fBufferSize(0),
fSampleRate(sampleRate),
fFeatures(features)
{
fHost.handle = this;
fHost.resourceDir = carla_strdup(bundlePath);
fHost.uiName = nullptr;

fHost.get_buffer_size = carla_host_get_buffer_size;
fHost.get_sample_rate = carla_host_get_sample_rate;
fHost.is_offline = carla_host_is_offline;
fHost.get_time_info = carla_host_get_time_info;
fHost.write_midi_event = carla_host_write_midi_event;
fHost.ui_parameter_changed = carla_host_ui_parameter_changed;
fHost.ui_custom_data_changed = carla_host_ui_custom_data_changed;
fHost.ui_closed = carla_host_ui_closed;
fHost.ui_open_file = carla_host_ui_open_file;
fHost.ui_save_file = carla_host_ui_save_file;
fHost.dispatcher = carla_host_dispatcher;

const LV2_Options_Option* options = nullptr;
const LV2_URID_Map* uridMap = nullptr;

for (int i=0; features[i] != nullptr; ++i)
{
if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
options = (const LV2_Options_Option*)features[i]->data;
else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
uridMap = (const LV2_URID_Map*)features[i]->data;
}

if (uridMap == nullptr || options == nullptr)
return;

for (int i=0; options[i].key != 0; ++i)
{
if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength))
{
if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
fBufferSize = *(const int*)options[i].value;
else
carla_stderr("Host provides maxBlockLength but has wrong value type");
break;
}
}
}

~NativePlugin()
{
CARLA_ASSERT(fHandle != nullptr);

if (fHost.resourceDir != nullptr)
{
delete[] fHost.resourceDir;
fHost.resourceDir = nullptr;
}
}

bool init()
{
if (fDescriptor->instantiate == nullptr || fDescriptor->process == nullptr || fBufferSize == 0)
return false;

fHandle = fDescriptor->instantiate(&fHost);

if (fHandle == nullptr)
return false;

carla_zeroStruct<MidiEvent>(fMidiEvents, kMaxMidiEvents*2);
carla_zeroStruct<TimeInfo>(fTimeInfo);
fPorts.init(fDescriptor, fHandle);
return true;
}

// -------------------------------------------------------------------
// LV2 functions

void lv2_connect_port(const uint32_t port, void* const dataLocation)
{
fPorts.connectPort(fDescriptor, port, dataLocation);
}

void lv2_activate()
{
if (fDescriptor->activate != nullptr)
fDescriptor->activate(fHandle);
}

void lv2_deactivate()
{
if (fDescriptor->deactivate != nullptr)
fDescriptor->deactivate(fHandle);
}

void lv2_cleanup()
{
if (fDescriptor->cleanup != nullptr)
fDescriptor->cleanup(fHandle);
}

void lv2_run(const uint32_t frames)
{
if (frames == 0)
{
updateParameterOutputs();
return;
}

// Check for updated parameters
float curValue;

for (uint32_t i=0; i < fPorts.paramCount; ++i)
{
CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)

curValue = *fPorts.paramsPtr[i];

if (fPorts.paramsLast[i] != curValue && (fDescriptor->get_parameter_info(fHandle, i)->hints & PARAMETER_IS_OUTPUT) == 0)
{
fPorts.paramsLast[i] = curValue;
fDescriptor->set_parameter_value(fHandle, i, curValue);
}
}

fDescriptor->process(fHandle, fPorts.audioIns, fPorts.audioOuts, frames, fMidiEventCount, fMidiEvents);

updateParameterOutputs();
}

// -------------------------------------------------------------------

protected:
uint32_t handleGetBufferSize()
{
return fBufferSize;
}

double handleGetSampleRate()
{
return fSampleRate;
}

bool handleIsOffline()
{
CARLA_ASSERT(fIsProcessing);
return (fPorts.freewheel != nullptr && *fPorts.freewheel < 0.5f);
}

const TimeInfo* handleGetTimeInfo()
{
CARLA_ASSERT(fIsProcessing);
return &fTimeInfo;
}

bool handleWriteMidiEvent(const MidiEvent* const event)
{
CARLA_SAFE_ASSERT_RETURN(fIsProcessing, false);
CARLA_SAFE_ASSERT_RETURN(fDescriptor->midiOuts > 0, false);
CARLA_SAFE_ASSERT_RETURN(event != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false);

if (fMidiEventCount >= kMaxMidiEvents*2)
return false;

// reverse-find first free event, and put it there
for (uint32_t i=(kMaxMidiEvents*2)-1; i >= fMidiEventCount; --i)
{
if (fMidiEvents[i].data[0] == 0)
{
std::memcpy(&fMidiEvents[i], event, sizeof(MidiEvent));
break;
}
}

return true;
}

void handleUiParameterChanged(const uint32_t /*index*/, const float /*value*/)
{
//setParameterValue(index, value, false, true, true);
}

void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/)
{
//setCustomData(CUSTOM_DATA_STRING, key, value, false);
}

void handleUiClosed()
{
// call external ui close
fIsUiVisible = false;
}

const char* handleUiOpenFile(const bool isDir, const char* const title, const char* const filter)
{
static CarlaString retStr;
QFileDialog::Options options(isDir ? QFileDialog::ShowDirsOnly : 0x0);

retStr = QFileDialog::getOpenFileName(nullptr, title, "", filter, nullptr, options).toUtf8().constData();

return retStr.isNotEmpty() ? (const char*)retStr : nullptr;
}

const char* handleUiSaveFile(const bool isDir, const char* const title, const char* const filter)
{
static CarlaString retStr;
QFileDialog::Options options(isDir ? QFileDialog::ShowDirsOnly : 0x0);

retStr = QFileDialog::getSaveFileName(nullptr, title, "", filter, nullptr, options).toUtf8().constData();

return retStr.isNotEmpty() ? (const char*)retStr : nullptr;
}

intptr_t handleDispatcher(const ::HostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
{
carla_debug("NativePlugin::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", opcode, index, value, ptr, opt);

intptr_t ret = 0;

switch (opcode)
{
case HOST_OPCODE_NULL:
break;
case HOST_OPCODE_SET_VOLUME:
//setVolume(opt, true, true);
break;
case HOST_OPCODE_SET_DRYWET:
//setDryWet(opt, true, true);
break;
case HOST_OPCODE_SET_BALANCE_LEFT:
//setBalanceLeft(opt, true, true);
break;
case HOST_OPCODE_SET_BALANCE_RIGHT:
//setBalanceRight(opt, true, true);
break;
case HOST_OPCODE_SET_PANNING:
//setPanning(opt, true, true);
break;
case HOST_OPCODE_GET_PARAMETER_MIDI_CC:
case HOST_OPCODE_SET_PARAMETER_MIDI_CC:
break;
case HOST_OPCODE_SET_PROCESS_PRECISION:
break;
case HOST_OPCODE_UPDATE_PARAMETER:
break;
case HOST_OPCODE_UPDATE_MIDI_PROGRAM:
break;
case HOST_OPCODE_RELOAD_PARAMETERS:
break;
case HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
break;
case HOST_OPCODE_RELOAD_ALL:
break;
case HOST_OPCODE_UI_UNAVAILABLE:
//kData->engine->callback(CALLBACK_SHOW_GUI, fId, -1, 0, 0.0f, nullptr);
break;
}

return ret;

// unused for now
(void)index;
(void)value;
(void)ptr;
}

void updateParameterOutputs()
{
for (uint32_t i=0; i < fPorts.paramCount; ++i)
{
if (fDescriptor->get_parameter_info(fHandle, i)->hints & PARAMETER_IS_OUTPUT)
{
fPorts.paramsLast[i] = fDescriptor->get_parameter_value(fHandle, i);

if (fPorts.paramsPtr[i] != nullptr)
*fPorts.paramsPtr[i] = fPorts.paramsLast[i];
}
}
}

// -------------------------------------------------------------------

private:
// Native data
PluginHandle fHandle;
HostDescriptor fHost;
const PluginDescriptor* const fDescriptor;

bool fIsProcessing;
bool fIsUiVisible;

uint32_t fMidiEventCount;
MidiEvent fMidiEvents[kMaxMidiEvents*2];

TimeInfo fTimeInfo;

// Lv2 host data
uint32_t fBufferSize;
double fSampleRate;

const LV2_Feature* const* fFeatures;

struct Ports {
LV2_Atom_Sequence** eventsIn;
LV2_Atom_Sequence** midiOuts;
float** audioIns;
float** audioOuts;
float* freewheel;
uint32_t paramCount;
float* paramsLast;
float** paramsPtr;

Ports()
: eventsIn(nullptr),
midiOuts(nullptr),
audioIns(nullptr),
audioOuts(nullptr),
freewheel(nullptr),
paramCount(0),
paramsLast(nullptr),
paramsPtr(nullptr) {}

~Ports()
{
if (eventsIn != nullptr)
{
delete[] eventsIn;
eventsIn = nullptr;
}

if (midiOuts != nullptr)
{
delete[] midiOuts;
midiOuts = nullptr;
}

if (audioIns != nullptr)
{
delete[] audioIns;
audioIns = nullptr;
}

if (audioOuts != nullptr)
{
delete[] audioOuts;
audioOuts = nullptr;
}

if (paramsLast != nullptr)
{
delete[] paramsLast;
paramsLast = nullptr;
}

if (paramsPtr != nullptr)
{
delete[] paramsPtr;
paramsPtr = nullptr;
}
}

void init(const PluginDescriptor* const desc, PluginHandle handle)
{
if (desc->midiIns > 0)
{
eventsIn = new LV2_Atom_Sequence*[desc->midiIns];

for (uint32_t i=0; i < desc->midiIns; ++i)
eventsIn[i] = nullptr;
}
else
{
eventsIn = new LV2_Atom_Sequence*[1];
eventsIn[0] = nullptr;
}

if (desc->midiOuts > 0)
{
midiOuts = new LV2_Atom_Sequence*[desc->midiOuts];

for (uint32_t i=0; i < desc->midiOuts; ++i)
midiOuts[i] = nullptr;
}

if (desc->audioIns > 0)
{
audioIns = new float*[desc->audioIns];

for (uint32_t i=0; i < desc->audioIns; ++i)
audioIns[i] = nullptr;
}

if (desc->audioOuts > 0)
{
audioOuts = new float*[desc->audioOuts];

for (uint32_t i=0; i < desc->audioOuts; ++i)
audioOuts[i] = nullptr;
}

if (desc->get_parameter_count != nullptr && desc->get_parameter_info != nullptr && desc->get_parameter_value != nullptr && desc->set_parameter_value != nullptr)
{
paramCount = desc->get_parameter_count(handle);

if (paramCount > 0)
{
paramsLast = new float[paramCount];
paramsPtr = new float*[paramCount];

for (uint32_t i=0; i < paramCount; ++i)
{
paramsLast[i] = desc->get_parameter_value(handle, i);
paramsPtr[i] = nullptr;
}
}
}
}

void connectPort(const PluginDescriptor* const desc, const uint32_t port, void* const dataLocation)
{
uint32_t index = 0;

if (port == index++)
{
eventsIn[0] = (LV2_Atom_Sequence*)dataLocation;
return;
}

for (uint32_t i=1; i < desc->midiIns; ++i)
{
if (port == index++)
{
eventsIn[i] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

for (uint32_t i=0; i < desc->midiOuts; ++i)
{
if (port == index++)
{
midiOuts[i] = (LV2_Atom_Sequence*)dataLocation;
return;
}
}

if (port == index++)
{
freewheel = (float*)dataLocation;
return;
}

for (uint32_t i=0; i < desc->audioIns; ++i)
{
if (port == index++)
{
audioIns[i] = (float*)dataLocation;
return;
}
}

for (uint32_t i=0; i < desc->audioOuts; ++i)
{
if (port == index++)
{
audioOuts[i] = (float*)dataLocation;
return;
}
}

for (uint32_t i=0; i < paramCount; ++i)
{
if (port == index++)
{
paramsPtr[i] = (float*)dataLocation;
return;
}
}
}

} fPorts;

// -------------------------------------------------------------------

#define handlePtr ((NativePlugin*)handle)

static uint32_t carla_host_get_buffer_size(::HostHandle handle)
{
return handlePtr->handleGetBufferSize();
}

static double carla_host_get_sample_rate(::HostHandle handle)
{
return handlePtr->handleGetSampleRate();
}

static bool carla_host_is_offline(::HostHandle handle)
{
return handlePtr->handleIsOffline();
}

static const ::TimeInfo* carla_host_get_time_info(::HostHandle handle)
{
return handlePtr->handleGetTimeInfo();
}

static bool carla_host_write_midi_event(::HostHandle handle, const ::MidiEvent* event)
{
return handlePtr->handleWriteMidiEvent(event);
}

static void carla_host_ui_parameter_changed(::HostHandle handle, uint32_t index, float value)
{
handlePtr->handleUiParameterChanged(index, value);
}

static void carla_host_ui_custom_data_changed(::HostHandle handle, const char* key, const char* value)
{
handlePtr->handleUiCustomDataChanged(key, value);
}

static void carla_host_ui_closed(::HostHandle handle)
{
handlePtr->handleUiClosed();
}

static const char* carla_host_ui_open_file(::HostHandle handle, bool isDir, const char* title, const char* filter)
{
return handlePtr->handleUiOpenFile(isDir, title, filter);
}

static const char* carla_host_ui_save_file(::HostHandle handle, bool isDir, const char* title, const char* filter)
{
return handlePtr->handleUiSaveFile(isDir, title, filter);
}

static intptr_t carla_host_dispatcher(::HostHandle handle, ::HostDispatcherOpcode opcode, int32_t index, intptr_t value, void* ptr, float opt)
{
return handlePtr->handleDispatcher(opcode, index, value, ptr, opt);
}

#undef handlePtr

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePlugin)
};

// -----------------------------------------------------------------------
// Static LV2 Descriptor objects
// LV2 descriptor functions

static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
{
carla_debug("lv2_instantiate(%p, %g, %s, %p)", lv2Descriptor, sampleRate, bundlePath, features);

const PluginDescriptor* pluginDesc = nullptr;
const char* pluginLabel = nullptr;

if (std::strncmp(lv2Descriptor->URI, "http://kxstudio.sf.net/carla/plugins/", 37) == 0)
pluginLabel = lv2Descriptor->URI+37;
else if (std::strcmp(lv2Descriptor->URI, "http://kxstudio.sf.net/carla") == 0)
pluginLabel = lv2Descriptor->URI+23;

if (pluginLabel == nullptr)
{
carla_stderr("Failed to find carla native plugin with URI: \"%s\"", lv2Descriptor->URI);
return nullptr;
}

carla_debug("lv2_instantiate() - looking up label %s", pluginLabel);

for (NonRtList<const PluginDescriptor*>::Itenerator it = sPluginDescsMgr.descs.begin(); it.valid(); it.next())
{
const PluginDescriptor*& tmpDesc(*it);

if (std::strcmp(tmpDesc->label, pluginLabel) == 0)
{
pluginDesc = tmpDesc;
break;
}
}

if (pluginDesc == nullptr)
{
carla_stderr("Failed to find carla native plugin with label: \"%s\"", pluginLabel);
return nullptr;
}

NativePlugin* const plugin(new NativePlugin(pluginDesc, sampleRate, bundlePath, features));

if (! plugin->init())
{
carla_stderr("Failed to init plugin");
delete plugin;
return nullptr;
}

return (LV2_Handle)plugin;
}

#define instancePtr ((NativePlugin*)instance)

static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
{
instancePtr->lv2_connect_port(port, dataLocation);
}

static void lv2_activate(LV2_Handle instance)
{
carla_debug("lv2_activate(%p)", instance);
instancePtr->lv2_activate();
}

static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
{
instancePtr->lv2_run(sampleCount);
}

static void lv2_deactivate(LV2_Handle instance)
{
carla_debug("lv2_deactivate(%p)", instance);
instancePtr->lv2_deactivate();
}

static void lv2_cleanup(LV2_Handle instance)
{
carla_debug("lv2_cleanup(%p)", instance);
instancePtr->lv2_cleanup();
delete instancePtr;
}

#if 0
static uint32_t lv2_get_options(LV2_Handle instance, LV2_Options_Option* options)
{
carla_debug("lv2_()", );
return instancePtr->lv2_get_options(options);
}

static uint32_t lv2_set_options(LV2_Handle instance, const LV2_Options_Option* options)
{
carla_debug("lv2_()", );
return instancePtr->lv2_set_options(options);
}

static LV2_State_Status lv2_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features)
{
carla_debug("lv2_()", );
return instancePtr->lv2_save(store, handle, flags, features);
}

static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature* const* features)
{
carla_debug("lv2_()", );
return instancePtr->lv2_restore(retrieve, handle, flags, features);
}
#endif

static const void* lv2_extension_data(const char* uri)
{
carla_debug("lv2_extension_data(%s)", uri);

#if 0
static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options };
static const LV2_State_Interface state = { lv2_save, lv2_restore };

if (std::strcmp(uri, LV2_OPTIONS__interface) == 0)
return &options;
if (std::strcmp(uri, LV2_STATE__interface) == 0)
return &state;
#endif

return nullptr;
}

#undef instancePtr

// -----------------------------------------------------------------------
// Startup code

// CARLA_EXPORT void lv2_generate_ttl(const char* basename)
// {
// createLv2Files (basename);
// }

CARLA_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index)
{
carla_debug("lv2_descriptor(%i)", index);

if (index >= sPluginDescsMgr.descs.count())
{
carla_debug("lv2_descriptor(%i) - out of bounds", index);
return nullptr;
}
if (index < sPluginDescsMgr.lv2Descs.count())
{
carla_debug("lv2_descriptor(%i) - found previously allocated", index);
return sPluginDescsMgr.lv2Descs.getAt(index);
}

const PluginDescriptor*& pluginDesc(sPluginDescsMgr.descs.getAt(index));

@@ -54,38 +753,45 @@ CARLA_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index)
tmpURI += pluginDesc->label;
}

LV2_Descriptor* lv2Desc(new LV2_Descriptor);
carla_debug("lv2_descriptor(%i) - not found, allocating new with uri: %s", index, (const char*)tmpURI);

lv2Desc->URI = carla_strdup(tmpURI);
lv2Desc->instantiate = nullptr;
lv2Desc->connect_port = nullptr;
lv2Desc->activate = nullptr;
lv2Desc->run = nullptr;
lv2Desc->deactivate = nullptr;
lv2Desc->cleanup = nullptr;
lv2Desc->extension_data = nullptr;
const LV2_Descriptor* const lv2Desc(new const LV2_Descriptor{
/* URI */ carla_strdup(tmpURI),
/* instantiate */ lv2_instantiate,
/* connect_port */ lv2_connect_port,
/* activate */ lv2_activate,
/* run */ lv2_run,
/* deactivate */ lv2_deactivate,
/* cleanup */ lv2_cleanup,
/* extension_data */ lv2_extension_data
});

sPluginDescsMgr.lv2Descs.append(lv2Desc);

return lv2Desc;
return sPluginDescsMgr.lv2Descs.getLast();
}

// CARLA_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
// {
// switch (index)
// {
// case 0:
// return &JuceLv2UI_External;
// case 1:
// return &JuceLv2UI_Parent;
// default:
// return nullptr;
// }
// }
CARLA_EXPORT const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
{
carla_debug("lv2ui_descriptor(%i)", index);

// -----------------------------------------------------------------------
//if (index != 0)
return nullptr;

int main()
{
return 0;
#if 0
static const LV2UI_Descriptor lv2UiDesc = {
/* URI */ "http://kxstudio.sf.net/carla#UI",
/* instantiate */ lv2ui_instantiate,
/* connect_port */ nullptr,
/* activate */ nullptr,
/* run */ nullptr,
/* deactivate */ nullptr,
/* cleanup */ nullptr,
/* extension_data */ nullptr
};

return &lv2UiDesc;
#endif
}

// -----------------------------------------------------------------------

Loading…
Cancel
Save