Browse Source

Implement native vst3 plugin scanning; Cleanup

Signed-off-by: falkTX <falktx@falktx.com>
tags/v2.5.0
falkTX 2 years ago
parent
commit
1e5c9900ae
16 changed files with 903 additions and 106 deletions
  1. +506
    -37
      source/discovery/carla-discovery.cpp
  2. +1
    -1
      source/includes/CarlaDefines.h
  3. +9
    -5
      source/includes/travesty/audio_processor.h
  4. +40
    -29
      source/includes/travesty/base.h
  5. +3
    -2
      source/includes/travesty/bstream.h
  6. +3
    -2
      source/includes/travesty/component.h
  7. +23
    -7
      source/includes/travesty/edit_controller.h
  8. +15
    -2
      source/includes/travesty/events.h
  9. +29
    -4
      source/includes/travesty/factory.h
  10. +4
    -3
      source/includes/travesty/host.h
  11. +7
    -4
      source/includes/travesty/message.h
  12. +69
    -0
      source/includes/travesty/unit.h
  13. +16
    -9
      source/includes/travesty/view.h
  14. +36
    -0
      source/utils/CarlaMacUtils.cpp
  15. +13
    -0
      source/utils/CarlaMacUtils.hpp
  16. +129
    -1
      source/utils/CarlaVst3Utils.hpp

+ 506
- 37
source/discovery/carla-discovery.cpp View File

@@ -29,13 +29,6 @@
#include "CarlaVst3Utils.hpp" #include "CarlaVst3Utils.hpp"


#ifdef CARLA_OS_MAC #ifdef CARLA_OS_MAC
# define Component CocoaComponent
# define MemoryBlock CocoaMemoryBlock
# define Point CocoaPoint
# import <Foundation/Foundation.h>
# undef Component
# undef MemoryBlock
# undef Point
# include "CarlaMacUtils.cpp" # include "CarlaMacUtils.cpp"
# if defined(USING_JUCE) && defined(__aarch64__) # if defined(USING_JUCE) && defined(__aarch64__)
# include <spawn.h> # include <spawn.h>
@@ -74,6 +67,9 @@
# if JUCE_PLUGINHOST_VST # if JUCE_PLUGINHOST_VST
# define USING_JUCE_FOR_VST2 # define USING_JUCE_FOR_VST2
# endif # endif
# if JUCE_PLUGINHOST_VST3
# define USING_JUCE_FOR_VST3
# endif
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif


@@ -993,44 +989,31 @@ static intptr_t VSTCALLBACK vstHostCallback(AEffect* const effect, const int32_t
return ret; return ret;
} }


static void do_vst_check(lib_t& libHandle, const char* const filename, const bool doInit)
static void do_vst2_check(lib_t& libHandle, const char* const filename, const bool doInit)
{ {
VST_Function vstFn = nullptr; VST_Function vstFn = nullptr;


#ifdef CARLA_OS_MAC #ifdef CARLA_OS_MAC
CFBundleRef bundleRef = nullptr;
CFBundleRefNum resFileId = 0;
BundleLoader bundleLoader;


if (libHandle == nullptr) if (libHandle == nullptr)
{ {
const CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)filename, (CFIndex)strlen(filename), true);
CARLA_SAFE_ASSERT_RETURN(urlRef != nullptr,);

bundleRef = CFBundleCreate(kCFAllocatorDefault, urlRef);
CFRelease(urlRef);
CARLA_SAFE_ASSERT_RETURN(bundleRef != nullptr,);

if (! CFBundleLoadExecutable(bundleRef))
if (! bundleLoader.load(filename))
{ {
CFRelease(bundleRef);
DISCOVERY_OUT("error", "Failed to load VST bundle executable");
DISCOVERY_OUT("error", "Failed to load VST2 bundle executable");
return; return;
} }


vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("main_macho"));
vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleLoader.ref, CFSTR("main_macho"));


if (vstFn == nullptr) if (vstFn == nullptr)
vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("VSTPluginMain"));
vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleLoader.ref, CFSTR("VSTPluginMain"));


if (vstFn == nullptr) if (vstFn == nullptr)
{ {
CFBundleUnloadExecutable(bundleRef);
CFRelease(bundleRef);
DISCOVERY_OUT("error", "Not a VST plugin");
DISCOVERY_OUT("error", "Not a VST2 plugin");
return; return;
} }

resFileId = CFBundleOpenBundleResourceMap(bundleRef);
} }
else else
#endif #endif
@@ -1355,14 +1338,7 @@ static void do_vst_check(lib_t& libHandle, const char* const filename, const boo
effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f); effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
} }


#ifdef CARLA_OS_MAC
if (bundleRef != nullptr)
{
CFBundleCloseBundleResourceMap(bundleRef, resFileId);
CFBundleUnloadExecutable(bundleRef);
CFRelease(bundleRef);
}
#else
#ifndef CARLA_OS_MAC
return; return;


// unused // unused
@@ -1371,6 +1347,499 @@ static void do_vst_check(lib_t& libHandle, const char* const filename, const boo
} }
#endif // ! USING_JUCE_FOR_VST2 #endif // ! USING_JUCE_FOR_VST2


#ifndef USING_JUCE_FOR_VST3
static uint32_t V3_API v3_ref_static(void*) { return 1; }
static uint32_t V3_API v3_unref_static(void*) { return 0; }

struct carla_v3_host_application : v3_host_application_cpp {
carla_v3_host_application()
{
query_interface = carla_query_interface;
ref = v3_ref_static;
unref = v3_unref_static;
app.get_name = carla_get_name;
app.create_instance = carla_create_instance;
}

static v3_result V3_API carla_query_interface(void* const self, const v3_tuid iid, void** const iface)
{
if (v3_tuid_match(iid, v3_funknown_iid) ||
v3_tuid_match(iid, v3_host_application_iid))
{
*iface = self;
return V3_OK;
}

*iface = nullptr;
return V3_NO_INTERFACE;
}

static v3_result V3_API carla_get_name(void*, v3_str_128 name)
{
static const char hostname[] = "Carla-Discovery\0";

for (size_t i=0; i<sizeof(hostname); ++i)
name[i] = hostname[i];

return V3_OK;
}

static v3_result V3_API carla_create_instance(void*, v3_tuid, v3_tuid, void**) { return V3_NOT_IMPLEMENTED; }
};

struct carla_v3_param_changes : v3_param_changes_cpp {
carla_v3_param_changes()
{
query_interface = carla_query_interface;
ref = v3_ref_static;
unref = v3_unref_static;
changes.get_param_count = carla_get_param_count;
changes.get_param_data = carla_get_param_data;
changes.add_param_data = carla_add_param_data;
}

static v3_result V3_API carla_query_interface(void* const self, const v3_tuid iid, void** const iface)
{
if (v3_tuid_match(iid, v3_funknown_iid) ||
v3_tuid_match(iid, v3_param_changes_iid))
{
*iface = self;
return V3_OK;
}

*iface = nullptr;
return V3_NO_INTERFACE;
}

static int32_t V3_API carla_get_param_count(void*) { return 0; }
static v3_param_value_queue** V3_API carla_get_param_data(void*, int32_t) { return nullptr; }
static v3_param_value_queue** V3_API carla_add_param_data(void*, v3_param_id*, int32_t*) { return nullptr; }
};

struct carla_v3_event_list : v3_event_list_cpp {
carla_v3_event_list()
{
query_interface = carla_query_interface;
ref = v3_ref_static;
unref = v3_unref_static;
list.get_event_count = carla_get_event_count;
list.get_event = carla_get_event;
list.add_event = carla_add_event;
}

static v3_result V3_API carla_query_interface(void* const self, const v3_tuid iid, void** const iface)
{
if (v3_tuid_match(iid, v3_funknown_iid) ||
v3_tuid_match(iid, v3_event_list_iid))
{
*iface = self;
return V3_OK;
}

*iface = nullptr;
return V3_NO_INTERFACE;
}

static uint32_t V3_API carla_get_event_count(void*) { return 0; }
static v3_result V3_API carla_get_event(void*, int32_t, v3_event*) { return V3_NOT_IMPLEMENTED; }
static v3_result V3_API carla_add_event(void*, v3_event*) { return V3_NOT_IMPLEMENTED; }
};

static void do_vst3_check(lib_t& libHandle, const char* const filename, const bool doInit)
{
V3_ENTRYFN v3_entry;
V3_EXITFN v3_exit;
V3_GETFN v3_get;

#ifdef CARLA_OS_MAC
BundleLoader bundleLoader;
#endif

// if passed filename is not a plugin binary directly, inspect bundle and find one
if (libHandle == nullptr)
{
#ifdef CARLA_OS_MAC
if (! bundleLoader.load(filename))
{
DISCOVERY_OUT("error", "Failed to load VST3 bundle executable");
return;
}

v3_entry = (V3_ENTRYFN)CFBundleGetFunctionPointerForName(bundleLoader.ref, CFSTR(V3_ENTRYFNNAME));
v3_exit = (V3_EXITFN)CFBundleGetFunctionPointerForName(bundleLoader.ref, CFSTR(V3_EXITFNNAME));
v3_get = (V3_GETFN)CFBundleGetFunctionPointerForName(bundleLoader.ref, CFSTR(V3_GETFNNAME));
#else
water::String binaryfilename = filename;

if (!binaryfilename.endsWithChar(CARLA_OS_SEP))
binaryfilename += CARLA_OS_SEP_STR;

binaryfilename += "Contents" CARLA_OS_SEP_STR V3_CONTENT_DIR CARLA_OS_SEP_STR;
binaryfilename += File(filename).getFileNameWithoutExtension();
# ifdef CARLA_OS_WIN
binaryfilename += ".vst3";
# else
binaryfilename += ".so";
# endif

if (! File(binaryfilename).existsAsFile())
{
DISCOVERY_OUT("error", "Failed to find a suitable VST3 bundle binary");
return;
}

libHandle = lib_open(binaryfilename.toRawUTF8());

if (libHandle == nullptr)
{
print_lib_error(filename);
return;
}
#endif
}

#ifndef CARLA_OS_MAC
// ensure entry and exist points are available
v3_entry = lib_symbol<V3_ENTRYFN>(libHandle, V3_ENTRYFNNAME);
v3_exit = lib_symbol<V3_EXITFN>(libHandle, V3_EXITFNNAME);
v3_get = lib_symbol<V3_GETFN>(libHandle, V3_GETFNNAME);
#endif

if (v3_entry == nullptr || v3_exit == nullptr || v3_get == nullptr)
{
DISCOVERY_OUT("error", "Not a VST3 plugin");
return;
}

// call entry point
#if defined(CARLA_OS_MAC)
v3_entry(bunbleLoader.ref);
#elif defined(CARLA_OS_WIN)
v3_entry();
#else
v3_entry(libHandle);
#endif

carla_v3_host_application hostApplication;
carla_v3_host_application* const hostApplicationPtr = &hostApplication;
v3_funknown** const hostContext = (v3_funknown**)&hostApplicationPtr;

// fetch initial factory
v3_plugin_factory** factory1 = v3_get();
CARLA_SAFE_ASSERT_RETURN(factory1 != nullptr, v3_exit());

// get factory info
v3_factory_info factoryInfo = {};
CARLA_SAFE_ASSERT_RETURN(v3_cpp_obj(factory1)->get_factory_info(factory1, &factoryInfo) == V3_OK, v3_exit());

// get num classes
const int32_t numClasses = v3_cpp_obj(factory1)->num_classes(factory1);
CARLA_SAFE_ASSERT_RETURN(numClasses > 0, v3_exit());

// query 2nd factory
v3_plugin_factory_2** factory2 = nullptr;
if (v3_cpp_obj_query_interface(factory1, v3_plugin_factory_2_iid, &factory2) == V3_OK)
{
CARLA_SAFE_ASSERT_RETURN(factory2 != nullptr, v3_exit());
}
else
{
CARLA_SAFE_ASSERT(factory2 == nullptr);
factory2 = nullptr;
}

// query 3rd factory
v3_plugin_factory_3** factory3 = nullptr;
if (factory2 != nullptr && v3_cpp_obj_query_interface(factory2, v3_plugin_factory_3_iid, &factory3) == V3_OK)
{
CARLA_SAFE_ASSERT_RETURN(factory3 != nullptr, v3_exit());
}
else
{
CARLA_SAFE_ASSERT(factory3 == nullptr);
factory3 = nullptr;
}

// set host context (application) if 3rd factory provided
if (factory3 != nullptr)
v3_cpp_obj(factory3)->set_host_context(factory3, hostContext);

// go through all relevant classes
for (int32_t i=0; i<numClasses; ++i)
{
// v3_class_info_2 is ABI compatible with v3_class_info
union {
v3_class_info v1;
v3_class_info_2 v2;
} classInfo = {};

if (factory2 != nullptr)
v3_cpp_obj(factory2)->get_class_info_2(factory2, i, &classInfo.v2);
else
v3_cpp_obj(factory1)->get_class_info(factory1, i, &classInfo.v1);

// safety check
CARLA_SAFE_ASSERT_CONTINUE(classInfo.v1.cardinality == 0x7FFFFFFF);

// only check for audio plugins
if (std::strcmp(classInfo.v1.category, "Audio Module Class") != 0)
continue;

// create instance
void* instance = nullptr;
CARLA_SAFE_ASSERT_CONTINUE(v3_cpp_obj(factory1)->create_instance(factory1, classInfo.v1.class_id, v3_component_iid, &instance) == V3_OK);
CARLA_SAFE_ASSERT_CONTINUE(instance != nullptr);

// initialize instance
v3_component** const component = static_cast<v3_component**>(instance);

CARLA_SAFE_ASSERT_CONTINUE(v3_cpp_obj_initialize(component, hostContext) == V3_OK);

// create edit controller
v3_edit_controller** controller = nullptr;
bool shouldTerminateController;
if (v3_cpp_obj_query_interface(component, v3_edit_controller_iid, &controller) != V3_OK)
controller = nullptr;

if (controller != nullptr)
{
// got edit controller from casting component, assume they belong to the same object
shouldTerminateController = false;
}
else
{
// try to create edit controller from factory
v3_tuid uid = {};
if (v3_cpp_obj(component)->get_controller_class_id(component, uid) == V3_OK)
{
instance = nullptr;
if (v3_cpp_obj(factory1)->create_instance(factory1, uid, v3_edit_controller_iid, &instance) == V3_OK && instance != nullptr)
controller = static_cast<v3_edit_controller**>(instance);
}

if (controller == nullptr)
{
DISCOVERY_OUT("warning", "Plugin '" << classInfo.v1.name << "' does not have an edit controller");
v3_cpp_obj_terminate(component);
v3_cpp_obj_unref(component);
continue;
}

// component is separate from controller, needs its dedicated initialize and terminate
shouldTerminateController = true;
v3_cpp_obj_initialize(controller, hostContext);
}

// fill in all the details
uint hints = 0x0;
int audioIns = 0;
int audioOuts = 0;
int cvIns = 0;
int cvOuts = 0;
int parameterIns = 0;
int parameterOuts = 0;

const int32_t numAudioInputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_AUDIO, V3_INPUT);
const int32_t numEventInputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_EVENT, V3_INPUT);
const int32_t numAudioOutputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_AUDIO, V3_OUTPUT);
const int32_t numEventOutputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_EVENT, V3_OUTPUT);
const int32_t numParameters = v3_cpp_obj(controller)->get_parameter_count(controller);

CARLA_SAFE_ASSERT(numAudioInputBuses >= 0);
CARLA_SAFE_ASSERT(numEventInputBuses >= 0);
CARLA_SAFE_ASSERT(numAudioOutputBuses >= 0);
CARLA_SAFE_ASSERT(numEventOutputBuses >= 0);
CARLA_SAFE_ASSERT(numParameters >= 0);

for (int32_t j=0; j<numAudioInputBuses; ++j)
{
v3_bus_info busInfo = {};
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_INPUT, j, &busInfo) == V3_OK);

if (busInfo.flags & V3_IS_CONTROL_VOLTAGE)
++cvIns;
else
++audioIns;
}

for (int32_t j=0; j<numAudioInputBuses; ++j)
{
v3_bus_info busInfo = {};
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_OUTPUT, j, &busInfo) == V3_OK);

if (busInfo.flags & V3_IS_CONTROL_VOLTAGE)
++cvOuts;
else
++audioOuts;
}

for (int32_t j=0; j<numParameters; ++j)
{
v3_param_info paramInfo = {};
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(controller)->get_parameter_info(controller, j, &paramInfo) == V3_OK);

if (paramInfo.flags & (V3_PARAM_IS_BYPASS|V3_PARAM_IS_HIDDEN|V3_PARAM_PROGRAM_CHANGE))
continue;

if (paramInfo.flags & V3_PARAM_READ_ONLY)
++parameterOuts;
else
++parameterIns;
}

if (v3_plugin_view** const view = v3_cpp_obj(controller)->create_view(controller, "view"))
{
if (v3_cpp_obj(view)->is_platform_type_supported(view, V3_VIEW_PLATFORM_TYPE_NATIVE) == V3_TRUE)
hints |= PLUGIN_HAS_CUSTOM_UI;

v3_cpp_obj_unref(view);
}

if (factory2 != nullptr && std::strstr(classInfo.v2.sub_categories, "Instrument") != nullptr)
hints |= PLUGIN_IS_SYNTH;

if (doInit)
{
v3_audio_processor** processor = nullptr;
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj_query_interface(component, v3_audio_processor_iid, &processor) == V3_OK);
CARLA_SAFE_ASSERT_BREAK(processor != nullptr);

CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(processor)->can_process_sample_size(processor, V3_SAMPLE_32) == V3_OK);

CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->set_active(component, true) == V3_OK);
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->set_active(component, false) == V3_OK);

v3_process_setup setup = { V3_REALTIME, V3_SAMPLE_32, kBufferSize, kSampleRate };
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(processor)->setup_processing(processor, &setup) == V3_OK);

for (int32_t j=0; j<numAudioInputBuses; ++j)
{
v3_bus_info busInfo = {};
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_INPUT, j, &busInfo) == V3_OK);

if ((busInfo.flags & V3_DEFAULT_ACTIVE) == 0x0) {
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->activate_bus(component, V3_AUDIO, V3_INPUT, j, true) == V3_OK);
}
}

for (int32_t j=0; j<numAudioInputBuses; ++j)
{
v3_bus_info busInfo = {};
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_OUTPUT, j, &busInfo) == V3_OK);

if ((busInfo.flags & V3_DEFAULT_ACTIVE) == 0x0) {
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->activate_bus(component, V3_AUDIO, V3_OUTPUT, j, true) == V3_OK);
}
}

CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->set_active(component, true) == V3_OK);
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(processor)->set_processing(processor, true) == V3_OK);

float* bufferAudioIn[std::max(1, numAudioInputBuses)];
float* bufferAudioOut[std::max(1, numAudioOutputBuses)];

if (numAudioInputBuses == 0)
{
bufferAudioIn[0] = nullptr;
}
else
{
for (int j=0; j < numAudioInputBuses; ++j)
{
bufferAudioIn[j] = new float[kBufferSize];
carla_zeroFloats(bufferAudioIn[j], kBufferSize);
}
}

if (numAudioOutputBuses == 0)
{
bufferAudioOut[0] = nullptr;
}
else
{
for (int j=0; j < numAudioOutputBuses; ++j)
{
bufferAudioOut[j] = new float[kBufferSize];
carla_zeroFloats(bufferAudioOut[j], kBufferSize);
}
}

carla_v3_event_list eventList;
carla_v3_event_list* eventListPtr = &eventList;

carla_v3_param_changes paramChanges;
carla_v3_param_changes* paramChangesPtr = &paramChanges;

v3_audio_bus_buffers processInputs = { numAudioInputBuses, 0, { bufferAudioIn } };
v3_audio_bus_buffers processOutputs = { numAudioOutputBuses, 0, { bufferAudioOut } };

v3_process_context processContext = {};
processContext.sample_rate = kSampleRate;

v3_process_data processData = {
V3_REALTIME,
V3_SAMPLE_32,
kBufferSize,
numAudioInputBuses,
numAudioOutputBuses,
&processInputs,
&processOutputs,
(v3_param_changes**)&paramChangesPtr,
(v3_param_changes**)&paramChangesPtr,
(v3_event_list**)&eventListPtr,
(v3_event_list**)&eventListPtr,
&processContext
};
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(processor)->process(processor, &processData) == V3_OK);

for (int j=0; j < numAudioInputBuses; ++j)
delete[] bufferAudioIn[j];
for (int j=0; j < numAudioOutputBuses; ++j)
delete[] bufferAudioOut[j];

CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(processor)->set_processing(processor, false) == V3_OK);
CARLA_SAFE_ASSERT_BREAK(v3_cpp_obj(component)->set_active(component, false) == V3_OK);

v3_cpp_obj_unref(processor);
}

if (shouldTerminateController)
v3_cpp_obj_terminate(controller);

v3_cpp_obj_unref(controller);

v3_cpp_obj_terminate(component);
v3_cpp_obj_unref(component);

DISCOVERY_OUT("init", "-----------");
DISCOVERY_OUT("build", BINARY_NATIVE);
DISCOVERY_OUT("hints", hints);
DISCOVERY_OUT("category", getPluginCategoryAsString(factory2 != nullptr ? getPluginCategoryFromV3SubCategories(classInfo.v2.sub_categories)
: getPluginCategoryFromName(classInfo.v1.name)));
DISCOVERY_OUT("name", classInfo.v1.name);
DISCOVERY_OUT("label", tuid2str(classInfo.v1.class_id));
DISCOVERY_OUT("maker", (factory2 != nullptr ? classInfo.v2.vendor : factoryInfo.vendor));
DISCOVERY_OUT("audio.ins", audioIns);
DISCOVERY_OUT("audio.outs", audioOuts);
DISCOVERY_OUT("cv.ins", cvIns);
DISCOVERY_OUT("cv.outs", cvOuts);
DISCOVERY_OUT("midi.ins", numEventInputBuses);
DISCOVERY_OUT("midi.outs", numEventOutputBuses);
DISCOVERY_OUT("parameters.ins", parameterIns);
DISCOVERY_OUT("parameters.outs", parameterOuts);
DISCOVERY_OUT("end", "------------");
}

// unref interfaces
if (factory2 != nullptr)
v3_cpp_obj_unref(factory2);

v3_cpp_obj_unref(factory1);

v3_exit();
}
#endif // ! USING_JUCE_FOR_VST3

#ifdef USING_JUCE #ifdef USING_JUCE
// ------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------
// find all available plugin audio ports // find all available plugin audio ports
@@ -1790,7 +2259,7 @@ int main(int argc, char* argv[])
#if defined(USING_JUCE) && JUCE_PLUGINHOST_VST #if defined(USING_JUCE) && JUCE_PLUGINHOST_VST
retryJucePlugin = do_juce_check(filename, "VST2", doInit); retryJucePlugin = do_juce_check(filename, "VST2", doInit);
#else #else
do_vst_check(handle, filename, doInit);
do_vst2_check(handle, filename, doInit);
#endif #endif
break; break;


@@ -1798,7 +2267,7 @@ int main(int argc, char* argv[])
#if defined(USING_JUCE) && JUCE_PLUGINHOST_VST3 #if defined(USING_JUCE) && JUCE_PLUGINHOST_VST3
retryJucePlugin = do_juce_check(filename, "VST3", doInit); retryJucePlugin = do_juce_check(filename, "VST3", doInit);
#else #else
DISCOVERY_OUT("error", "VST3 support not available");
do_vst3_check(handle, filename, doInit);
#endif #endif
break; break;




+ 1
- 1
source/includes/CarlaDefines.h View File

@@ -39,7 +39,7 @@
/* Check OS */ /* Check OS */
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(_M_ARM64) #if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(_M_ARM64)
# define CARLA_OS_WIN64 # define CARLA_OS_WIN64
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_M_ARM)
# define CARLA_OS_WIN32 # define CARLA_OS_WIN32
#elif defined(__APPLE__) #elif defined(__APPLE__)
# define CARLA_OS_MAC # define CARLA_OS_MAC


+ 9
- 5
source/includes/travesty/audio_processor.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -90,8 +90,9 @@ struct v3_process_setup {
*/ */


struct v3_param_value_queue { struct v3_param_value_queue {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_param_id (V3_API* get_param_id)(void* self); v3_param_id (V3_API* get_param_id)(void* self);
int32_t (V3_API* get_point_count)(void* self); int32_t (V3_API* get_point_count)(void* self);
v3_result (V3_API* get_point)(void* self, int32_t idx, int32_t* sample_offset, double* value); v3_result (V3_API* get_point)(void* self, int32_t idx, int32_t* sample_offset, double* value);
@@ -102,8 +103,9 @@ static constexpr const v3_tuid v3_param_value_queue_iid =
V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA); V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA);


struct v3_param_changes { struct v3_param_changes {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
int32_t (V3_API* get_param_count)(void* self); int32_t (V3_API* get_param_count)(void* self);
struct v3_param_value_queue** (V3_API* get_param_data)(void* self, int32_t idx); struct v3_param_value_queue** (V3_API* get_param_data)(void* self, int32_t idx);
struct v3_param_value_queue** (V3_API* add_param_data)(void* self, v3_param_id* id, int32_t* index); struct v3_param_value_queue** (V3_API* add_param_data)(void* self, v3_param_id* id, int32_t* index);
@@ -181,8 +183,9 @@ enum {
}; };


struct v3_process_context_requirements { struct v3_process_context_requirements {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
uint32_t (V3_API* get_process_context_requirements)(void* self); uint32_t (V3_API* get_process_context_requirements)(void* self);
}; };


@@ -222,8 +225,9 @@ struct v3_process_data {
*/ */


struct v3_audio_processor { struct v3_audio_processor {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* set_bus_arrangements)(void* self, v3_speaker_arrangement* inputs, int32_t num_inputs, v3_result (V3_API* set_bus_arrangements)(void* self, v3_speaker_arrangement* inputs, int32_t num_inputs,
v3_speaker_arrangement* outputs, int32_t num_outputs); v3_speaker_arrangement* outputs, int32_t num_outputs);
v3_result (V3_API* get_bus_arrangement)(void* self, int32_t bus_direction, int32_t idx, v3_speaker_arrangement*); v3_result (V3_API* get_bus_arrangement)(void* self, int32_t bus_direction, int32_t idx, v3_speaker_arrangement*);


+ 40
- 29
source/includes/travesty/base.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -24,33 +24,8 @@
* deal with C vs C++ differences * deal with C vs C++ differences
*/ */


#ifdef __cplusplus

/**
* cast object into its proper C++ type.
* this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields.
* we can use this as a little helper for keeping both C and C++ compatiblity.
* specialized templated calls are defined where required
* (that is, object inherits from something other than `v3_funknown`)
*
* example usage: `v3_cpp_obj(obj)->method(obj, args...);`
*/
template<class T> static inline
constexpr T* v3_cpp_obj(T** obj)
{
/**
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
* but we need everything to be `static_cast` for it to be `constexpr` compatible.
*/
return static_cast<T*>(static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3));
}

#else

# ifndef constexpr
# define constexpr
# endif

#if !defined(__cplusplus) && !defined(constexpr)
# define constexpr
#endif #endif


/** /**
@@ -177,8 +152,9 @@ static constexpr const v3_tuid v3_funknown_iid =
*/ */


struct v3_plugin_base { struct v3_plugin_base {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* initialize)(void* self, struct v3_funknown** context); v3_result (V3_API* initialize)(void* self, struct v3_funknown** context);
v3_result (V3_API* terminate)(void* self); v3_result (V3_API* terminate)(void* self);
}; };
@@ -188,6 +164,27 @@ static constexpr const v3_tuid v3_plugin_base_iid =


#ifdef __cplusplus #ifdef __cplusplus


/**
* cast object into its proper C++ type.
* this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields.
*
* we can use this as a little helper for keeping both C and C++ compatiblity.
* specialized templated calls are defined where required
* (that is, object inherits from something other than `v3_funknown`)
*
* example usage: `v3_cpp_obj(obj)->method(obj, args...);`
*/

template<class T> static inline
constexpr T* v3_cpp_obj(T** obj)
{
/**
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
* but we need everything to be `static_cast` for it to be `constexpr` compatible.
*/
return static_cast<T*>(static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3));
}

/** /**
* helper C++ functions to manually call v3_funknown methods on an object. * helper C++ functions to manually call v3_funknown methods on an object.
*/ */
@@ -210,4 +207,18 @@ uint32_t v3_cpp_obj_unref(T** obj)
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->unref(obj); return static_cast<v3_funknown*>(static_cast<void*>(*obj))->unref(obj);
} }


template<class T> static inline
v3_result v3_cpp_obj_initialize(T** obj, v3_funknown** context)
{
return static_cast<v3_plugin_base*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3))->initialize(obj, context);
}

template<class T> static inline
v3_result v3_cpp_obj_terminate(T** obj)
{
return static_cast<v3_plugin_base*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3))->terminate(obj);
}

#endif #endif

+ 3
- 2
source/includes/travesty/bstream.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -25,8 +25,9 @@ enum v3_seek_mode {
}; };


struct v3_bstream { struct v3_bstream {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API *read)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_read); v3_result (V3_API *read)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_read);
v3_result (V3_API *write)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_written); v3_result (V3_API *write)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_written);
v3_result (V3_API *seek)(void* self, int64_t pos, int32_t seek_mode, int64_t* result); v3_result (V3_API *seek)(void* self, int64_t pos, int32_t seek_mode, int64_t* result);


+ 3
- 2
source/includes/travesty/component.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -89,8 +89,9 @@ struct v3_bus_info {
struct v3_routing_info; struct v3_routing_info;


struct v3_component { struct v3_component {
#ifndef __cplusplus
struct v3_plugin_base; struct v3_plugin_base;
#endif
v3_result (V3_API *get_controller_class_id)(void* self, v3_tuid class_id); v3_result (V3_API *get_controller_class_id)(void* self, v3_tuid class_id);
v3_result (V3_API *set_io_mode)(void* self, int32_t io_mode); v3_result (V3_API *set_io_mode)(void* self, int32_t io_mode);
int32_t (V3_API *get_bus_count)(void* self, int32_t media_type, int32_t bus_direction); int32_t (V3_API *get_bus_count)(void* self, int32_t media_type, int32_t bus_direction);


+ 23
- 7
source/includes/travesty/edit_controller.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -40,8 +40,9 @@ enum {
}; };


struct v3_component_handler { struct v3_component_handler {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* begin_edit)(void* self, v3_param_id); v3_result (V3_API* begin_edit)(void* self, v3_param_id);
v3_result (V3_API* perform_edit)(void* self, v3_param_id, double value_normalised); v3_result (V3_API* perform_edit)(void* self, v3_param_id, double value_normalised);
v3_result (V3_API* end_edit)(void* self, v3_param_id); v3_result (V3_API* end_edit)(void* self, v3_param_id);
@@ -51,6 +52,19 @@ struct v3_component_handler {
static constexpr const v3_tuid v3_component_handler_iid = static constexpr const v3_tuid v3_component_handler_iid =
V3_ID(0x93A0BEA3, 0x0BD045DB, 0x8E890B0C, 0xC1E46AC6); V3_ID(0x93A0BEA3, 0x0BD045DB, 0x8E890B0C, 0xC1E46AC6);


struct v3_component_handler2 {
#ifndef __cplusplus
struct v3_funknown;
#endif
v3_result (V3_API* set_dirty)(void* self, v3_bool state);
v3_result (V3_API* request_open_editor)(void* self, const char* name);
v3_result (V3_API* start_group_edit)(void* self);
v3_result (V3_API* finish_group_edit)(void* self);
};

static constexpr const v3_tuid v3_component_handler2_iid =
V3_ID(0xF040B4B3, 0xA36045EC, 0xABCDC045, 0xB4D5A2CC);

/** /**
* edit controller * edit controller
*/ */
@@ -77,11 +91,12 @@ struct v3_param_info {
}; };


struct v3_edit_controller { struct v3_edit_controller {
#ifndef __cplusplus
struct v3_plugin_base; struct v3_plugin_base;
v3_result (V3_API* set_component_state)(void* self, struct v3_bstream*);
v3_result (V3_API* set_state)(void* self, struct v3_bstream*);
v3_result (V3_API* get_state)(void* self, struct v3_bstream*);
#endif
v3_result (V3_API* set_component_state)(void* self, struct v3_bstream**);
v3_result (V3_API* set_state)(void* self, struct v3_bstream**);
v3_result (V3_API* get_state)(void* self, struct v3_bstream**);
int32_t (V3_API* get_parameter_count)(void* self); int32_t (V3_API* get_parameter_count)(void* self);
v3_result (V3_API* get_parameter_info)(void* self, int32_t param_idx, struct v3_param_info*); v3_result (V3_API* get_parameter_info)(void* self, int32_t param_idx, struct v3_param_info*);
v3_result (V3_API* get_parameter_string_for_value)(void* self, v3_param_id, double normalised, v3_str_128 output); v3_result (V3_API* get_parameter_string_for_value)(void* self, v3_param_id, double normalised, v3_str_128 output);
@@ -102,8 +117,9 @@ static constexpr const v3_tuid v3_edit_controller_iid =
*/ */


struct v3_midi_mapping { struct v3_midi_mapping {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* get_midi_controller_assignment)(void* self, int32_t bus, int16_t channel, int16_t cc, v3_param_id* id); v3_result (V3_API* get_midi_controller_assignment)(void* self, int32_t bus, int16_t channel, int16_t cc, v3_param_id* id);
}; };




+ 15
- 2
source/includes/travesty/events.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -132,8 +132,9 @@ struct v3_event {
*/ */


struct v3_event_list { struct v3_event_list {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
uint32_t (V3_API* get_event_count)(void* self); uint32_t (V3_API* get_event_count)(void* self);
v3_result (V3_API* get_event)(void* self, int32_t idx, struct v3_event* event); v3_result (V3_API* get_event)(void* self, int32_t idx, struct v3_event* event);
v3_result (V3_API* add_event)(void* self, struct v3_event* event); v3_result (V3_API* add_event)(void* self, struct v3_event* event);
@@ -142,4 +143,16 @@ struct v3_event_list {
static constexpr const v3_tuid v3_event_list_iid = static constexpr const v3_tuid v3_event_list_iid =
V3_ID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44); V3_ID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44);


#ifdef __cplusplus

/**
* C++ variants
*/

struct v3_event_list_cpp : v3_funknown {
v3_event_list list;
};

#endif

#include "align_pop.h" #include "align_pop.h"

+ 29
- 4
source/includes/travesty/factory.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -37,8 +37,9 @@ struct v3_class_info {
}; };


struct v3_plugin_factory { struct v3_plugin_factory {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API *get_factory_info)(void* self, struct v3_factory_info*); v3_result (V3_API *get_factory_info)(void* self, struct v3_factory_info*);
int32_t (V3_API *num_classes)(void* self); int32_t (V3_API *num_classes)(void* self);
v3_result (V3_API *get_class_info)(void* self, int32_t idx, struct v3_class_info*); v3_result (V3_API *get_class_info)(void* self, int32_t idx, struct v3_class_info*);
@@ -70,8 +71,9 @@ struct v3_class_info_2 {
}; };


struct v3_plugin_factory_2 { struct v3_plugin_factory_2 {
#ifndef __cplusplus
struct v3_plugin_factory; struct v3_plugin_factory;
#endif
v3_result (V3_API *get_class_info_2)(void* self, int32_t idx, struct v3_class_info_2*); v3_result (V3_API *get_class_info_2)(void* self, int32_t idx, struct v3_class_info_2*);
}; };


@@ -98,8 +100,9 @@ struct v3_class_info_3 {
}; };


struct v3_plugin_factory_3 { struct v3_plugin_factory_3 {
#ifndef __cplusplus
struct v3_plugin_factory_2; struct v3_plugin_factory_2;
#endif
v3_result (V3_API *get_class_info_utf16)(void* self, int32_t idx, struct v3_class_info_3*); v3_result (V3_API *get_class_info_utf16)(void* self, int32_t idx, struct v3_class_info_3*);
v3_result (V3_API *set_host_context)(void* self, struct v3_funknown** host); v3_result (V3_API *set_host_context)(void* self, struct v3_funknown** host);
}; };
@@ -119,4 +122,26 @@ struct v3_plugin_factory_cpp : v3_funknown {
v3_plugin_factory_3 v3; v3_plugin_factory_3 v3;
}; };


template<> inline
constexpr v3_plugin_factory_2* v3_cpp_obj(v3_plugin_factory_2** obj)
{
/**
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
* but we need everything to be `static_cast` for it to be `constexpr` compatible.
*/
return static_cast<v3_plugin_factory_2*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*7));
}

template<> inline
constexpr v3_plugin_factory_3* v3_cpp_obj(v3_plugin_factory_3** obj)
{
/**
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
* but we need everything to be `static_cast` for it to be `constexpr` compatible.
*/
return static_cast<v3_plugin_factory_3*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*8));
}

#endif #endif

+ 4
- 3
source/includes/travesty/host.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -21,12 +21,13 @@
#include "align_push.h" #include "align_push.h"


/** /**
* connection point
* host application
*/ */


struct v3_host_application { struct v3_host_application {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* get_name)(void* self, v3_str_128 name); // wtf? v3_result (V3_API* get_name)(void* self, v3_str_128 name); // wtf?
v3_result (V3_API* create_instance)(void* self, v3_tuid cid, v3_tuid iid, void** obj); v3_result (V3_API* create_instance)(void* self, v3_tuid cid, v3_tuid iid, void** obj);
}; };


+ 7
- 4
source/includes/travesty/message.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -25,8 +25,9 @@
*/ */


struct v3_attribute_list { struct v3_attribute_list {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* set_int)(void* self, const char* id, int64_t value); v3_result (V3_API* set_int)(void* self, const char* id, int64_t value);
v3_result (V3_API* get_int)(void* self, const char* id, int64_t* value); v3_result (V3_API* get_int)(void* self, const char* id, int64_t* value);
v3_result (V3_API* set_float)(void* self, const char* id, double value); v3_result (V3_API* set_float)(void* self, const char* id, double value);
@@ -45,8 +46,9 @@ static constexpr const v3_tuid v3_attribute_list_iid =
*/ */


struct v3_message { struct v3_message {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
const char* (V3_API* get_message_id)(void* self); const char* (V3_API* get_message_id)(void* self);
void (V3_API* set_message_id)(void* self, const char* id); void (V3_API* set_message_id)(void* self, const char* id);
v3_attribute_list** (V3_API* get_attributes)(void* self); v3_attribute_list** (V3_API* get_attributes)(void* self);
@@ -60,8 +62,9 @@ static constexpr const v3_tuid v3_message_iid =
*/ */


struct v3_connection_point { struct v3_connection_point {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* connect)(void* self, struct v3_connection_point** other); v3_result (V3_API* connect)(void* self, struct v3_connection_point** other);
v3_result (V3_API* disconnect)(void* self, struct v3_connection_point** other); v3_result (V3_API* disconnect)(void* self, struct v3_connection_point** other);
v3_result (V3_API* notify)(void* self, struct v3_message** message); v3_result (V3_API* notify)(void* self, struct v3_message** message);


+ 69
- 0
source/includes/travesty/unit.h View File

@@ -0,0 +1,69 @@
/*
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.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.
*
* THE 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.
*/

#pragma once

#include "base.h"

#include "align_push.h"

struct v3_unit_info {
int32_t id; // 0 for root unit
int32_t parent_unit_id; // -1 for none
v3_str_128 name;
int32_t program_list_id; // -1 for none
};

struct v3_program_list_info {
int32_t id;
v3_str_128 name;
int32_t programCount;
};

struct v3_unit_information {
#ifndef __cplusplus
struct v3_funknown;
#endif
int32_t (V3_API* get_unit_count)(void* self);
v3_result (V3_API* get_unit_info)(void* self, int32_t unit_idx, v3_unit_info* info);
int32_t (V3_API* get_program_list_count)(void* self);
v3_result (V3_API* get_program_list_info)(void* self, int32_t list_idx, v3_program_list_info* info);
v3_result (V3_API* get_program_name)(void* self, int32_t list_id, int32_t program_idx, v3_str_128 name);
v3_result (V3_API* get_program_info)(void* self, int32_t list_id, int32_t program_idx, const char *attribute_id, v3_str_128 attribute_value);
v3_result (V3_API* has_program_pitch_names)(void* self, int32_t list_id, int32_t program_idx);
v3_result (V3_API* get_program_pitch_name)(void* self, int32_t list_id, int32_t program_idx, int16_t midi_pitch, v3_str_128 name);
int32_t (V3_API* get_selected_unit)(void* self);
v3_result (V3_API* select_unit)(void* self, int32_t unit_id);
v3_result (V3_API* get_unit_by_bus)(void* self, int32_t type, int32_t bus_direction, int32_t bus_idx, int32_t channel, int32_t* unit_id);
v3_result (V3_API* set_unit_program_data)(void* self, int32_t list_or_unit_id, int32_t program_idx, struct v3_bstream** data);
};

static constexpr const v3_tuid v3_unit_information_iid =
V3_ID(0x3D4BD6B5, 0x913A4FD2, 0xA886E768, 0xA5EB92C1);

#ifdef __cplusplus

/**
* C++ variants
*/

struct v3_unit_information_cpp : v3_funknown {
v3_unit_information unit;
};

#endif

#include "align_pop.h"

+ 16
- 9
source/includes/travesty/view.h View File

@@ -1,6 +1,6 @@
/* /*
* travesty, pure C VST3-compatible interface * travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * 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 * or without fee is hereby granted, provided that the above copyright notice and this
@@ -48,8 +48,9 @@ struct v3_view_rect {
struct v3_plugin_frame; struct v3_plugin_frame;


struct v3_plugin_view { struct v3_plugin_view {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* is_platform_type_supported)(void* self, const char* platform_type); v3_result (V3_API* is_platform_type_supported)(void* self, const char* platform_type);
v3_result (V3_API* attached)(void* self, void* parent, const char* platform_type); v3_result (V3_API* attached)(void* self, void* parent, const char* platform_type);
v3_result (V3_API* removed)(void* self); v3_result (V3_API* removed)(void* self);
@@ -72,8 +73,9 @@ static constexpr const v3_tuid v3_plugin_view_iid =
*/ */


struct v3_plugin_frame { struct v3_plugin_frame {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* resize_view)(void* self, struct v3_plugin_view**, struct v3_view_rect*); v3_result (V3_API* resize_view)(void* self, struct v3_plugin_view**, struct v3_view_rect*);
}; };


@@ -86,8 +88,9 @@ static constexpr const v3_tuid v3_plugin_frame_iid =
*/ */


struct v3_plugin_view_content_scale { struct v3_plugin_view_content_scale {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* set_content_scale_factor)(void* self, float factor); v3_result (V3_API* set_content_scale_factor)(void* self, float factor);
}; };


@@ -99,8 +102,9 @@ static constexpr const v3_tuid v3_plugin_view_content_scale_iid =
*/ */


struct v3_plugin_view_parameter_finder { struct v3_plugin_view_parameter_finder {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* find_parameter)(void* self, int32_t x, int32_t y, v3_param_id *); v3_result (V3_API* find_parameter)(void* self, int32_t x, int32_t y, v3_param_id *);
}; };


@@ -112,8 +116,9 @@ static constexpr const v3_tuid v3_plugin_view_parameter_finder_iid =
*/ */


struct v3_event_handler { struct v3_event_handler {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
void (V3_API* on_fd_is_set)(void* self, int fd); void (V3_API* on_fd_is_set)(void* self, int fd);
}; };


@@ -125,8 +130,9 @@ static constexpr const v3_tuid v3_event_handler_iid =
*/ */


struct v3_timer_handler { struct v3_timer_handler {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
void (V3_API* on_timer)(void* self); void (V3_API* on_timer)(void* self);
}; };


@@ -138,8 +144,9 @@ static constexpr const v3_tuid v3_timer_handler_iid =
*/ */


struct v3_run_loop { struct v3_run_loop {
#ifndef __cplusplus
struct v3_funknown; struct v3_funknown;
#endif
v3_result (V3_API* register_event_handler)(void* self, v3_event_handler** handler, int fd); v3_result (V3_API* register_event_handler)(void* self, v3_event_handler** handler, int fd);
v3_result (V3_API* unregister_event_handler)(void* self, v3_event_handler** handler); v3_result (V3_API* unregister_event_handler)(void* self, v3_event_handler** handler);
v3_result (V3_API* register_timer)(void* self, v3_timer_handler** handler, uint64_t ms); v3_result (V3_API* register_timer)(void* self, v3_timer_handler** handler, uint64_t ms);
@@ -176,7 +183,7 @@ struct v3_event_handler_cpp : v3_funknown {
}; };


struct v3_timer_handler_cpp : v3_funknown { struct v3_timer_handler_cpp : v3_funknown {
v3_timer_handler handler;
v3_timer_handler timer;
}; };


struct v3_run_loop_cpp : v3_funknown { struct v3_run_loop_cpp : v3_funknown {


+ 36
- 0
source/utils/CarlaMacUtils.cpp View File

@@ -92,6 +92,42 @@ AutoNSAutoreleasePool::~AutoNSAutoreleasePool()


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


BundleLoader::BundleLoader() noexcept
: ref(nullptr),
refNum(0) {}

BundleLoader::~BundleLoader()
{
if (ref == nullptr)
return;

CFBundleCloseBundleResourceMap(ref, refNum);
CFBundleUnloadExecutable(ref);
CFRelease(ref);
}

bool BundleLoader::load(const char* const filename)
{
const CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)filename, (CFIndex)std::strlen(filename), true);
CARLA_SAFE_ASSERT_RETURN(urlRef != nullptr, false);

ref = CFBundleCreate(kCFAllocatorDefault, urlRef);
CFRelease(urlRef);
CARLA_SAFE_ASSERT_RETURN(ref != nullptr, false);

if (! CFBundleLoadExecutable(ref))
{
CFRelease(ref);
ref = nullptr;
return false;
}

refNum = CFBundleOpenBundleResourceMap(ref);
return true;
}

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

CARLA_BACKEND_END_NAMESPACE CARLA_BACKEND_END_NAMESPACE


#endif // CARLA_OS_MAC #endif // CARLA_OS_MAC

+ 13
- 0
source/utils/CarlaMacUtils.hpp View File

@@ -43,6 +43,8 @@ const char* findBinaryInBundle(const char* const bundleDir);
*/ */
bool removeFileFromQuarantine(const char* const filename); bool removeFileFromQuarantine(const char* const filename);


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

/* /*
* ... * ...
*/ */
@@ -57,6 +59,17 @@ private:


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


struct BundleLoader {
CFBundleRef ref;
CFBundleRefNum refNum;

BundleLoader() noexcept;
~BundleLoader();
bool load(const char* const filename);
};

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

CARLA_BACKEND_END_NAMESPACE CARLA_BACKEND_END_NAMESPACE


#endif // CARLA_MAC_UTILS_HPP_INCLUDED #endif // CARLA_MAC_UTILS_HPP_INCLUDED

+ 129
- 1
source/utils/CarlaVst3Utils.hpp View File

@@ -1,6 +1,6 @@
/* /*
* Carla VST3 utils * Carla VST3 utils
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@@ -18,9 +18,137 @@
#ifndef CARLA_VST3_UTILS_HPP_INCLUDED #ifndef CARLA_VST3_UTILS_HPP_INCLUDED
#define CARLA_VST3_UTILS_HPP_INCLUDED #define CARLA_VST3_UTILS_HPP_INCLUDED


#include "CarlaBackend.h"
#include "CarlaUtils.hpp" #include "CarlaUtils.hpp"


#include "travesty/audio_processor.h"
#include "travesty/component.h" #include "travesty/component.h"
#include "travesty/edit_controller.h" #include "travesty/edit_controller.h"
#include "travesty/factory.h"
#include "travesty/host.h"

#if !(defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN))
#if defined(__aarch64__) || defined(__arm64__)
#define V3_ARCHITECTURE "aarch64"
#elif defined(__TARGET_ARCH_ARM)
#if __TARGET_ARCH_ARM == 9
#define V3_ARCHITECTURE "armv9l"
#elif __TARGET_ARCH_ARM == 8
#define V3_ARCHITECTURE "armv8l"
#elif __TARGET_ARCH_ARM == 7
#define V3_ARCHITECTURE "armv7l"
#elif _TARGET_ARCH_ARM == 6
#define V3_ARCHITECTURE "armv6l"
#elif __TARGET_ARCH_ARM == 5
#define V3_ARCHITECTURE "armv5l"
#else
#define V3_ARCHITECTURE "arm"
#endif
#elif defined(__arm__)
#define V3_ARCHITECTURE "arm"
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64)
#define V3_ARCHITECTURE "x86_64"
#elif defined(__i386) || defined(__i386__)
#define V3_ARCHITECTURE "i386"
#elif defined(__ia64) || defined(__ia64__)
#define V3_ARCHITECTURE "ia64"
#elif defined(__mips64)
#define V3_ARCHITECTURE "mips64"
#elif defined(__mips) || defined(__mips__)
#define V3_ARCHITECTURE "mips"
#elif defined(__ppc64) || defined(__ppc64__) || defined(__powerpc64__)
#define V3_ARCHITECTURE "ppc64"
#elif defined(__ppc) || defined(__ppc__) || defined(__powerpc__)
#define V3_ARCHITECTURE "ppc"
#elif defined(__riscv)
#if __riscv_xlen == 64
#define V3_ARCHITECTURE "riscv64"
#else
#define V3_ARCHITECTURE "riscv"
#endif
#else
#define V3_ARCHITECTURE "unknown"
#endif
#if defined(__HAIKU__)
#define V3_PLATFORM "haiku"
#elif defined(__linux__) || defined(__linux)
#define V3_PLATFORM "linux"
#elif defined(__FreeBSD__)
#define V3_PLATFORM "freebsd"
#elif defined(__NetBSD__)
#define V3_PLATFORM "netbsd"
#elif defined(__OpenBSD__)
#define V3_PLATFORM "openbsd"
#elif defined(__GNU__)
#define V3_PLATFORM "hurd"
#else
#define V3_PLATFORM "unknown"
#endif
#endif

#if defined(CARLA_OS_MAC)
#define V3_CONTENT_DIR "MacOS"
#elif defined(_M_ARM64)
#define V3_CONTENT_DIR "aarch64-win" /* TBD */
#elif defined(_M_ARM)
#define V3_CONTENT_DIR "arm-win" /* TBD */
#elif defined(CARLA_OS_WIN64)
#define V3_CONTENT_DIR "x86_64-win"
#elif defined(CARLA_OS_WIN32)
#define V3_CONTENT_DIR "x86-win"
#else
#define V3_CONTENT_DIR V3_ARCHITECTURE "-" V3_PLATFORM
#endif

#if defined(CARLA_OS_MAC)
# define V3_ENTRYFNNAME "bundleEntry"
# define V3_EXITFNNAME "bundleExit"
typedef void (*V3_ENTRYFN)(void*);
typedef void (*V3_EXITFN)(void);
#elif defined(CARLA_OS_WIN)
# define V3_ENTRYFNNAME "InitDll"
# define V3_EXITFNNAME "ExitDll"
typedef void (*V3_ENTRYFN)(void);
typedef void (*V3_EXITFN)(void);
#else
# define V3_ENTRYFNNAME "ModuleEntry"
# define V3_EXITFNNAME "ModuleExit"
typedef void (*V3_ENTRYFN)(void*);
typedef void (*V3_EXITFN)(void);
#endif

#define V3_GETFNNAME "GetPluginFactory"
typedef v3_plugin_factory** (*V3_GETFN)(void);

CARLA_BACKEND_START_NAMESPACE

static inline
PluginCategory getPluginCategoryFromV3SubCategories(const char* const subcategories)
{
if (std::strstr(subcategories, "Instrument") != nullptr)
return PLUGIN_CATEGORY_SYNTH;

return subcategories[0] != '\0' ? PLUGIN_CATEGORY_OTHER : PLUGIN_CATEGORY_NONE;
}

static inline constexpr
uint32_t v3_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_t d) noexcept
{
return static_cast<uint32_t>((a << 24) | (b << 16) | (c << 8) | (d << 0));
}

static inline
const char* tuid2str(const v3_tuid iid)
{
static char buf[44];
std::snprintf(buf, sizeof(buf), "0x%08X,0x%08X,0x%08X,0x%08X",
v3_cconst(iid[ 0], iid[ 1], iid[ 2], iid[ 3]),
v3_cconst(iid[ 4], iid[ 5], iid[ 6], iid[ 7]),
v3_cconst(iid[ 8], iid[ 9], iid[10], iid[11]),
v3_cconst(iid[12], iid[13], iid[14], iid[15]));
return buf;
}

CARLA_BACKEND_END_NAMESPACE


#endif // CARLA_VST3_UTILS_HPP_INCLUDED #endif // CARLA_VST3_UTILS_HPP_INCLUDED

Loading…
Cancel
Save