Browse Source

Start basic AU loader code

Signed-off-by: falkTX <falktx@falktx.com>
pull/1898/head
falkTX 6 months ago
parent
commit
b08801ed88
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 414 additions and 20 deletions
  1. +8
    -4
      source/backend/engine/CarlaEngine.cpp
  2. +399
    -4
      source/backend/plugin/CarlaPluginAU.cpp
  3. +5
    -12
      source/backend/plugin/Makefile
  4. +2
    -0
      source/bridges-plugin/Makefile

+ 8
- 4
source/backend/engine/CarlaEngine.cpp View File

@@ -704,14 +704,14 @@ bool CarlaEngine::addPlugin(const BinaryType btype,
plugin = CarlaPlugin::newVST3(initializer);
break;

case PLUGIN_AU:
plugin = CarlaPlugin::newAU(initializer);
break;

case PLUGIN_CLAP:
plugin = CarlaPlugin::newCLAP(initializer);
break;

case PLUGIN_AU:
plugin = CarlaPlugin::newAU(initializer);
break;

#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
case PLUGIN_INTERNAL:
plugin = CarlaPlugin::newNative(initializer);
@@ -1364,6 +1364,9 @@ bool CarlaEngine::loadFile(const char* const filename)
// Direct plugin binaries

#ifdef CARLA_OS_MAC
if (extension == "component")
return addPlugin(PLUGIN_AU, filename, nullptr, nullptr, 0, nullptr);

if (extension == "vst")
return addPlugin(PLUGIN_VST2, filename, nullptr, nullptr, 0, nullptr);
#else
@@ -3096,6 +3099,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
case PLUGIN_VST2:
case PLUGIN_VST3:
case PLUGIN_CLAP:
case PLUGIN_AU:
btype = getBinaryTypeFromFile(stateSave.binary);
break;
default:


+ 399
- 4
source/backend/plugin/CarlaPluginAU.cpp View File

@@ -1,21 +1,416 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPlugin.hpp"
#include "CarlaPluginInternal.hpp"
#include "CarlaEngine.hpp"
#include "CarlaUtils.hpp"

#ifdef CARLA_OS_MAC
# include "CarlaBackendUtils.hpp"
# include "CarlaPluginUI.hpp"
# include "CarlaMacUtils.hpp"
# include <AudioToolbox/AudioUnit.h>
# include <Foundation/Foundation.h>
#endif

CARLA_BACKEND_START_NAMESPACE

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

#ifdef CARLA_OS_MAC
typedef AudioComponentPlugInInterface* (*FactoryFn)(const AudioComponentDescription*);
typedef OSStatus (*InitializeFn)(void*);
typedef OSStatus (*UninitializeFn)(void*);
typedef OSStatus (*GetPropertyInfoFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, UInt32*, Boolean*);
typedef OSStatus (*GetPropertyFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, void*, UInt32*);
typedef OSStatus (*MIDIEventFn)(void*, UInt32, UInt32, UInt32, UInt32);

static constexpr FourCharCode getFourCharCodeFromString(const char str[4])
{
return (str[0] << 24) + (str[1] << 16) + (str[2] << 8) + str[3];
}

class CarlaPluginAU : public CarlaPlugin,
private CarlaPluginUI::Callback
{
public:
CarlaPluginAU(CarlaEngine* const engine, const uint id)
: CarlaPlugin(engine, id),
fInterface(nullptr)
{
carla_stdout("CarlaPluginAU::CarlaPluginAU(%p, %i)", engine, id);
}

~CarlaPluginAU() override
{
carla_stdout("CarlaPluginAU::~CarlaPluginAU()");

// close UI
showCustomUI(false);

pData->singleMutex.lock();
pData->masterMutex.lock();

if (pData->client != nullptr && pData->client->isActive())
pData->client->deactivate(true);

if (pData->active)
{
deactivate();
pData->active = false;
}

if (fInterface != nullptr)
{
fInterface->Close(fInterface);
fInterface = nullptr;
}

// if (fLastChunk != nullptr)
// {
// std::free(fLastChunk);
// fLastChunk = nullptr;
// }

clearBuffers();
}

// -------------------------------------------------------------------
// Information (base)

PluginType getType() const noexcept override
{
return PLUGIN_AU;
}

PluginCategory getCategory() const noexcept override
{
// TODO
return PLUGIN_CATEGORY_NONE;
}

uint32_t getLatencyInFrames() const noexcept override
{
// TODO
return 0;
}

// -------------------------------------------------------------------
// Information (count)

// -------------------------------------------------------------------
// Information (current data)

// -------------------------------------------------------------------
// Information (per-plugin data)

bool getLabel(char* const strBuf) const noexcept override
{
std::strncpy(strBuf, fLabel.buffer(), STR_MAX);
return true;
}

bool getMaker(char* const strBuf) const noexcept override
{
std::strncpy(strBuf, fMaker.buffer(), STR_MAX);
return true;
}

bool getRealName(char* const strBuf) const noexcept override
{
std::strncpy(strBuf, fName.buffer(), STR_MAX);
return true;
}

// -------------------------------------------------------------------
// Plugin state

void reload() override
{
CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);
carla_debug("CarlaPluginAU::reload() - start");

// Safely disable plugin for reload
const ScopedDisabler sd(this);

if (pData->active)
deactivate();

clearBuffers();

bufferSizeChanged(pData->engine->getBufferSize());
reloadPrograms(true);

if (pData->active)
activate();

carla_debug("CarlaPluginAU::reload() - end");
}

// -------------------------------------------------------------------
// Plugin processing

void activate() noexcept override
{
CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);

// TODO
}

void deactivate() noexcept override
{
CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);

// TODO
}

void process(const float* const* const audioIn,
float** const audioOut,
const float* const* const cvIn,
float** const,
const uint32_t frames) override
{
// TODO
}

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

protected:
void handlePluginUIClosed() override
{
carla_stdout("CarlaPluginCLAP::handlePluginUIClosed()");

// TODO
}

void handlePluginUIResized(const uint width, const uint height) override
{
// TODO
}

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

public:
bool init(const CarlaPluginPtr plugin,
const char* const filename,
const char* const label,
const char* const name,
const uint options)
{
CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);

// ---------------------------------------------------------------
// first checks

if (pData->client != nullptr)
{
pData->engine->setLastError("Plugin client is already registered");
return false;
}

if (filename == nullptr || filename[0] == '\0')
{
pData->engine->setLastError("null filename");
return false;
}

if (label == nullptr)
{
pData->engine->setLastError("null label");
return false;
}

// ---------------------------------------------------------------
// load bundle information

if (! fBundleLoader.load(filename))
{
pData->engine->setLastError("Failed to load AU bundle executable");
return false;
}

const CFTypeRef componentsRef = CFBundleGetValueForInfoDictionaryKey(fBundleLoader.getRef(), CFSTR("AudioComponents"));

if (componentsRef == nullptr || CFGetTypeID(componentsRef) != CFArrayGetTypeID())
{
pData->engine->setLastError("Not an AU component");
return false;
}

// ---------------------------------------------------------------
// find binary matching requested label

CFStringRef componentName;
AudioComponentDescription desc = {};
FactoryFn factoryFn;

const CFArrayRef components = static_cast<CFArrayRef>(componentsRef);

for (uint32_t c = 0, count = CFArrayGetCount(components); c < count; ++c)
{
// reset
desc.componentType = 0;

const CFTypeRef componentRef = CFArrayGetValueAtIndex(components, c);
CARLA_SAFE_ASSERT_CONTINUE(componentRef != nullptr);
CARLA_SAFE_ASSERT_CONTINUE(CFGetTypeID(componentRef) == CFDictionaryGetTypeID());

const CFDictionaryRef component = static_cast<CFDictionaryRef>(componentRef);

componentName = nullptr;
CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("name"), (const void **)&componentName));

CFStringRef componentFactoryFunction = nullptr;
CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("factoryFunction"), (const void **)&componentFactoryFunction));

CFStringRef componentType = nullptr;
CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("type"), (const void **)&componentType));
CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentType) == 4);

CFStringRef componentSubType = nullptr;
CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("subtype"), (const void **)&componentSubType));
CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentSubType) == 4);

CFStringRef componentManufacturer = nullptr;
CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("manufacturer"), (const void **)&componentManufacturer));
CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentManufacturer) == 4);

factoryFn = fBundleLoader.getSymbol<FactoryFn>(componentFactoryFunction);
CARLA_SAFE_ASSERT_CONTINUE(factoryFn != nullptr);

char clabel[15] = {};
CFStringGetCString(componentType, clabel, 5, kCFStringEncodingASCII);
CFStringGetCString(componentSubType, clabel + 5, 5, kCFStringEncodingASCII);
CFStringGetCString(componentManufacturer, clabel + 10, 5, kCFStringEncodingASCII);

desc.componentType = getFourCharCodeFromString(clabel);
desc.componentSubType = getFourCharCodeFromString(clabel + 5);
desc.componentManufacturer = getFourCharCodeFromString(clabel + 10);

CARLA_SAFE_ASSERT_CONTINUE(desc.componentType != 0);
CARLA_SAFE_ASSERT_CONTINUE(desc.componentSubType != 0);
CARLA_SAFE_ASSERT_CONTINUE(desc.componentManufacturer != 0);

clabel[4] = clabel[9] = ',';

if (label[0] == '\0' || std::strcmp(label, clabel) == 0)
break;
}

if (desc.componentType == 0)
{
pData->engine->setLastError("Failed to find request plugin in Component bundle");
return false;
}

// ---------------------------------------------------------------
// load binary

fInterface = factoryFn(&desc);
if (fInterface == nullptr)
{
pData->engine->setLastError("Component failed to create new interface");
return false;
}

const InitializeFn auInitialize = (InitializeFn)fInterface->Lookup(kAudioUnitInitializeSelect);
const UninitializeFn auUninitialize = (UninitializeFn)fInterface->Lookup(kAudioUnitUninitializeSelect);
const GetPropertyInfoFn auGetPropertyInfo = (GetPropertyInfoFn)fInterface->Lookup(kAudioUnitGetPropertyInfoSelect);
const GetPropertyFn auGetProperty = (GetPropertyFn)fInterface->Lookup(kAudioUnitGetPropertySelect);
const MIDIEventFn auMIDIEvent = (MIDIEventFn)fInterface->Lookup(kMusicDeviceMIDIEventSelect);

if (auInitialize == nullptr ||
auUninitialize == nullptr ||
auGetPropertyInfo == nullptr ||
auGetProperty == nullptr)
{
pData->engine->setLastError("Component does not provide all necessary functions");
fInterface = nullptr;
return false;
}

if (fInterface->Open(fInterface, (AudioUnit)(void*)0x1) != noErr)
{
pData->engine->setLastError("Component failed to open");
fInterface->Close(fInterface);
fInterface = nullptr;
return false;
}

// ---------------------------------------------------------------
// get info

const CFIndex componentNameLen = CFStringGetLength(componentName);
char* const nameBuffer = new char[componentNameLen + 1];

if (CFStringGetCString(componentName, nameBuffer, componentNameLen + 1, kCFStringEncodingUTF8))
{
if (char* const sep = std::strstr(nameBuffer, ": "))
{
sep[0] = sep[1] = '\0';
fName = sep + 2;
fMaker = nameBuffer;
}
else
{
fName = nameBuffer;
fMaker = nameBuffer + componentNameLen;
}
}

fLabel = label;
pData->name = pData->engine->getUniquePluginName(name != nullptr && name[0] != '\0' ? name : fName.buffer());
pData->filename = carla_strdup(filename);

delete[] nameBuffer;

// ---------------------------------------------------------------
// register client

pData->client = pData->engine->addClient(plugin);

if (pData->client == nullptr || ! pData->client->isOk())
{
pData->engine->setLastError("Failed to register plugin client");
return false;
}

// ---------------------------------------------------------------
// set default options

pData->options = PLUGIN_OPTION_FIXED_BUFFERS;

return true;
}

private:
BundleLoader fBundleLoader;
AudioComponentPlugInInterface* fInterface;
CarlaString fName;
CarlaString fLabel;
CarlaString fMaker;
};
#endif

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

CarlaPluginPtr CarlaPlugin::newAU(const Initializer& init)
{
carla_debug("CarlaPlugin::newAU({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})",
init.engine, init.filename, init.name, init.label, init.uniqueId);
carla_stdout("CarlaPlugin::newAU({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})",
init.engine, init.filename, init.label, init.name, init.uniqueId);

#ifdef CARLA_OS_MAC
std::shared_ptr<CarlaPluginAU> plugin(new CarlaPluginAU(init.engine, init.id));

if (! plugin->init(plugin, init.filename, init.label, init.name, init.options))
return nullptr;

return plugin;
#else
init.engine->setLastError("AU support not available");
return nullptr;
#endif
}

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


+ 5
- 12
source/backend/plugin/Makefile View File

@@ -75,20 +75,13 @@ $(OBJDIR)/CarlaPluginJSFX.cpp.o: CarlaPluginJSFX.cpp
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(YSFX_FLAGS) -c -o $@

ifeq ($(MACOS),true)
$(OBJDIR)/CarlaPluginVST2.cpp.o: CarlaPluginVST2.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@
$(OBJDIR)/CarlaPluginAU.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(OBJDIR)/CarlaPluginVST3.cpp.o: CarlaPluginVST3.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@
$(OBJDIR)/CarlaPluginCLAP.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(OBJDIR)/CarlaPluginCLAP.cpp.o: CarlaPluginCLAP.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling $<"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@
$(OBJDIR)/CarlaPluginVST2.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(OBJDIR)/CarlaPluginVST3.cpp.o: BUILD_CXX_FLAGS += -ObjC++
endif

$(OBJDIR)/%.cpp.o: %.cpp


+ 2
- 0
source/bridges-plugin/Makefile View File

@@ -276,6 +276,8 @@ $(OBJDIR)/CarlaEng%.cpp.o: $(CWD)/backend/engine/CarlaEng%.cpp
$(OBJDIR)/CarlaPluginJSFX.cpp.o: BUILD_CXX_FLAGS += $(YSFX_FLAGS)

ifeq ($(MACOS),true)
$(OBJDIR)/CarlaPluginAU.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(OBJDIR)/CarlaPluginCLAP.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(OBJDIR)/CarlaPluginVST2.cpp.o: BUILD_CXX_FLAGS += -ObjC++


Loading…
Cancel
Save