// // 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; }