DPF

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

commit 9f5b0132a3b783e6700f78376451ad3ff8e83dd1
parent 522f691ae6066f2445c7f2992b5c2c57816e216d
Author: falkTX <falktx@falktx.com>
Date:   Sat, 24 Feb 2024 18:07:57 +0100

Proper AU view handling, delete ui on view dealloc

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

Diffstat:
Mdistrho/src/DistrhoPluginAU.cpp | 6++++--
Mdistrho/src/DistrhoUIAU.mm | 123++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 111 insertions(+), 18 deletions(-)

diff --git a/distrho/src/DistrhoPluginAU.cpp b/distrho/src/DistrhoPluginAU.cpp @@ -919,6 +919,7 @@ public: if (d_isNotEqual(fSampleRateForInput, sampleRate)) { fSampleRateForInput = sampleRate; + d_nextSampleRate = sampleRate; #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0 if (d_isEqual(fSampleRateForOutput, sampleRate)) @@ -939,6 +940,7 @@ public: if (d_isNotEqual(fSampleRateForOutput, sampleRate)) { fSampleRateForOutput = sampleRate; + d_nextSampleRate = sampleRate; #if DISTRHO_PLUGIN_NUM_INPUTS != 0 if (d_isEqual(fSampleRateForInput, sampleRate)) @@ -1798,7 +1800,7 @@ private: { fCurrentProgram = program; fPlugin.loadProgram(fCurrentProgram); - notifyListeners('DPFO', kAudioUnitScope_Global, 0); + notifyListeners('DPFo', kAudioUnitScope_Global, 0); } } #endif @@ -1856,7 +1858,7 @@ private: if (fPlugin.getStateKey(j) == key) { if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0) - notifyListeners('DPFS', kAudioUnitScope_Global, j); + notifyListeners('DPFs', kAudioUnitScope_Global, j); break; } diff --git a/distrho/src/DistrhoUIAU.mm b/distrho/src/DistrhoUIAU.mm @@ -21,6 +21,7 @@ #include <AudioUnit/AudioUnit.h> #include <AudioUnit/AUCocoaUIView.h> +#include <Cocoa/Cocoa.h> #undef Point #undef Size @@ -56,12 +57,15 @@ class DPF_UI_AU { public: DPF_UI_AU(const AudioUnit component, - const intptr_t winId, + NSView* const view, const double sampleRate, void* const instancePointer) : fComponent(component), + fParentView(view), fTimerRef(nullptr), - fUI(this, winId, sampleRate, + fUI(this, + reinterpret_cast<uintptr_t>(view), + sampleRate, editParameterCallback, setParameterCallback, setStateCallback, @@ -71,8 +75,6 @@ public: d_nextBundlePath, instancePointer) { - d_stdout("UI created"); - #if DISTRHO_PLUGIN_WANT_STATE // create state keys { @@ -103,6 +105,7 @@ public: fStateKeys[i] = key; } + CFRelease(keysRef); std::free(key); } } @@ -119,6 +122,7 @@ public: CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); + AudioUnitAddPropertyListener(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this); AudioUnitAddPropertyListener(fComponent, 'DPFp', auPropertyChangedCallback, this); #if DISTRHO_PLUGIN_WANT_PROGRAMS AudioUnitAddPropertyListener(fComponent, 'DPFo', auPropertyChangedCallback, this); @@ -130,7 +134,7 @@ public: ~DPF_UI_AU() { - d_stdout("UI destroyed"); + AudioUnitRemovePropertyListenerWithUserData(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this); AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFp', auPropertyChangedCallback, this); #if DISTRHO_PLUGIN_WANT_PROGRAMS AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFo', auPropertyChangedCallback, this); @@ -146,13 +150,27 @@ public: } } - NSView* getNativeView() const + void postSetup() { - return reinterpret_cast<NSView*>(fUI.getNativeWindowHandle()); + if (fUI.isResizable()) + { + // [view setAutoresizingMask:NSViewNotSizable]; + [fParentView setAutoresizesSubviews:YES]; + } + else + { + [fParentView setAutoresizingMask:NSViewNotSizable]; + [fParentView setAutoresizesSubviews:NO]; + } + + // NSView* const uiView = reinterpret_cast<NSView*>(fUI.getNativeWindowHandle()); + + [fParentView setFrameSize:NSMakeSize(fUI.getWidth(), fUI.getHeight())]; } private: const AudioUnit fComponent; + NSView* const fParentView; CFRunLoopTimerRef fTimerRef; UIExporter fUI; @@ -177,6 +195,17 @@ private: // ---------------------------------------------------------------------------------------------------------------- // AU callbacks + void auSampleRateChanged(const AudioUnitScope scope) + { + Float64 sampleRate = 0; + UInt32 dataSize = sizeof(Float64); + if (AudioUnitGetProperty(fComponent, kAudioUnitProperty_SampleRate, scope, 0, &sampleRate, &dataSize) == noErr + && dataSize == sizeof(Float64)) + { + fUI.setSampleRate(sampleRate, true); + } + } + void auParameterChanged(const AudioUnitElement elem) { float value = 0; @@ -236,20 +265,26 @@ private: DISTRHO_SAFE_ASSERT_RETURN(self != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(self->fComponent == component,); - DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,); switch (prop) { + case kAudioUnitProperty_SampleRate: + DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope,); + self->auSampleRateChanged(scope); + break; case 'DPFp': + DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,); self->auParameterChanged(elem); break; #if DISTRHO_PLUGIN_WANT_PROGRAMS case 'DPFo': + DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,); self->auProgramChanged(); break; #endif #if DISTRHO_PLUGIN_WANT_STATE case 'DPFs': + DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,); self->auStateChanged(elem); break; #endif @@ -322,8 +357,9 @@ private: } #endif - void setSize(uint, uint) + void setSize(const uint width, const uint height) { + [fParentView setFrameSize:NSMakeSize(width, height)]; } static void setSizeCallback(void* const ptr, const uint width, const uint height) @@ -341,17 +377,60 @@ END_NAMESPACE_DISTRHO #define MACRO_NAME2(a, b, c, d, e, f) a ## b ## c ## d ## e ## f #define MACRO_NAME(a, b, c, d, e, f) MACRO_NAME2(a, b, c, d, e, f) +// -------------------------------------------------------------------------------------------------------------------- + #define COCOA_VIEW_CLASS_NAME \ - MACRO_NAME(CocoaAUView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_AU_SUBTYPE, _, DISTRHO_PLUGIN_AU_MANUFACTURER) + MACRO_NAME(CocoaView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_AU_SUBTYPE, _, DISTRHO_PLUGIN_AU_MANUFACTURER) -@interface COCOA_VIEW_CLASS_NAME : NSObject<AUCocoaUIBase> +@interface COCOA_VIEW_CLASS_NAME : NSView { +@public DPF_UI_AU* ui; } @end @implementation COCOA_VIEW_CLASS_NAME +- (id) initWithPreferredSize:(NSSize)size +{ + self = [super initWithFrame: NSMakeRect (0, 0, size.width, size.height)]; + [self setHidden:NO]; + return self; +} + +- (BOOL) acceptsFirstResponder +{ + return YES; +} + +- (void) dealloc +{ + delete ui; + ui = nullptr; + + [super dealloc]; +} + +- (BOOL) isFlipped +{ + return YES; +} + +@end + +// -------------------------------------------------------------------------------------------------------------------- + +#define COCOA_UI_CLASS_NAME \ + MACRO_NAME(CocoaAUView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_AU_SUBTYPE, _, DISTRHO_PLUGIN_AU_MANUFACTURER) + +@interface COCOA_UI_CLASS_NAME : NSObject<AUCocoaUIBase> +{ + COCOA_VIEW_CLASS_NAME* view; +} +@end + +@implementation COCOA_UI_CLASS_NAME + - (NSString*) description { return @DISTRHO_PLUGIN_NAME; @@ -364,16 +443,26 @@ END_NAMESPACE_DISTRHO - (NSView*) uiViewForAudioUnit:(AudioUnit)component withSize:(NSSize)inPreferredSize { - const double sampleRate = d_nextSampleRate; - const intptr_t winId = 0; + Float64 sampleRate = d_nextSampleRate; void* instancePointer = nullptr; + UInt32 dataSize; #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS - UInt32 dataSize = sizeof(void*); + dataSize = sizeof(void*); AudioUnitGetProperty(component, 'DPFa', kAudioUnitScope_Global, 0, &instancePointer, &dataSize); #endif - ui = new DPF_UI_AU(component, winId, sampleRate, instancePointer); + #if DISTRHO_PLUGIN_NUM_INPUTS != 0 + dataSize = sizeof(Float64); + AudioUnitGetProperty(component, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sampleRate, &dataSize); + #elif DISTRHO_PLUGIN_NUM_INPUTS != 0 + dataSize = sizeof(Float64); + AudioUnitGetProperty(component, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, &dataSize); + #endif + + view = [[[COCOA_VIEW_CLASS_NAME alloc] initWithPreferredSize:inPreferredSize] autorelease]; + view->ui = new DPF_UI_AU(component, view, sampleRate, instancePointer); + view->ui->postSetup(); // request data from DSP side { @@ -383,11 +472,13 @@ END_NAMESPACE_DISTRHO AudioUnitSetProperty(component, 'DPFi', kAudioUnitScope_Global, 0, &cancel, sizeof(uint16_t)); } - return ui->getNativeView(); + return view; } @end +// -------------------------------------------------------------------------------------------------------------------- + #undef MACRO_NAME #undef MACRO_NAME2