Signed-off-by: falkTX <falktx@falktx.com>tags/v2.5.0
@@ -29,13 +29,6 @@ | |||
#include "CarlaVst3Utils.hpp" | |||
#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" | |||
# if defined(USING_JUCE) && defined(__aarch64__) | |||
# include <spawn.h> | |||
@@ -74,6 +67,9 @@ | |||
# if JUCE_PLUGINHOST_VST | |||
# define USING_JUCE_FOR_VST2 | |||
# endif | |||
# if JUCE_PLUGINHOST_VST3 | |||
# define USING_JUCE_FOR_VST3 | |||
# endif | |||
# pragma GCC diagnostic pop | |||
#endif | |||
@@ -993,44 +989,31 @@ static intptr_t VSTCALLBACK vstHostCallback(AEffect* const effect, const int32_t | |||
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; | |||
#ifdef CARLA_OS_MAC | |||
CFBundleRef bundleRef = nullptr; | |||
CFBundleRefNum resFileId = 0; | |||
BundleLoader bundleLoader; | |||
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; | |||
} | |||
vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("main_macho")); | |||
vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleLoader.ref, CFSTR("main_macho")); | |||
if (vstFn == nullptr) | |||
vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("VSTPluginMain")); | |||
vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleLoader.ref, CFSTR("VSTPluginMain")); | |||
if (vstFn == nullptr) | |||
{ | |||
CFBundleUnloadExecutable(bundleRef); | |||
CFRelease(bundleRef); | |||
DISCOVERY_OUT("error", "Not a VST plugin"); | |||
DISCOVERY_OUT("error", "Not a VST2 plugin"); | |||
return; | |||
} | |||
resFileId = CFBundleOpenBundleResourceMap(bundleRef); | |||
} | |||
else | |||
#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); | |||
} | |||
#ifdef CARLA_OS_MAC | |||
if (bundleRef != nullptr) | |||
{ | |||
CFBundleCloseBundleResourceMap(bundleRef, resFileId); | |||
CFBundleUnloadExecutable(bundleRef); | |||
CFRelease(bundleRef); | |||
} | |||
#else | |||
#ifndef CARLA_OS_MAC | |||
return; | |||
// unused | |||
@@ -1371,6 +1347,499 @@ static void do_vst_check(lib_t& libHandle, const char* const filename, const boo | |||
} | |||
#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 | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// find all available plugin audio ports | |||
@@ -1790,7 +2259,7 @@ int main(int argc, char* argv[]) | |||
#if defined(USING_JUCE) && JUCE_PLUGINHOST_VST | |||
retryJucePlugin = do_juce_check(filename, "VST2", doInit); | |||
#else | |||
do_vst_check(handle, filename, doInit); | |||
do_vst2_check(handle, filename, doInit); | |||
#endif | |||
break; | |||
@@ -1798,7 +2267,7 @@ int main(int argc, char* argv[]) | |||
#if defined(USING_JUCE) && JUCE_PLUGINHOST_VST3 | |||
retryJucePlugin = do_juce_check(filename, "VST3", doInit); | |||
#else | |||
DISCOVERY_OUT("error", "VST3 support not available"); | |||
do_vst3_check(handle, filename, doInit); | |||
#endif | |||
break; | |||
@@ -39,7 +39,7 @@ | |||
/* Check OS */ | |||
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(_M_ARM64) | |||
# 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 | |||
#elif defined(__APPLE__) | |||
# define CARLA_OS_MAC | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* 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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
v3_param_id (V3_API* get_param_id)(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); | |||
@@ -102,8 +103,9 @@ static constexpr const v3_tuid v3_param_value_queue_iid = | |||
V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA); | |||
struct v3_param_changes { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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* add_param_data)(void* self, v3_param_id* id, int32_t* index); | |||
@@ -181,8 +183,9 @@ enum { | |||
}; | |||
struct v3_process_context_requirements { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
uint32_t (V3_API* get_process_context_requirements)(void* self); | |||
}; | |||
@@ -222,8 +225,9 @@ struct v3_process_data { | |||
*/ | |||
struct v3_audio_processor { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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_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 | |||
* 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 | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
@@ -24,33 +24,8 @@ | |||
* 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 | |||
/** | |||
@@ -177,8 +152,9 @@ static constexpr const v3_tuid v3_funknown_iid = | |||
*/ | |||
struct v3_plugin_base { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
v3_result (V3_API* initialize)(void* self, struct v3_funknown** context); | |||
v3_result (V3_API* terminate)(void* self); | |||
}; | |||
@@ -188,6 +164,27 @@ static constexpr const v3_tuid v3_plugin_base_iid = | |||
#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. | |||
*/ | |||
@@ -210,4 +207,18 @@ uint32_t v3_cpp_obj_unref(T** 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 |
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* 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 { | |||
#ifndef __cplusplus | |||
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 *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); | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* 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_component { | |||
#ifndef __cplusplus | |||
struct v3_plugin_base; | |||
#endif | |||
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); | |||
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 | |||
* 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 | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
@@ -40,8 +40,9 @@ enum { | |||
}; | |||
struct v3_component_handler { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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* end_edit)(void* self, v3_param_id); | |||
@@ -51,6 +52,19 @@ struct v3_component_handler { | |||
static constexpr const v3_tuid v3_component_handler_iid = | |||
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 | |||
*/ | |||
@@ -77,11 +91,12 @@ struct v3_param_info { | |||
}; | |||
struct v3_edit_controller { | |||
#ifndef __cplusplus | |||
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); | |||
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); | |||
@@ -102,8 +117,9 @@ static constexpr const v3_tuid v3_edit_controller_iid = | |||
*/ | |||
struct v3_midi_mapping { | |||
#ifndef __cplusplus | |||
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); | |||
}; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* 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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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* 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 = | |||
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" |
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* 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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
v3_result (V3_API *get_factory_info)(void* self, struct v3_factory_info*); | |||
int32_t (V3_API *num_classes)(void* self); | |||
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 { | |||
#ifndef __cplusplus | |||
struct v3_plugin_factory; | |||
#endif | |||
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 { | |||
#ifndef __cplusplus | |||
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 *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; | |||
}; | |||
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 |
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
@@ -21,12 +21,13 @@ | |||
#include "align_push.h" | |||
/** | |||
* connection point | |||
* host application | |||
*/ | |||
struct v3_host_application { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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); | |||
}; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
@@ -25,8 +25,9 @@ | |||
*/ | |||
struct v3_attribute_list { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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* 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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
const char* (V3_API* get_message_id)(void* self); | |||
void (V3_API* set_message_id)(void* self, const char* id); | |||
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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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* 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 | |||
* 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 | |||
* 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_view { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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* removed)(void* self); | |||
@@ -72,8 +73,9 @@ static constexpr const v3_tuid v3_plugin_view_iid = | |||
*/ | |||
struct v3_plugin_frame { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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 { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
void (V3_API* on_timer)(void* self); | |||
}; | |||
@@ -138,8 +144,9 @@ static constexpr const v3_tuid v3_timer_handler_iid = | |||
*/ | |||
struct v3_run_loop { | |||
#ifndef __cplusplus | |||
struct v3_funknown; | |||
#endif | |||
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* 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 { | |||
v3_timer_handler handler; | |||
v3_timer_handler timer; | |||
}; | |||
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 | |||
#endif // CARLA_OS_MAC |
@@ -43,6 +43,8 @@ const char* findBinaryInBundle(const char* const bundleDir); | |||
*/ | |||
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 | |||
#endif // CARLA_MAC_UTILS_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||
/* | |||
* 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 | |||
* modify it under the terms of the GNU General Public License as | |||
@@ -18,9 +18,137 @@ | |||
#ifndef CARLA_VST3_UTILS_HPP_INCLUDED | |||
#define CARLA_VST3_UTILS_HPP_INCLUDED | |||
#include "CarlaBackend.h" | |||
#include "CarlaUtils.hpp" | |||
#include "travesty/audio_processor.h" | |||
#include "travesty/component.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 |