// // AUPlayerView.mm // MIDI // // Created by Christopher Snowhill on 1/29/16. // Copyright © 2016-2022 Christopher Snowhill. All rights reserved. // #import #import #import "AUPlayerView.h" AUPluginUI::AUPluginUI (AudioUnit & _au) : au (_au) , mapped (false) , resizable (false) , min_width (0) , min_height (0) , req_width (0) , req_height (0) , alo_width (0) , alo_height (0) { cocoa_window = nil; au_view = nil; if (test_cocoa_view_support()) { create_cocoa_view (); } if (au_view) { cocoa_window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, req_width, req_height) styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable) backing:NSBackingStoreBuffered defer:NO]; [cocoa_window setAutodisplay:YES]; [cocoa_window setTitle:@"AU Plug-in"]; [cocoa_window setOneShot:YES]; [cocoa_window setContentView:au_view]; [cocoa_window orderFront:cocoa_window]; } } AUPluginUI::~AUPluginUI() { } bool AUPluginUI::test_cocoa_view_support () { UInt32 dataSize = 0; Boolean isWritable = 0; OSStatus err = AudioUnitGetPropertyInfo(au, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable); return dataSize > 0 && err == noErr; } bool AUPluginUI::plugin_class_valid (Class pluginClass) { if([pluginClass conformsToProtocol: @protocol(AUCocoaUIBase)]) { if([pluginClass instancesRespondToSelector: @selector(interfaceVersion)] && [pluginClass instancesRespondToSelector: @selector(uiViewForAudioUnit:withSize:)]) { return true; } } return false; } int AUPluginUI::create_cocoa_view () { bool wasAbleToLoadCustomView = false; AudioUnitCocoaViewInfo* cocoaViewInfo = NULL; UInt32 numberOfClasses = 0; UInt32 dataSize; Boolean isWritable; NSString* factoryClassName = 0; NSURL* CocoaViewBundlePath = NULL; OSStatus result = AudioUnitGetPropertyInfo (au, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, &dataSize, &isWritable ); numberOfClasses = (dataSize - sizeof(CFURLRef)) / sizeof(CFStringRef); // Does view have custom Cocoa UI? if ((result == noErr) && (numberOfClasses > 0) ) { cocoaViewInfo = (AudioUnitCocoaViewInfo *)malloc(dataSize); if(AudioUnitGetProperty(au, kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global, 0, cocoaViewInfo, &dataSize) == noErr) { CocoaViewBundlePath = (__bridge NSURL *)cocoaViewInfo->mCocoaAUViewBundleLocation; // we only take the first view in this example. factoryClassName = (__bridge NSString *)cocoaViewInfo->mCocoaAUViewClass[0]; } else { if (cocoaViewInfo != NULL) { free (cocoaViewInfo); cocoaViewInfo = NULL; } } } // [A] Show custom UI if view has it if (CocoaViewBundlePath && factoryClassName) { NSBundle *viewBundle = [NSBundle bundleWithPath:[CocoaViewBundlePath path]]; if (viewBundle == NULL) { return -1; } else { Class factoryClass = [viewBundle classNamed:factoryClassName]; if (!factoryClass) { return -1; } // make sure 'factoryClass' implements the AUCocoaUIBase protocol if (!plugin_class_valid (factoryClass)) { return -1; } // make a factory id factory = [[factoryClass alloc] init]; if (factory == NULL) { return -1; } // make a view au_view = [factory uiViewForAudioUnit:au withSize:NSZeroSize]; // cleanup if (cocoaViewInfo) { UInt32 i; for (i = 0; i < numberOfClasses; i++) CFRelease(cocoaViewInfo->mCocoaAUViewClass[i]); free (cocoaViewInfo); } wasAbleToLoadCustomView = true; } } if (!wasAbleToLoadCustomView) { // load generic Cocoa view au_view = [[AUGenericView alloc] initWithAudioUnit:au]; [(AUGenericView *)au_view setShowsExpertParameters:1]; } // Get the initial size of the new AU View's frame NSRect frame = [au_view frame]; min_width = req_width = CGRectGetWidth(NSRectToCGRect(frame)); min_height = req_height = CGRectGetHeight(NSRectToCGRect(frame)); resizable = [au_view autoresizingMask]; return 0; }