mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
Add a crappy utility for editing AU effect presets
This commit is contained in:
parent
209734925f
commit
7251c89cf4
@ -86,7 +86,7 @@ function mainProject(_target, _subtarget)
|
||||
linkoptions {
|
||||
"-sectcreate __TEXT __info_plist " .. GEN_DIR .. "/resource/" .. _target .. "-Info.plist"
|
||||
}
|
||||
custombuildtask {
|
||||
custombuildtask {
|
||||
{ MAME_DIR .. "src/version.c" , GEN_DIR .. "/resource/" .. _target .. "-Info.plist", { MAME_DIR .. "src/build/verinfo.py" }, {"@echo Emitting " .. _target .. "-Info.plist" .. "...", "python $(1) -p -b " .. _target .. " $(<) > $(@)" }},
|
||||
}
|
||||
dependency {
|
||||
|
@ -76,7 +76,7 @@ function maintargetosdoptions(_target)
|
||||
"bsd",
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
configuration { "mingw*" or "vs*" }
|
||||
targetprefix "sdl"
|
||||
|
||||
@ -366,11 +366,11 @@ project ("ocore_" .. _OPTIONS["osd"])
|
||||
}
|
||||
|
||||
removeflags {
|
||||
"SingleOutputDir",
|
||||
"SingleOutputDir",
|
||||
}
|
||||
|
||||
dofile("sdl_cfg.lua")
|
||||
|
||||
|
||||
includedirs {
|
||||
MAME_DIR .. "src/emu",
|
||||
MAME_DIR .. "src/osd",
|
||||
@ -428,7 +428,7 @@ if _OPTIONS["with-tools"] then
|
||||
MAME_DIR .. "src/osd",
|
||||
MAME_DIR .. "src/lib/util",
|
||||
}
|
||||
|
||||
|
||||
targetdir(MAME_DIR)
|
||||
|
||||
links {
|
||||
@ -440,8 +440,8 @@ if _OPTIONS["with-tools"] then
|
||||
MAME_DIR .. "src/osd/sdl/testkeys.c",
|
||||
}
|
||||
|
||||
if _OPTIONS["targetos"]=="windows" then
|
||||
if _OPTIONS["SDL_LIBVER"]=="sdl2" then
|
||||
if _OPTIONS["targetos"] == "windows" then
|
||||
if _OPTIONS["SDL_LIBVER"] == "sdl2" then
|
||||
links {
|
||||
"SDL2.dll",
|
||||
}
|
||||
@ -456,10 +456,49 @@ if _OPTIONS["with-tools"] then
|
||||
files {
|
||||
MAME_DIR .. "src/osd/sdl/main.c",
|
||||
}
|
||||
elseif _OPTIONS["targetos"]=="macosx" and _OPTIONS["SDL_LIBVER"]=="sdl" then
|
||||
elseif _OPTIONS["targetos"] == "macosx" and _OPTIONS["SDL_LIBVER"] == "sdl" then
|
||||
-- SDLMain_tmpl isn't necessary for SDL2
|
||||
files {
|
||||
MAME_DIR .. "src/osd/sdl/SDLMain_tmpl.m",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------
|
||||
-- aueffectutil
|
||||
--------------------------------------------------
|
||||
|
||||
if _OPTIONS["targetos"] == "macosx" and _OPTIONS["with-tools"] then
|
||||
project("aueffectutil")
|
||||
uuid ("3db8316d-fad7-4f5b-b46a-99373c91550e")
|
||||
kind "ConsoleApp"
|
||||
|
||||
options {
|
||||
"ForceCPP",
|
||||
}
|
||||
|
||||
dofile("sdl_cfg.lua")
|
||||
|
||||
targetdir(MAME_DIR)
|
||||
|
||||
linkoptions {
|
||||
"-sectcreate __TEXT __info_plist " .. MAME_DIR .. "src/osd/sdl/aueffectutil-Info.plist",
|
||||
}
|
||||
|
||||
dependency {
|
||||
{ "aueffectutil", MAME_DIR .. "src/osd/sdl/aueffectutil-Info.plist", true },
|
||||
}
|
||||
|
||||
links {
|
||||
"AudioUnit.framework",
|
||||
"AudioToolbox.framework",
|
||||
"CoreAudio.framework",
|
||||
"CoreAudioKit.framework",
|
||||
"CoreServices.framework",
|
||||
}
|
||||
|
||||
files {
|
||||
MAME_DIR .. "src/osd/sdl/aueffectutil.m",
|
||||
}
|
||||
end
|
||||
|
@ -24,14 +24,6 @@
|
||||
// workarounds for 10.6 warnings
|
||||
#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
|
||||
|
||||
typedef int NSInteger;
|
||||
typedef unsigned NSUInteger;
|
||||
typedef float CGFloat;
|
||||
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1050
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
|
||||
|
||||
@protocol NSWindowDelegate <NSObject>
|
||||
|
45
src/osd/sdl/aueffectutil-Info.plist
Normal file
45
src/osd/sdl/aueffectutil-Info.plist
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>AUEffectUtil</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>aueffect</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>AUEffect</string>
|
||||
<key>CFBundleTypeOSTypes</key>
|
||||
<array/>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>NSDocumentClass</key>
|
||||
<string>AUEffectDocument</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>aupreset</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>AudioUnit Preset</string>
|
||||
<key>CFBundleTypeOSTypes</key>
|
||||
<array/>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>NSDocumentClass</key>
|
||||
<string>AUEffectDocument</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.mamedev.aueffectutil</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>AUEffectUtil</string>
|
||||
</dict>
|
||||
</plist>
|
665
src/osd/sdl/aueffectutil.m
Normal file
665
src/osd/sdl/aueffectutil.m
Normal file
@ -0,0 +1,665 @@
|
||||
#import <AudioUnit/AudioUnit.h>
|
||||
#import <AudioUnit/AUCocoaUIView.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreAudio/CoreAudio.h>
|
||||
#import <CoreAudioKit/CoreAudioKit.h>
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
struct EffectInfo
|
||||
{
|
||||
Component component;
|
||||
OSType type;
|
||||
OSType subtype;
|
||||
OSType manufacturer;
|
||||
};
|
||||
|
||||
|
||||
static NSString *const AUEffectUtilErrorDomain = @"AUEffectUtilErrorDomain";
|
||||
|
||||
static NSString *const AUEffectDocumentType = @"AUEffect";
|
||||
static NSString *const AUPresetDocumentType = @"AudioUnit Preset";
|
||||
|
||||
static NSString *const ComponentTypeKey = @"ComponentType";
|
||||
static NSString *const ComponentSubTypeKey = @"ComponentSubType";
|
||||
static NSString *const ComponentManufacturerKey = @"ComponentManufacturer";
|
||||
static NSString *const ClassInfoKey = @"ClassInfo";
|
||||
|
||||
|
||||
@interface AUEffectDocument : NSDocument <NSWindowDelegate>
|
||||
{
|
||||
IBOutlet NSWindow *window;
|
||||
IBOutlet NSScrollView *scroller;
|
||||
|
||||
AudioComponentDescription description;
|
||||
AUGraph graph;
|
||||
AUNode outputNode, sourceNode, effectNode;
|
||||
AudioUnit outputUnit, sourceUnit, effectUnit;
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
|
||||
- (void)makeWindowControllers;
|
||||
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error;
|
||||
- (NSData *)dataOfType:(NSString *)type error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AUEffectDocument
|
||||
|
||||
- (void)loadEffectUI {
|
||||
if ((0 == effectNode) || (nil == window))
|
||||
return;
|
||||
|
||||
OSStatus status;
|
||||
UInt32 uiDescSize;
|
||||
AudioUnitCocoaViewInfo *viewInfo;
|
||||
NSView *view = nil;
|
||||
status = AudioUnitGetPropertyInfo(effectUnit,
|
||||
kAudioUnitProperty_CocoaUI,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&uiDescSize,
|
||||
NULL);
|
||||
UInt32 const uiClassCount = 1 + ((uiDescSize - sizeof(*viewInfo)) / sizeof(viewInfo->mCocoaAUViewClass[0]));
|
||||
if ((noErr == status) && (0 < uiClassCount))
|
||||
{
|
||||
viewInfo = (AudioUnitCocoaViewInfo *)malloc(uiDescSize);
|
||||
status = AudioUnitGetProperty(effectUnit,
|
||||
kAudioUnitProperty_CocoaUI,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
viewInfo,
|
||||
&uiDescSize);
|
||||
if (noErr == status)
|
||||
{
|
||||
NSBundle *const bundle = [NSBundle bundleWithPath:[(NSURL *)viewInfo->mCocoaAUViewBundleLocation path]];
|
||||
Class const viewClass = [bundle classNamed:(NSString *)viewInfo->mCocoaAUViewClass[0]];
|
||||
if ((NULL != viewClass)
|
||||
&& [viewClass conformsToProtocol:@protocol(AUCocoaUIBase)]
|
||||
&& [viewClass instancesRespondToSelector:@selector(uiViewForAudioUnit:withSize:)])
|
||||
{
|
||||
id const factory = [[viewClass alloc] init];
|
||||
view = [factory uiViewForAudioUnit:effectUnit
|
||||
withSize:[[scroller contentView] bounds].size];
|
||||
[factory release];
|
||||
}
|
||||
CFRelease(viewInfo->mCocoaAUViewBundleLocation);
|
||||
for (UInt32 i = 0; i < uiClassCount; i++)
|
||||
CFRelease(viewInfo->mCocoaAUViewClass[i]);
|
||||
}
|
||||
free(viewInfo);
|
||||
}
|
||||
if (nil == view)
|
||||
{
|
||||
view = [[[AUGenericView alloc] initWithAudioUnit:effectUnit] autorelease];
|
||||
[(AUGenericView *)view setShowsExpertParameters:YES];
|
||||
}
|
||||
|
||||
NSRect const frame = [view frame];
|
||||
NSSize const desired = [NSScrollView frameSizeForContentSize:frame.size
|
||||
hasHorizontalScroller:[scroller hasHorizontalScroller]
|
||||
hasVerticalScroller:[scroller hasVerticalScroller]
|
||||
borderType:[scroller borderType]];
|
||||
NSSize const min = [window contentMinSize];
|
||||
NSRect const current = [scroller frame];
|
||||
[window setContentSize:NSMakeSize(MAX(min.width, desired.width), MAX(min.height, desired.height))];
|
||||
[view setFrameSize:[scroller contentSize]];
|
||||
[scroller setDocumentView:view];
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
if (!(self = [super init])) return nil;
|
||||
|
||||
description.componentType = description.componentSubType = description.componentManufacturer = 0;
|
||||
description.componentFlags = description.componentFlagsMask = 0;
|
||||
graph = NULL;
|
||||
outputNode = sourceNode = effectNode = 0;
|
||||
|
||||
AudioComponentDescription const outputDesc = { kAudioUnitType_Output, kAudioUnitSubType_DefaultOutput, kAudioUnitManufacturer_Apple, 0, 0, };
|
||||
AudioComponentDescription const sourceDesc = { kAudioUnitType_Generator, kAudioUnitSubType_AudioFilePlayer, kAudioUnitManufacturer_Apple, 0, 0, };
|
||||
if ((noErr != NewAUGraph(&graph))
|
||||
|| (noErr != AUGraphAddNode(graph, &outputDesc, &outputNode))
|
||||
|| (noErr != AUGraphAddNode(graph, &sourceDesc, &sourceNode))
|
||||
|| (noErr != AUGraphOpen(graph))
|
||||
|| (noErr != AUGraphNodeInfo(graph, outputNode, NULL, &outputUnit))
|
||||
|| (noErr != AUGraphNodeInfo(graph, sourceNode, NULL, &sourceUnit))
|
||||
|| (noErr != AUGraphInitialize(graph)))
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (NULL != graph)
|
||||
{
|
||||
AUGraphClose(graph);
|
||||
DisposeAUGraph(graph);
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)makeWindowControllers {
|
||||
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 400, 300)
|
||||
styleMask:(NSTitledWindowMask |
|
||||
NSClosableWindowMask |
|
||||
NSMiniaturizableWindowMask |
|
||||
NSResizableWindowMask)
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:YES];
|
||||
[window setContentMinSize:NSMakeSize(400, 300)];
|
||||
[window setReleasedWhenClosed:NO];
|
||||
[window setDelegate:self];
|
||||
[window setTitle:@"Effect"];
|
||||
[self setWindow:window];
|
||||
|
||||
NSWindowController *const controller = [[NSWindowController alloc] initWithWindow:window];
|
||||
[self addWindowController:controller];
|
||||
[controller release];
|
||||
[window release];
|
||||
|
||||
scroller = [[NSScrollView alloc] initWithFrame:[[window contentView] bounds]];
|
||||
[scroller setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
|
||||
[scroller setHasHorizontalScroller:YES];
|
||||
[scroller setHasVerticalScroller:YES];
|
||||
[scroller setAutohidesScrollers:NO];
|
||||
[scroller setBorderType:NSNoBorder];
|
||||
[[window contentView] addSubview:scroller];
|
||||
[scroller release];
|
||||
|
||||
[self loadEffectUI];
|
||||
}
|
||||
|
||||
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)type error:(NSError **)error {
|
||||
OSStatus status;
|
||||
|
||||
BOOL const hasWrapper = [type isEqualToString:AUEffectDocumentType];
|
||||
if (!hasWrapper && ![type isEqualToString:AUPresetDocumentType])
|
||||
{
|
||||
if (NULL != error)
|
||||
{
|
||||
NSString *const message = [NSString stringWithFormat:@"Unsupported document type %@", type];
|
||||
NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey,
|
||||
nil];
|
||||
*error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *errDesc = nil;
|
||||
id const desc = [NSPropertyListSerialization propertyListFromData:data
|
||||
mutabilityOption:0
|
||||
format:NULL
|
||||
errorDescription:&errDesc];
|
||||
if ((nil == desc) || ![desc isKindOfClass:[NSDictionary class]] || (nil != errDesc))
|
||||
{
|
||||
if (NULL != error)
|
||||
{
|
||||
NSString *const message = [NSString stringWithFormat:@"Error in file format (%@)", errDesc];
|
||||
NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey,
|
||||
nil];
|
||||
*error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
|
||||
}
|
||||
if (nil != errDesc)
|
||||
[errDesc release];
|
||||
return NO;
|
||||
}
|
||||
|
||||
id const typeValue = [desc objectForKey:(hasWrapper ? ComponentTypeKey : @"type")];
|
||||
id const subtypeValue = [desc objectForKey:(hasWrapper ? ComponentSubTypeKey : @"subtype")];
|
||||
id const manufacturerValue = [desc objectForKey:(hasWrapper ? ComponentManufacturerKey : @"manufacturer")];
|
||||
if ((nil == typeValue) || ![typeValue isKindOfClass:[NSNumber class]]
|
||||
|| (nil == subtypeValue) || ![subtypeValue isKindOfClass:[NSNumber class]]
|
||||
|| (nil == manufacturerValue) || ![manufacturerValue isKindOfClass:[NSNumber class]]
|
||||
|| ([typeValue unsignedLongValue] != kAudioUnitType_Effect))
|
||||
{
|
||||
if (NULL != error)
|
||||
{
|
||||
NSString *const message = @"Error in effect description file format";
|
||||
NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey,
|
||||
nil];
|
||||
*error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (0 != effectNode)
|
||||
{
|
||||
[[scroller documentView] removeFromSuperview];
|
||||
AUGraphRemoveNode(graph, effectNode);
|
||||
effectNode = 0;
|
||||
}
|
||||
|
||||
description.componentType = [typeValue longValue];
|
||||
description.componentSubType = [subtypeValue longValue];
|
||||
description.componentManufacturer = [manufacturerValue longValue];
|
||||
status = noErr;
|
||||
status = AUGraphClearConnections(graph);
|
||||
if (noErr == status) status = AUGraphAddNode(graph, &description, &effectNode);
|
||||
if (noErr == status) status = AUGraphNodeInfo(graph, effectNode, NULL, &effectUnit);
|
||||
if (noErr == status) status = AUGraphConnectNodeInput(graph, sourceNode, 0, effectNode, 0);
|
||||
if (noErr == status) status = AUGraphConnectNodeInput(graph, effectNode, 0, outputNode, 0);
|
||||
if (noErr == status) status = AUGraphUpdate(graph, NULL);
|
||||
if (noErr != status)
|
||||
{
|
||||
if (NULL != error)
|
||||
{
|
||||
NSString * const message = @"Error encountered while configuring AudioUnit graph";
|
||||
NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
|
||||
NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey,
|
||||
underlying, NSUnderlyingErrorKey,
|
||||
nil];
|
||||
*error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
CFPropertyListRef const classInfo = (CFPropertyListRef)(hasWrapper ? [desc objectForKey:ClassInfoKey] : desc);
|
||||
if (NULL != classInfo)
|
||||
{
|
||||
AudioUnitParameter change = { effectUnit, kAUParameterListener_AnyParameter, 0, 0 };
|
||||
status = AudioUnitSetProperty(effectUnit,
|
||||
kAudioUnitProperty_ClassInfo,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&classInfo,
|
||||
sizeof(classInfo));
|
||||
if (noErr == status) status = AUParameterListenerNotify(NULL, NULL, &change);
|
||||
if (noErr != status)
|
||||
{
|
||||
if (NULL != error)
|
||||
{
|
||||
NSString * const message = @"Error configuring effect";
|
||||
NSError *const underlying = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
|
||||
NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:message, NSLocalizedDescriptionKey,
|
||||
underlying, NSUnderlyingErrorKey,
|
||||
nil];
|
||||
*error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
[self loadEffectUI];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSData *)dataOfType:(NSString *)type error:(NSError **)error {
|
||||
CFPropertyListRef classInfo;
|
||||
UInt32 infoSize = sizeof(classInfo);
|
||||
OSStatus const status = AudioUnitGetProperty(effectUnit,
|
||||
kAudioUnitProperty_ClassInfo,
|
||||
kAudioUnitScope_Global,
|
||||
0,
|
||||
&classInfo,
|
||||
&infoSize);
|
||||
if (noErr != status)
|
||||
{
|
||||
if (NULL != error)
|
||||
{
|
||||
NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:@"Error getting effect settings", NSLocalizedDescriptionKey,
|
||||
[NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil], NSUnderlyingErrorKey,
|
||||
nil];
|
||||
*error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
NSDictionary *const desc = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLong:description.componentType], ComponentTypeKey,
|
||||
[NSNumber numberWithUnsignedLong:description.componentSubType], ComponentSubTypeKey,
|
||||
[NSNumber numberWithUnsignedLong:description.componentManufacturer], ComponentManufacturerKey,
|
||||
classInfo, ClassInfoKey,
|
||||
nil];
|
||||
CFRelease(classInfo);
|
||||
NSString *errDesc = nil;
|
||||
NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc
|
||||
format:NSPropertyListXMLFormat_v1_0
|
||||
errorDescription:&errDesc];
|
||||
if ((nil == data) || (nil != errDesc))
|
||||
{
|
||||
if (NULL != error)
|
||||
{
|
||||
NSDictionary *const info = [NSDictionary dictionaryWithObjectsAndKeys:@"Error serialising effect settings", NSLocalizedDescriptionKey,
|
||||
nil];
|
||||
*error = [NSError errorWithDomain:AUEffectUtilErrorDomain code:0 userInfo:info];
|
||||
}
|
||||
if (nil != errDesc) [errDesc release];
|
||||
return nil;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface AUEffectUtilAppDelegate : NSObject
|
||||
{
|
||||
EffectInfo *effects;
|
||||
|
||||
IBOutlet NSMenu *newEffectMenu;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
- (void)dealloc;
|
||||
|
||||
- (IBAction)newEffect:(id)sender;
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification;
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification;
|
||||
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AUEffectUtilAppDelegate
|
||||
|
||||
- (void)appendApplicationMenu:(NSMenu *)parent {
|
||||
NSMenuItem *item;
|
||||
NSMenu *submenu;
|
||||
NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"];
|
||||
|
||||
NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Application"];
|
||||
item = [parent addItemWithTitle:@"Application" action:NULL keyEquivalent:@""];
|
||||
[parent setSubmenu:menu forItem:item];
|
||||
[menu release];
|
||||
[menu setValue:@"NSAppleMenu" forKey:@"name"];
|
||||
|
||||
item = [menu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
|
||||
[item setTarget:NSApp];
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
item = [menu addItemWithTitle:@"Services" action:NULL keyEquivalent:@""];
|
||||
submenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Services"];
|
||||
[menu setSubmenu:submenu forItem:item];
|
||||
[submenu release];
|
||||
[NSApp setServicesMenu:submenu];
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
item = [menu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] action:@selector(hide:) keyEquivalent:@"h"];
|
||||
item = [menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
|
||||
[item setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask];
|
||||
item = [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
item = [menu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
[item setTarget:NSApp];
|
||||
}
|
||||
|
||||
- (void)appendFileMenu:(NSMenu *)parent {
|
||||
NSMenuItem *item;
|
||||
|
||||
NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"File"];
|
||||
item = [parent addItemWithTitle:@"File" action:NULL keyEquivalent:@""];
|
||||
[parent setSubmenu:menu forItem:item];
|
||||
[menu release];
|
||||
|
||||
item = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""];
|
||||
newEffectMenu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"New"];
|
||||
[menu setSubmenu:newEffectMenu forItem:item];
|
||||
[newEffectMenu release];
|
||||
item = [menu addItemWithTitle:@"Open…" action:@selector(openDocument:) keyEquivalent:@"o"];
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
item = [menu addItemWithTitle:NSLocalizedString(@"Close", nil) action:@selector(performClose:) keyEquivalent:@"w"];
|
||||
item = [menu addItemWithTitle:NSLocalizedString(@"Save", nil) action:@selector(saveDocument:) keyEquivalent:@"s"];
|
||||
item = [menu addItemWithTitle:NSLocalizedString(@"Save As…", nil) action:@selector(saveDocumentAs:) keyEquivalent:@"S"];
|
||||
item = [menu addItemWithTitle:NSLocalizedString(@"Revert to Saved", nil) action:@selector(revertDocumentToSaved:) keyEquivalent:@""];
|
||||
}
|
||||
|
||||
- (void)appendEditMenu:(NSMenu *)parent {
|
||||
NSMenuItem *item;
|
||||
|
||||
NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Edit"];
|
||||
item = [parent addItemWithTitle:@"Edit" action:NULL keyEquivalent:@""];
|
||||
[parent setSubmenu:menu forItem:item];
|
||||
[menu release];
|
||||
|
||||
item = [menu addItemWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@"z"];
|
||||
item = [menu addItemWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@"Z"];
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
item = [menu addItemWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"];
|
||||
item = [menu addItemWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"];
|
||||
item = [menu addItemWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"];
|
||||
item = [menu addItemWithTitle:@"Delete" action:@selector(delete:) keyEquivalent:@""];
|
||||
item = [menu addItemWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"];
|
||||
}
|
||||
|
||||
- (void)appendWindowMenu:(NSMenu *)parent {
|
||||
NSMenuItem *item;
|
||||
|
||||
NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Window"];
|
||||
item = [parent addItemWithTitle:@"Window" action:NULL keyEquivalent:@""];
|
||||
[parent setSubmenu:menu forItem:item];
|
||||
[menu release];
|
||||
[NSApp setWindowsMenu:menu];
|
||||
|
||||
item = [menu addItemWithTitle:@"Minimize" action:@selector(performMinimize:) keyEquivalent:@"m"];
|
||||
item = [menu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
|
||||
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
item = [menu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""];
|
||||
}
|
||||
|
||||
- (void)appendHelpMenu:(NSMenu *)parent {
|
||||
NSMenuItem *item;
|
||||
NSString *const appName = [(NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()) objectForKey:@"CFBundleName"];
|
||||
|
||||
NSMenu *const menu = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"Help"];
|
||||
item = [parent addItemWithTitle:@"Help" action:NULL keyEquivalent:@""];
|
||||
[parent setSubmenu:menu forItem:item];
|
||||
[menu release];
|
||||
[NSApp setHelpMenu:menu];
|
||||
|
||||
item = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ Help", appName] action:@selector(showHelp:) keyEquivalent:@"?"];
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
if (!(self = [super init])) return nil;
|
||||
effects = NULL;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (effects) free(effects);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (IBAction)newEffect:(id)sender {
|
||||
int const index = [sender tag];
|
||||
if ((0 > index) || (0 == effects[index].component))
|
||||
{
|
||||
NSAlert *const alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert setMessageText:@"Invalid effect component"];
|
||||
[alert addButtonWithTitle:@"OK"];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
return;
|
||||
}
|
||||
|
||||
NSNumber *const typeValue = [NSNumber numberWithUnsignedLong:effects[index].type];
|
||||
NSNumber *const subtypeValue = [NSNumber numberWithUnsignedLong:effects[index].subtype];
|
||||
NSNumber *const manufacturerValue = [NSNumber numberWithUnsignedLong:effects[index].manufacturer];
|
||||
NSDictionary *const desc = [NSDictionary dictionaryWithObjectsAndKeys:typeValue, ComponentTypeKey,
|
||||
subtypeValue, ComponentSubTypeKey,
|
||||
manufacturerValue, ComponentManufacturerKey,
|
||||
nil];
|
||||
NSString *errDesc = nil;
|
||||
NSData *const data = [NSPropertyListSerialization dataFromPropertyList:desc
|
||||
format:NSPropertyListXMLFormat_v1_0
|
||||
errorDescription:&errDesc];
|
||||
if ((nil == data) || (nil != errDesc))
|
||||
{
|
||||
NSAlert *const alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert setMessageText:@"Error serialising properties for new effect"];
|
||||
if (nil != errDesc) [alert setInformativeText:[errDesc autorelease]];
|
||||
[alert addButtonWithTitle:@"OK"];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *err = nil;
|
||||
AUEffectDocument *const document = [[AUEffectDocument alloc] init];
|
||||
if ((nil == document) || ![document readFromData:data ofType:AUEffectDocumentType error:&err])
|
||||
{
|
||||
[document release];
|
||||
if (nil != err)
|
||||
{
|
||||
[[NSAlert alertWithError:err] runModal];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAlert *const alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert setMessageText:@"Error creating new effect document"];
|
||||
[alert addButtonWithTitle:@"OK"];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
[document makeWindowControllers];
|
||||
[document showWindows];
|
||||
[[NSDocumentController sharedDocumentController] addDocument:document];
|
||||
[document release];
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
|
||||
NSMenu *const menubar = [[NSMenu allocWithZone:[NSMenu zone]] initWithTitle:@"MainMenu"];
|
||||
[NSApp setMainMenu:menubar];
|
||||
[menubar release];
|
||||
[self appendApplicationMenu:menubar];
|
||||
[self appendFileMenu:menubar];
|
||||
[self appendEditMenu:menubar];
|
||||
[self appendWindowMenu:menubar];
|
||||
[self appendHelpMenu:menubar];
|
||||
|
||||
ProcessSerialNumber const serial = { 0, kCurrentProcess };
|
||||
OSStatus const status = TransformProcessType(&serial, kProcessTransformToForegroundApplication);
|
||||
if (noErr != status)
|
||||
{
|
||||
NSLog(@"Error transforming to foreground application (%ld)", (long)status);
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
ComponentDescription effectFilter = { kAudioUnitType_Effect, 0, 0, 0, 0 };
|
||||
long const count = CountComponents(&effectFilter);
|
||||
if (0 == count)
|
||||
{
|
||||
NSAlert *const alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert setMessageText:@"No AudioUnit effects found"];
|
||||
[alert addButtonWithTitle:@"OK"];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
}
|
||||
|
||||
std::vector<std::pair<Component, OSStatus> > failed;
|
||||
effects = (EffectInfo *)malloc(count * sizeof(*effects));
|
||||
Component effect = FindNextComponent(0, &effectFilter);
|
||||
for (long i = 0; (i < count) && (effect != 0); i++, effect = FindNextComponent(effect, &effectFilter))
|
||||
{
|
||||
ComponentDescription effectDesc;
|
||||
Handle const nameHandle = NewHandle(4);
|
||||
OSStatus const err = GetComponentInfo(effect, &effectDesc, nameHandle, NULL, NULL);
|
||||
if (noErr == err)
|
||||
{
|
||||
effects[i].component = effect;
|
||||
effects[i].type = effectDesc.componentType;
|
||||
effects[i].subtype = effectDesc.componentSubType;
|
||||
effects[i].manufacturer = effectDesc.componentManufacturer;
|
||||
HLock(nameHandle);
|
||||
CFStringRef name = CFStringCreateWithPascalString(NULL,
|
||||
(unsigned char const *)*nameHandle,
|
||||
kCFStringEncodingMacRoman);
|
||||
HUnlock(nameHandle);
|
||||
NSMenuItem *const item = [newEffectMenu addItemWithTitle:(NSString *)name
|
||||
action:@selector(newEffect:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:i];
|
||||
[item setTarget:self];
|
||||
CFRelease(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
effects[i].component = 0;
|
||||
failed.push_back(std::make_pair(effect, err));
|
||||
}
|
||||
DisposeHandle(nameHandle);
|
||||
}
|
||||
|
||||
if (!failed.empty())
|
||||
{
|
||||
NSString *const message = [NSString stringWithFormat:@"Failed to get info for %lu effect%s",
|
||||
(unsigned long)failed.size(),
|
||||
((1U == failed.size()) ? "" : "s")];
|
||||
NSMutableString *const detail = [NSMutableString stringWithCapacity:(16 * failed.size())];
|
||||
std::vector<std::pair<Component, OSStatus> >::const_iterator it = failed.begin();
|
||||
[detail appendFormat:@"%lu (%ld)", (unsigned long)it->first, (long)it->second];
|
||||
++it;
|
||||
while (failed.end() != it)
|
||||
{
|
||||
[detail appendFormat:@", %lu (%ld)", (unsigned long)it->first, (long)it->second];
|
||||
++it;
|
||||
}
|
||||
NSAlert *const alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSWarningAlertStyle];
|
||||
[alert setMessageText:message];
|
||||
[alert setInformativeText:[NSString stringWithString:detail]];
|
||||
[alert addButtonWithTitle:@"OK"];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
// Initialise NSApplication
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
[NSApplication sharedApplication];
|
||||
AUEffectUtilAppDelegate *const delegate = [[AUEffectUtilAppDelegate alloc] init];
|
||||
[NSApp setDelegate:delegate];
|
||||
[pool release];
|
||||
|
||||
// Let's go!
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
[NSApp run];
|
||||
[delegate release];
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user