//------------------------------------------------------------------------ // Project : VST SDK // // Category : Helpers // Filename : public.sdk/source/vst/auwrapper/aucocoaview.mm // Created by : Steinberg, 12/2007 // Description : VST 3 -> AU Wrapper // //----------------------------------------------------------------------------- // This file is part of a Steinberg SDK. It is subject to the license terms // in the LICENSE file found in the top-level directory of this distribution // and at www.steinberg.net/sdklicenses. // No part of the SDK, including this file, may be copied, modified, propagated, // or distributed except according to the terms contained in the LICENSE file. //----------------------------------------------------------------------------- /// \cond ignore #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #import "aucocoaview.h" #import "auwrapper.h" #import "public.sdk/source/vst/utility/objcclassbuilder.h" #import "pluginterfaces/base/funknownimpl.h" #import "pluginterfaces/gui/iplugview.h" #import "pluginterfaces/vst/ivsteditcontroller.h" //------------------------------------------------------------------------ @interface NSObject (SMTG_AUView) - (id)initWithEditController:(Steinberg::Vst::IEditController*)editController audioUnit:(AudioUnit)au preferredSize:(NSSize)size; @end //------------------------------------------------------------------------ namespace Steinberg { namespace { //------------------------------------------------------------------------ struct AUPlugFrame : U::Implements> { AUPlugFrame (NSView* parent) : parent (parent) {} tresult PLUGIN_API resizeView (IPlugView* view, ViewRect* vr) override { NSRect newSize = NSMakeRect ([parent frame].origin.x, [parent frame].origin.y, vr->right - vr->left, vr->bottom - vr->top); [parent setFrame:newSize]; return kResultTrue; } NSView* parent; }; //------------------------------------------------------------------------ struct AUView { static constexpr auto VarNamePlugView = "plugView"; static constexpr auto VarNameEditController = "editController"; static constexpr auto VarNameAudioUnit = "audioUnit"; static constexpr auto VarNameDynlib = "dynlib"; static constexpr auto VarNamePlugFrame = "plugFrame"; static constexpr auto VarNameIsAttached = "isAttached"; struct Instance : ObjCInstance { using PlugViewVar = std::optional>; using EditControllerVar = std::optional>; using AudioUnitVar = std::optional>; using DynlibVar = std::optional>; using PlugFrameVar = std::optional>; using IsAttachedVar = std::optional>; Instance (__unsafe_unretained id obj) : ObjCInstance (obj, [NSView class]) { plugView = getVariable (VarNamePlugView); editController = getVariable (VarNameEditController); audioUnit = getVariable (VarNamePlugView); dynlib = getVariable (VarNameDynlib); plugFrame = getVariable (VarNamePlugFrame); isAttached = getVariable (VarNameIsAttached); } PlugViewVar plugView; EditControllerVar editController; AudioUnitVar audioUnit; DynlibVar dynlib; PlugFrameVar plugFrame; IsAttachedVar isAttached; }; static id alloc () { static ObjCClass gInstance; return [gInstance.cl alloc]; } private: struct ObjCClass { Class cl; ObjCClass () { cl = ObjCClassBuilder () .init ("SMTG_AUView", [NSView class]) .addIvar (VarNamePlugView) .addIvar (VarNameEditController) .addIvar (VarNameAudioUnit) .addIvar (VarNameDynlib) .addIvar (VarNamePlugFrame) .addIvar (VarNameIsAttached) .addMethod (@selector (initWithEditController:audioUnit:preferredSize:), initWithEditController) .addMethod (@selector (setFrame:), setFrame) .addMethod (@selector (isFlipped), isFlipped) .addMethod (@selector (viewDidMoveToSuperview), viewDidMoveToSuperview) .addMethod (@selector (dealloc), dealloc) .finalize (); } static id initWithEditController (id self, SEL cmd, Vst::IEditController* editController, AudioUnit au, NSSize size) { ObjCInstance obj (self); self = obj.callSuper (@selector (initWithFrame:), NSMakeRect (0, 0, size.width, size.height)); if (self) { Instance inst (self); inst.editController->set (editController); editController->addRef (); inst.audioUnit->set (au); auto plugView = editController->createView (Vst::ViewType::kEditor); if (!plugView || plugView->isPlatformTypeSupported (kPlatformTypeNSView) != kResultTrue) { [self dealloc]; return nil; } inst.plugView->set (plugView); auto plugFrame = NEW AUPlugFrame (self); inst.plugFrame->set (plugFrame); plugView->setFrame (plugFrame); if (plugView->attached (self, kPlatformTypeNSView) != kResultTrue) { [self dealloc]; return nil; } ViewRect vr; if (plugView->getSize (&vr) == kResultTrue) { NSRect newSize = NSMakeRect (0, 0, vr.right - vr.left, vr.bottom - vr.top); [self setFrame:newSize]; } inst.isAttached->set (YES); FObject* fObject = nullptr; UInt32 size = sizeof (FObject*); if (AudioUnitGetProperty (au, 64001, kAudioUnitScope_Global, 0, &fObject, &size) == noErr) { fObject->addRef (); inst.dynlib->set (fObject); } } return self; } static void setFrame (id self, SEL cmd, NSRect newSize) { Instance inst (self); inst.callSuper (@selector (setFrame:), newSize); ViewRect viewRect (0, 0, newSize.size.width, newSize.size.height); if (inst.plugView->get ()) inst.plugView->get ()->onSize (&viewRect); } static BOOL isFlipped (id self, SEL cmd) { return YES; } static void viewDidMoveToSuperview (id self, SEL cmd) { Instance inst (self); if (inst.plugView->get ()) { if ([self superview]) { if (!inst.isAttached->get ()) { if (inst.plugView->get ()->attached (self, kPlatformTypeNSView) == kResultTrue) { inst.isAttached->set (YES); } } } else { if (inst.isAttached->get ()) { inst.plugView->get ()->removed (); inst.isAttached->set (NO); } } } } static void dealloc (id self, SEL cmd) { Instance inst (self); if (auto plugView = inst.plugView->get ()) { if (inst.isAttached->get ()) { plugView->setFrame (0); plugView->removed (); } plugView->release (); if (auto plugFrame = inst.plugFrame->get ()) plugFrame->release (); if (auto editController = inst.editController->get ()) { auto refCount = editController->addRef (); if (refCount == 2) editController->terminate (); editController->release (); editController->release (); inst.editController->set (nullptr); } } if (auto dynlib = inst.dynlib->get ()) dynlib->release (); inst.callSuper (@selector (dealloc)); } }; }; //------------------------------------------------------------------------ } // anonymous } // Steinberg //------------------------------------------------------------------------ @implementation SMTG_AUCocoaUIBase_CLASS_NAME //------------------------------------------------------------------------ - (unsigned)interfaceVersion { return 0; } //------------------------------------------------------------------------ - (NSString*)description { return @"Cocoa View"; } //------------------------------------------------------------------------ - (NSView*)uiViewForAudioUnit:(AudioUnit)inAU withSize:(NSSize)inPreferredSize { using namespace Steinberg; Vst::IEditController* editController = 0; UInt32 size = sizeof (Vst::IEditController*); if (AudioUnitGetProperty (inAU, 64000, kAudioUnitScope_Global, 0, &editController, &size) != noErr) return nil; return [[AUView::alloc () initWithEditController:editController audioUnit:inAU preferredSize:inPreferredSize] autorelease]; } @end /// \endcond