/*============================================================================= * AUPresetManager.m * PlayPen *----------------------------------------------------------------------------- * * $Log: AUPresetManager.mm,v $ * Revision 1.8.6.2 2005/08/12 00:44:25 mhopkins * Pull latest version from TOT * * Revision 1.10 2005/06/03 19:25:40 luke * use new unsetCAFileHandlingObject interface * * Revision 1.9 2005/05/31 19:36:19 luke * rdar://4129221 need to call AUParameterListenerNotify(...) when changing factory presets as well as other kinds * * Revision 1.8 2005/03/09 22:42:22 dwyatt * don't leak presetToSet.presetName in itemWasActivated * * Revision 1.7 2005/03/09 01:38:13 bills * fix setting preset calls * * Revision 1.6 2005/03/08 02:19:27 dwyatt * don't leak CFPropertyListRefs * * Revision 1.5 2004/11/16 17:35:35 luke * clean up code * * Revision 1.4 2004/11/13 17:46:17 luke * removed NSAsserts & better handling errors * * Revision 1.3 2004/11/10 03:34:24 bills * delete on NULL is ok * * Revision 1.2 2004/11/10 03:32:52 bills * fix dealloc method * * Revision 1.1 2004/07/29 00:21:15 luke * factored out from PlayPen * * Revision 1.12 2004/07/29 00:08:51 luke * tweaks * * Revision 1.11 2004/07/28 23:57:20 luke * pass 3: final * * Revision 1.9 2004/07/28 20:49:24 luke * align with changes to CAFileBrowser * * Revision 1.8 2004/07/07 00:24:16 luke * [3482090] make AUInspector localizable * * Revision 1.7 2004/06/24 23:20:22 mhopkins * added method to return name and data key strings * * Revision 1.6 2004/05/27 22:56:08 luke * don't allow Factory presets to be renamed * * Revision 1.5 2004/05/26 19:42:47 luke * don't show factory preset option if unit doesn't have any factory presets * * Revision 1.4 2004/05/26 17:13:01 luke * [3656248] only search Network for presets when preferences say to do so * * Revision 1.3 2004/05/25 22:23:36 luke * sync. with changes to superclass & deallocate correctly * * Revision 1.2 2004/04/29 23:08:39 luke * fix sync w/ interface changes to AUInspector * * Revision 1.1 2004/04/17 20:05:20 luke * source reorg. * * Revision 1.22 2003/12/18 19:48:29 luke * push directory-creation code into CAFileBrowser superclass * * Revision 1.21 2003/12/02 01:17:19 luke * CAFileHandling factored * * Revision 1.20 2003/11/20 00:58:31 crogers * check factoryPresets for NULL * * Revision 1.19 2003/11/12 23:58:02 luke * tweak includes * * Revision 1.18 2003/11/06 19:25:04 luke * change title: 'Presets' -> 'AudioUnit Presets * * Revision 1.17 2003/10/30 19:08:08 luke * fix for NetInfo user dirs * * Revision 1.16 2003/10/22 20:21:39 luke * don't notify on presetChange: use propListeners * * Revision 1.15 2003/10/21 23:28:26 luke * added features that future subclasses may need * * Revision 1.14 2003/10/21 22:03:57 luke * change some behavior per discussions with Bill * * Revision 1.13 2003/10/21 18:53:52 luke * call self, not super * * Revision 1.12 2003/10/17 22:39:14 luke * implement preset saving * * Revision 1.11 2003/10/15 16:56:43 luke * tighten up code. * * Revision 1.10 2003/10/15 00:46:04 luke * tighten up code * * Revision 1.9 2003/10/15 00:12:50 luke * factor general support into CAFileBrowser class * * Revision 1.8 2003/10/14 19:18:32 luke * sync. with changes to CAFileHandling * * Revision 1.7 2003/10/14 18:18:19 luke * sync. with requested changes to CAFileHandling * * Revision 1.6 2003/10/14 17:25:35 luke * fix warnings * * Revision 1.5 2003/10/14 17:21:59 luke * now using CAFileHandling class * * Revision 1.4 2003/09/24 21:07:28 luke * alert AUParameterListeners when we load a preset * * Revision 1.3 2003/09/24 06:39:37 luke * finish implementation of preset browser * * Revision 1.2 2003/09/23 20:46:44 luke * updates * * Revision 1.1 2003/09/23 17:22:01 luke * AUPresetManager.m -> AUPresetManager.mm * * Revision 1.1 2003/09/23 00:58:22 luke * new file * *----------------------------------------------------------------------------- * Created by Luke Bellandi on Mon Sep 22 2003. * Copyright (c) 2003 Apple Computer Inc. All rights reserved. *=============================================================================*/ #import #import #import "CAComponent.h" #import "CAAUPresetFile.h" #import "AUPresetManager.h" #import "CAFileBrowser_Protected.h" @implementation AUPresetManager #pragma mark ____ PRIVATE FUNCTIONS ____ - (void)privGetFactoryPresets { // dump old presets [mFactoryPresets removeAllObjects]; // can't do anything if no AU selected if (mAudioUnit == NULL) return; NSMutableArray *presetArray = [NSMutableArray array]; [mFactoryPresets setObject:presetArray forKey:NSLocalizedStringFromTable(@"Factory", @"AUInspector", @"Factory Preset group heading")]; // get new presets CFArrayRef factoryPresets = NULL; UInt32 dataSize = sizeof(factoryPresets); ComponentResult result = AudioUnitGetProperty ( mAudioUnit, kAudioUnitProperty_FactoryPresets, kAudioUnitScope_Global, 0, &factoryPresets, &dataSize ); if ((result == noErr) && (factoryPresets != NULL)) { int count = CFArrayGetCount(factoryPresets); AUPreset * currentPreset; for (int i = 0; i < count; ++i) { currentPreset = (AUPreset*) CFArrayGetValueAtIndex (factoryPresets, i); [presetArray addObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithLong:currentPreset->presetNumber] forKey:(NSString *)(currentPreset->presetName)]]; } CFRelease(factoryPresets); } } - (BOOL)privHasFactoryPresets { NSArray *valueArray = [mFactoryPresets allValues]; if ([valueArray count] <= 0) return NO; NSArray *factoryPresetArray = (NSArray *)[valueArray objectAtIndex:0]; return [factoryPresetArray count] > 0; } #pragma mark ____ INIT / DEALLOC ____ - (id)initWithFrame:(NSRect)frame shouldScanNetworkForFiles:(BOOL)shouldScanNetworkForFiles { [super initWithFrame:frame shouldScanNetworkForFiles:shouldScanNetworkForFiles]; [self setTitle:NSLocalizedStringFromTable(@"AudioUnit Presets", @"AUInspector", @"Audio Unit Preset manager title")]; mFactoryPresets = [[NSMutableDictionary alloc] init]; return self; } - (id)initWithFrame:(NSRect)frame { return [self initWithFrame:frame shouldScanNetworkForFiles:NO]; } - (void)dealloc { [mFactoryPresets release]; delete mPresetFile; // can call delete on NULL [super dealloc]; } #pragma mark ____ PUBLIC FUNCTIONS ____ - (void)setAU:(AudioUnit)inAU { mAudioUnit = inAU; [self unsetCAFileHandlingObject]; if (mPresetFile) delete mPresetFile; mPresetFile = new CAAUPresetFile (CAComponent(mAudioUnit), [self scansNetworkForFiles]); [self privGetFactoryPresets]; [self setCAFileHandlingObject:mPresetFile]; [self reloadData]; } - (BOOL)savePresetWithName:(NSString *)inPresetName asChildOf:(id)item { AUPreset presetToSet; presetToSet.presetName = (CFStringRef)inPresetName; presetToSet.presetNumber = -1; ComponentResult result = AudioUnitSetProperty ( mAudioUnit, kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0, &presetToSet, sizeof(AUPreset) ); if (result != noErr) { result = AudioUnitSetProperty ( mAudioUnit, kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0, &presetToSet, sizeof(AUPreset) ); if (result != noErr) return NO; } // now get classInfo & write to file CFPropertyListRef classInfo = NULL; UInt32 dataSize = sizeof(CFPropertyListRef); result = AudioUnitGetProperty ( mAudioUnit, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classInfo, &dataSize); if (result != noErr) return NO; BOOL retVal = [self writePropertyList:classInfo withName:inPresetName asChildOfItem:item]; if (classInfo) CFRelease (classInfo); [self rescanFiles]; return retVal; } - (void)rescanFiles { [self setAU:mAudioUnit]; } #pragma mark ____ PROTECTED FUNCTIONS ____ - (BOOL)itemWasActivated:(id)object { if ([object isKindOfClass:[NSDictionary class]]) { // FACTORY PRESETS id obj = [[(NSDictionary *)object allValues] objectAtIndex:0]; if (![obj isKindOfClass:[NSNumber class]]) return NO; NSString *presetName = (NSString *)[[(NSDictionary *)object allKeys] objectAtIndex:0]; UInt32 presetNumber = [(NSNumber *)obj longValue]; AUPreset presetToSet; presetToSet.presetName = (CFStringRef)presetName; presetToSet.presetNumber = presetNumber; ComponentResult result = AudioUnitSetProperty ( mAudioUnit, kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0, &presetToSet, sizeof(AUPreset) ); if (result != noErr) { // try old 'currentPreset' property if presentPreset doesn't work result = AudioUnitSetProperty ( mAudioUnit, kAudioUnitProperty_CurrentPreset, kAudioUnitScope_Global, 0, &presetToSet, sizeof(AUPreset) ); if (result != noErr) return NO; } } else { // LOCAL/USER/NETWORK PRESETS CFPropertyListRef preset = [self readPropertyListForItem:object]; if (preset == NULL) return NO; // set preset in AU AUPreset presetToSet; CFTreeRef tree = (CFTreeRef)[(NSValue *)object pointerValue]; mPresetFile->GetNameCopy(tree, presetToSet.presetName); presetToSet.presetNumber = -1; ComponentResult result = AudioUnitSetProperty ( mAudioUnit, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &preset, sizeof(CFPropertyListRef)); CFRelease(preset); CFRelease(presetToSet.presetName); if (result != noErr) return NO; } // notify parameter listeners that they should re-scan unit AudioUnitParameter changedUnit; changedUnit.mAudioUnit = mAudioUnit; changedUnit.mParameterID = kAUParameterListener_AnyParameter; if (AUParameterListenerNotify (NULL, NULL, &changedUnit) != noErr) return NO; return YES; } - (NSString *)fileExtension { return (NSString *)CAAUPresetFile::kAUPresetFileExtension; } - (NSString *)nameKeyString { return (NSString *)CAAUPresetFile::kAUPresetNameKeyString; } - (BOOL)shouldAllowItemRenaming:(id)inItem { return (![inItem isKindOfClass:[NSDictionary class]]); } #pragma mark ____NSOutlineView.DataSource overrides____ // override outlineView dataSource methods so we can integrate factory presets - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item { // TOP LEVEL? if (item == nil) { if ([self privHasFactoryPresets]) { if (index == 0) return mFactoryPresets; return [super outlineView:outlineView child:(index - 1) ofItem:item]; } else { return [super outlineView:outlineView child:index ofItem:item]; } } // FACTORY PRESET? if ([item isKindOfClass:[NSDictionary class]]) { NSArray *array = [(NSDictionary*)item allValues]; if ([array count] <= 0) return nil; id obj = [array objectAtIndex:0]; if ([obj isKindOfClass:[NSArray class]]) return [(NSArray *)obj objectAtIndex:index]; else return obj; // NSDictionary * } // ELSE SUPERCLASS HANDLING return [super outlineView:outlineView child:index ofItem:item]; } - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { // TOP LEVEL? if (item == nil) { int factoryOffset = ([self privHasFactoryPresets] > 0) ? 1 : 0; return [super outlineView:outlineView numberOfChildrenOfItem:item] + factoryOffset; } // FACTORY PRESET? if ([item isKindOfClass:[NSDictionary class]]) { NSArray *array = [(NSDictionary*)item allValues]; if ([array count] <= 0) return 0; id obj = [array objectAtIndex:0]; if ([obj isKindOfClass:[NSArray class]]) return [(NSArray *)obj count]; else return 0; } // ELSE SUPERCLASS HANDLING return [super outlineView:outlineView numberOfChildrenOfItem:item]; } - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { // TOP LEVEL? if (item == nil) return NO; // FACTORY PRESET? if ([item isKindOfClass:[NSDictionary class]]) { NSArray *array = [(NSDictionary*)item allValues]; if ([array count] <= 0) return NO; id obj = [array objectAtIndex:0]; return [obj isKindOfClass:[NSArray class]]; } // ELSE SUPERCLASS HANDLING return [super outlineView:outlineView isItemExpandable:item]; } - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { NSString *title = nil; if ([item isKindOfClass:[NSArray class]]) { title = NSLocalizedStringFromTable(@"Factory", @"AUInspector", @"Factory Preset group heading"); } else if ([item isKindOfClass:[NSDictionary class]]) { title = (NSString *)[[(NSDictionary *)item allKeys] objectAtIndex:0]; } if (title != nil) { NSCell *cell = [self cell]; float fontSize = [[cell font] pointSize]; if ([self outlineView:outlineView isItemExpandable:item]) { [cell setFont:[NSFont boldSystemFontOfSize:fontSize]]; } else { [cell setFont:[NSFont systemFontOfSize:fontSize]]; } [cell setTitle:title]; return cell; } // ELSE SUPERCLASS HANDLING return [super outlineView:outlineView objectValueForTableColumn:tableColumn byItem:item]; } @end