Signed-off-by: falkTX <falktx@falktx.com>tags/v2.5.0
@@ -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, ¶mInfo) == 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 = ¶mChanges; | |||||
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**)¶mChangesPtr, | |||||
(v3_param_changes**)¶mChangesPtr, | |||||
(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; | ||||
@@ -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 | ||||
@@ -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*); | ||||
@@ -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 |
@@ -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); | ||||
@@ -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); | ||||
@@ -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); | ||||
}; | }; | ||||
@@ -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" |
@@ -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 |
@@ -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); | ||||
}; | }; | ||||
@@ -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); | ||||
@@ -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" |
@@ -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 { | ||||
@@ -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 |
@@ -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 |
@@ -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 |