DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit f1366080a7090a87ab5dddd71168af25b4072861
parent cff94b659c5e8de0f2ff8fd59d53663e3d46cfa2
Author: falkTX <falktx@falktx.com>
Date:   Mon, 19 Feb 2024 16:42:43 +0100

stubs for AU UI creation, works but does nothing

Signed-off-by: falkTX <falktx@falktx.com>

Diffstat:
MMakefile.plugins.mk | 10++++++++++
Mdistrho/DistrhoUIMain.cpp | 1+
Mdistrho/extra/FileBrowserDialogImpl.cpp | 9++++++++-
Mdistrho/src/DistrhoPluginAU.cpp | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Adistrho/src/DistrhoUIAU.mm | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 304 insertions(+), 9 deletions(-)

diff --git a/Makefile.plugins.mk b/Makefile.plugins.mk @@ -467,6 +467,16 @@ $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain @echo "Compiling DistrhoPluginMain.cpp (JACK)" $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_JACK $(JACK_FLAGS) -c -o $@ +$(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_DSP_DEPENDENCIES) + -@mkdir -p $(BUILD_DIR) + @echo "Compiling DistrhoPluginMain.cpp (AU)" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_AU -ObjC++ -c -o $@ + +$(BUILD_DIR)/DistrhoUIMain_AU.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES) + -@mkdir -p $(BUILD_DIR) + @echo "Compiling DistrhoUIMain.cpp (AU)" + $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_AU -ObjC++ -c -o $@ + $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES) -@mkdir -p $(BUILD_DIR) @echo "Compiling DistrhoUIMain.cpp (DSSI)" diff --git a/distrho/DistrhoUIMain.cpp b/distrho/DistrhoUIMain.cpp @@ -25,6 +25,7 @@ #if defined(DISTRHO_PLUGIN_TARGET_AU) # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 +# import "src/DistrhoUIAU.mm" #elif defined(DISTRHO_PLUGIN_TARGET_CARLA) # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 #elif defined(DISTRHO_PLUGIN_TARGET_CLAP) diff --git a/distrho/extra/FileBrowserDialogImpl.cpp b/distrho/extra/FileBrowserDialogImpl.cpp @@ -490,7 +490,11 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, [nsOpenPanel setCanChooseFiles:YES]; } - [nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]]; + NSString* const startDirString = [[NSString alloc] + initWithBytes:startDir + length:strlen(startDir) + encoding:NSUTF8StringEncoding]; + [nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:startDirString]]; // TODO file filter using allowedContentTypes: [UTType] @@ -523,6 +527,9 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed, } }]; }); + + [startDirString release]; + [titleString release]; # endif #endif diff --git a/distrho/src/DistrhoPluginAU.cpp b/distrho/src/DistrhoPluginAU.cpp @@ -15,6 +15,7 @@ */ #include "DistrhoPluginInternal.hpp" +#include "../DistrhoPluginUtils.hpp" // #define CA_BASIC_AU_FEATURES 1 #define CA_NO_AU_UI_FEATURES 1 @@ -22,6 +23,7 @@ #define TARGET_OS_MAC 1 #include <AudioUnit/AudioUnit.h> +#include <AudioUnit/AUCocoaUIView.h> #define TRACE d_stderr("////////--------------------------------------------------------------- %s %d", __PRETTY_FUNCTION__, __LINE__); @@ -356,26 +358,66 @@ protected: return res; } -#if 0 - OSStatus GetPropertyInfo(AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, + OSStatus GetPropertyInfo(const AudioUnitPropertyID inID, + const AudioUnitScope inScope, + const AudioUnitElement inElement, UInt32& outDataSize, Boolean& outWritable) override { TRACE + if (inScope == kAudioUnitScope_Global) + { + switch (inID) + { + #if DISTRHO_PLUGIN_HAS_UI + case kAudioUnitProperty_CocoaUI: + outDataSize = sizeof(AudioUnitCocoaViewInfo); + outWritable = true; + return noErr; + #endif + default: + break; + } + } + return PluginBase::GetPropertyInfo(inID, inScope, inElement, outDataSize, outWritable); } - OSStatus GetProperty(AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement, - void* outData) override + OSStatus GetProperty(const AudioUnitPropertyID inID, + const AudioUnitScope inScope, + const AudioUnitElement inElement, + void* const outData) override { TRACE + if (inScope == kAudioUnitScope_Global) + { + switch (inID) + { + #if DISTRHO_PLUGIN_HAS_UI + case kAudioUnitProperty_CocoaUI: + if (AudioUnitCocoaViewInfo* const info = static_cast<AudioUnitCocoaViewInfo*>(outData)) + { + NSString* const bundlePathString = [[NSString alloc] + initWithBytes:d_nextBundlePath + length:strlen(d_nextBundlePath) + encoding:NSUTF8StringEncoding]; + + info->mCocoaAUViewBundleLocation = static_cast<CFURLRef>([[NSURL fileURLWithPath: bundlePathString] retain]); + info->mCocoaAUViewClass[0] = CFSTR("DPF_UI_ViewFactory"); + + [bundlePathString release]; + } + return noErr; + #endif + default: + break; + } + } + return PluginBase::GetProperty(inID, inScope, inElement, outData); } +#if 0 OSStatus SetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, @@ -526,6 +568,14 @@ protected: return noErr; } + void SetMaxFramesPerSlice(const UInt32 nFrames) override + { + PluginBase::SetMaxFramesPerSlice(nFrames); + + DISTRHO_SAFE_ASSERT_RETURN(!fPlugin.isActive(),); + fPlugin.setBufferSize(nFrames, true); + } + UInt32 GetChannelLayoutTags(const AudioUnitScope scope, const AudioUnitElement element, AudioChannelLayoutTag* const outLayoutTags) override @@ -647,9 +697,33 @@ void* PluginAUFactory(const AudioComponentDescription* const inDesc) TRACE if (d_nextBufferSize == 0) d_nextBufferSize = kAUDefaultMaxFramesPerSlice; + if (d_isZero(d_nextSampleRate)) d_nextSampleRate = kAUDefaultSampleRate; + if (d_nextBundlePath == nullptr) + { + static String bundlePath; + + String tmpPath(getBinaryFilename()); + tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); + tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); + + if (tmpPath.endsWith(DISTRHO_OS_SEP_STR "Contents")) + { + tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); + bundlePath = tmpPath; + } + else + { + bundlePath = "error"; + } + + d_nextBundlePath = bundlePath.buffer(); + } + + // d_nextCanRequestParameterValueChanges = true; + return PluginBaseFactory<PluginAU>::Factory(inDesc); } diff --git a/distrho/src/DistrhoUIAU.mm b/distrho/src/DistrhoUIAU.mm @@ -0,0 +1,203 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2024 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. + */ + +// TODO +// - g_nextBundlePath vs d_nextBundlePath cleanup + +#include "DistrhoUIInternal.hpp" + +#define Point AudioUnitPoint +#define Size AudioUnitSize + +// #include <AudioUnit/AudioUnit.h> +#include <AudioUnit/AUCocoaUIView.h> + +#undef Point +#undef Size + +START_NAMESPACE_DISTRHO + +// -------------------------------------------------------------------------------------------------------------------- + +#if ! DISTRHO_PLUGIN_WANT_STATE +static constexpr const setStateFunc setStateCallback = nullptr; +#endif +#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT +static constexpr const sendNoteFunc sendNoteCallback = nullptr; +#endif + +// -------------------------------------------------------------------------------------------------------------------- +// Static data, see DistrhoPlugin.cpp + +extern double d_nextSampleRate; +extern const char* d_nextBundlePath; + +// -------------------------------------------------------------------------------------------------------------------- + +class DPF_UI_AU +{ +public: + DPF_UI_AU(const AudioUnit inAU, + const intptr_t winId, + const double sampleRate, + void* const instancePointer) + : fAU(inAU), + fTimerRef(nullptr), + fUI(this, winId, sampleRate, + editParameterCallback, + setParameterCallback, + setStateCallback, + sendNoteCallback, + setSizeCallback, + nullptr, // TODO file request + d_nextBundlePath, + instancePointer) + { + constexpr const CFTimeInterval interval = 60 * 0.0001; + + CFRunLoopTimerContext context = {}; + context.info = this; + fTimerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval, interval, 0, 0, + _idleCallback, &context); + DISTRHO_SAFE_ASSERT_RETURN(fTimerRef != nullptr,); + + CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); + } + + ~DPF_UI_AU() + { + if (fTimerRef != nullptr) + { + CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); + CFRelease(fTimerRef); + } + } + + NSView* getNativeView() const + { + return reinterpret_cast<NSView*>(fUI.getNativeWindowHandle()); + } + +private: + const AudioUnit fAU; + CFRunLoopTimerRef fTimerRef; + + UIExporter fUI; + + // ---------------------------------------------------------------------------------------------------------------- + // Idle setup + + void idleCallback() + { + fUI.idleFromNativeIdle(); + } + + static void _idleCallback(CFRunLoopTimerRef, void* const info) + { + static_cast<DPF_UI_AU*>(info)->idleCallback(); + } + + // ---------------------------------------------------------------------------------------------------------------- + // DPF callbacks + + void editParameter(uint32_t, bool) const + { + } + + static void editParameterCallback(void* const ptr, const uint32_t rindex, const bool started) + { + static_cast<DPF_UI_AU*>(ptr)->editParameter(rindex, started); + } + + void setParameterValue(uint32_t, float) + { + } + + static void setParameterCallback(void* const ptr, const uint32_t rindex, const float value) + { + static_cast<DPF_UI_AU*>(ptr)->setParameterValue(rindex, value); + } + + #if DISTRHO_PLUGIN_WANT_STATE + void setState(const char*, const char*) + { + } + + static void setStateCallback(void* const ptr, const char* const key, const char* const value) + { + static_cast<DPF_UI_AU*>(ptr)->setState(key, value); + } + #endif + + #if DISTRHO_PLUGIN_WANT_MIDI_INPUT + void sendNote(uint8_t, uint8_t, uint8_t) + { + } + + static void sendNoteCallback(void* const ptr, const uint8_t channel, const uint8_t note, const uint8_t velocity) + { + static_cast<DPF_UI_AU*>(ptr)->sendNote(channel, note, velocity); + } + #endif + + void setSize(uint, uint) + { + } + + static void setSizeCallback(void* const ptr, const uint width, const uint height) + { + static_cast<DPF_UI_AU*>(ptr)->setSize(width, height); + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +// -------------------------------------------------------------------------------------------------------------------- + +@interface DPF_UI_ViewFactory : NSObject<AUCocoaUIBase> +{ + DPF_UI_AU* ui; +} +@end + +@implementation DPF_UI_ViewFactory + +- (NSString*) description +{ + return [NSString stringWithUTF8String:DISTRHO_PLUGIN_NAME]; +} + +- (unsigned) interfaceVersion +{ + return 0; +} + +- (NSView*) uiViewForAudioUnit:(AudioUnit)inAU withSize:(NSSize)inPreferredSize +{ + const double sampleRate = d_nextSampleRate; + const intptr_t winId = 0; + void* const instancePointer = nullptr; + + ui = new DPF_UI_AU(inAU, winId, sampleRate, instancePointer); + + return ui->getNativeView(); +} + +@end + +// --------------------------------------------------------------------------------------------------------------------