From dbc0698cee64ae222a90726714b9c52016df6898 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Mon, 17 Jan 2022 06:37:38 -0800 Subject: [PATCH] Equalizer: Implemented stock presets --- Application/PlaybackController.m | 1 + Cog.xcodeproj/project.pbxproj | 18 +++ Winamp.q1.json | 257 +++++++++++++++++++++++++++++++ Window/AUPlayerView.h | 7 +- Window/AUPlayerView.m | 231 ++++++++++++++++++++++++++- 5 files changed, 509 insertions(+), 5 deletions(-) create mode 100644 Winamp.q1.json diff --git a/Application/PlaybackController.m b/Application/PlaybackController.m index 63d02cc96..1675a6bdf 100644 --- a/Application/PlaybackController.m +++ b/Application/PlaybackController.m @@ -61,6 +61,7 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation"; NSDictionary *defaultsDictionary = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithDouble:100.0], @"volume", [NSNumber numberWithBool:NO], @"GraphicEQenable", + [NSNumber numberWithInt:-1], @"GraphicEQpreset", nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary]; diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index fe550777d..cf3b6f6c0 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -118,6 +118,8 @@ 8355D6B6180612F300D05687 /* NSData+MD5.m in Sources */ = {isa = PBXBuildFile; fileRef = 8355D6B5180612F300D05687 /* NSData+MD5.m */; }; 8355D6B8180613FB00D05687 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8355D6B7180613FB00D05687 /* Security.framework */; }; 8359009D17FF06570060F3ED /* ArchiveSource.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8359FF3117FEF35D0060F3ED /* ArchiveSource.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 835A8FD327957310005B3C39 /* json.c in Sources */ = {isa = PBXBuildFile; fileRef = 835A8FC627957310005B3C39 /* json.c */; }; + 835A8FD6279575B1005B3C39 /* Winamp.q1.json in Resources */ = {isa = PBXBuildFile; fileRef = 835A8FD5279575B1005B3C39 /* Winamp.q1.json */; }; 8360EF6D17F92E56005208A4 /* HighlyComplete.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8360EF0517F92B24005208A4 /* HighlyComplete.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 836D28A818086386005B7299 /* MiniModeMenuTitleTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 836D28A718086386005B7299 /* MiniModeMenuTitleTransformer.m */; }; 836F5BF91A357A01002730CC /* sidplay.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8314D6411A354DFF00EEE8E6 /* sidplay.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -928,6 +930,9 @@ 8355D6B5180612F300D05687 /* NSData+MD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+MD5.m"; sourceTree = ""; }; 8355D6B7180613FB00D05687 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 8359FF2C17FEF35C0060F3ED /* ArchiveSource.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ArchiveSource.xcodeproj; path = Plugins/ArchiveSource/ArchiveSource.xcodeproj; sourceTree = ""; }; + 835A8FC627957310005B3C39 /* json.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = json.c; sourceTree = ""; }; + 835A8FC827957310005B3C39 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = ""; }; + 835A8FD5279575B1005B3C39 /* Winamp.q1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Winamp.q1.json; sourceTree = ""; }; 835C888B22CC1881001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = en; path = en.lproj/Credits.html; sourceTree = ""; }; 835C888C22CC1882001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 835C888D22CC1882001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; @@ -1149,6 +1154,7 @@ 177EBF770B8BC2A70000BC8C /* ThirdParty */ = { isa = PBXGroup; children = ( + 835A8FC527957310005B3C39 /* json */, 177EBF850B8BC2A70000BC8C /* ImageTextCell */, 179790DD0C087AB7001D6996 /* OpenURLPanel */, ); @@ -1477,6 +1483,7 @@ 8D1107310486CEB800E47090 /* Info.plist */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 8E7575D909F31E930080F1EE /* Localizable.strings */, + 835A8FD5279575B1005B3C39 /* Winamp.q1.json */, 1791005C0CB44D6D0070BC5C /* Cog.scriptSuite */, 1791005D0CB44D6D0070BC5C /* Cog.scriptTerminology */, 17D1B0D00F6320EA00694C57 /* InfoInspector.xib */, @@ -1656,6 +1663,15 @@ name = Products; sourceTree = ""; }; + 835A8FC527957310005B3C39 /* json */ = { + isa = PBXGroup; + children = ( + 835A8FC627957310005B3C39 /* json.c */, + 835A8FC827957310005B3C39 /* json.h */, + ); + path = json; + sourceTree = ""; + }; 8360EF0117F92B23005208A4 /* Products */ = { isa = PBXGroup; children = ( @@ -2333,6 +2349,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 835A8FD6279575B1005B3C39 /* Winamp.q1.json in Resources */, 83BC5AC420E4CE9000631CD4 /* Feedback.xib in Resources */, 83BC5AC320E4CE8D00631CD4 /* SpotlightPanel.xib in Resources */, 83BC5AC220E4CE8A00631CD4 /* FileTree.xib in Resources */, @@ -2484,6 +2501,7 @@ 1784560F0F631E24007E8021 /* FileTreeViewController.m in Sources */, 178456120F631E31007E8021 /* SideViewController.m in Sources */, 17D1B1010F63255200694C57 /* InfoWindowController.m in Sources */, + 835A8FD327957310005B3C39 /* json.c in Sources */, 17D1B1680F632ABB00694C57 /* BlankZeroFormatter.m in Sources */, 17D1B1690F632ABB00694C57 /* IndexFormatter.m in Sources */, 17D1B16A0F632ABB00694C57 /* SecondsFormatter.m in Sources */, diff --git a/Winamp.q1.json b/Winamp.q1.json new file mode 100644 index 000000000..b94757fd4 --- /dev/null +++ b/Winamp.q1.json @@ -0,0 +1,257 @@ +{ + "type" : "Winamp EQ library file v1.1" + ,"presets" : [ + { + "name" : "Classical" + ,"hz70" : 33 + ,"hz180" : 33 + ,"hz320" : 33 + ,"hz600" : 33 + ,"hz1000" : 33 + ,"hz3000" : 33 + ,"hz6000" : 20 + ,"hz12000" : 20 + ,"hz14000" : 20 + ,"hz16000" : 16 + ,"preamp" : 33 + } + ,{ + "name" : "Club" + ,"hz70" : 33 + ,"hz180" : 33 + ,"hz320" : 38 + ,"hz600" : 42 + ,"hz1000" : 42 + ,"hz3000" : 42 + ,"hz6000" : 38 + ,"hz12000" : 33 + ,"hz14000" : 33 + ,"hz16000" : 33 + ,"preamp" : 33 + } + ,{ + "name" : "Dance" + ,"hz70" : 48 + ,"hz180" : 44 + ,"hz320" : 36 + ,"hz600" : 32 + ,"hz1000" : 32 + ,"hz3000" : 22 + ,"hz6000" : 20 + ,"hz12000" : 20 + ,"hz14000" : 32 + ,"hz16000" : 32 + ,"preamp" : 33 + } + ,{ + "name" : "Flat" + ,"hz70" : 33 + ,"hz180" : 33 + ,"hz320" : 33 + ,"hz600" : 33 + ,"hz1000" : 33 + ,"hz3000" : 33 + ,"hz6000" : 33 + ,"hz12000" : 33 + ,"hz14000" : 33 + ,"hz16000" : 33 + ,"preamp" : 33 + } + ,{ + "name" : "Laptop speakers/headphones" + ,"hz70" : 40 + ,"hz180" : 50 + ,"hz320" : 41 + ,"hz600" : 26 + ,"hz1000" : 28 + ,"hz3000" : 35 + ,"hz6000" : 40 + ,"hz12000" : 48 + ,"hz14000" : 53 + ,"hz16000" : 56 + ,"preamp" : 33 + } + ,{ + "name" : "Large hall" + ,"hz70" : 49 + ,"hz180" : 49 + ,"hz320" : 42 + ,"hz600" : 42 + ,"hz1000" : 33 + ,"hz3000" : 24 + ,"hz6000" : 24 + ,"hz12000" : 24 + ,"hz14000" : 33 + ,"hz16000" : 33 + ,"preamp" : 33 + } + ,{ + "name" : "Party" + ,"hz70" : 44 + ,"hz180" : 44 + ,"hz320" : 33 + ,"hz600" : 33 + ,"hz1000" : 33 + ,"hz3000" : 33 + ,"hz6000" : 33 + ,"hz12000" : 33 + ,"hz14000" : 44 + ,"hz16000" : 44 + ,"preamp" : 33 + } + ,{ + "name" : "Pop" + ,"hz70" : 29 + ,"hz180" : 40 + ,"hz320" : 44 + ,"hz600" : 45 + ,"hz1000" : 41 + ,"hz3000" : 30 + ,"hz6000" : 28 + ,"hz12000" : 28 + ,"hz14000" : 29 + ,"hz16000" : 29 + ,"preamp" : 33 + } + ,{ + "name" : "Reggae" + ,"hz70" : 33 + ,"hz180" : 33 + ,"hz320" : 31 + ,"hz600" : 22 + ,"hz1000" : 33 + ,"hz3000" : 43 + ,"hz6000" : 43 + ,"hz12000" : 33 + ,"hz14000" : 33 + ,"hz16000" : 33 + ,"preamp" : 33 + } + ,{ + "name" : "Rock" + ,"hz70" : 45 + ,"hz180" : 40 + ,"hz320" : 23 + ,"hz600" : 19 + ,"hz1000" : 26 + ,"hz3000" : 39 + ,"hz6000" : 47 + ,"hz12000" : 50 + ,"hz14000" : 50 + ,"hz16000" : 50 + ,"preamp" : 33 + } + ,{ + "name" : "Soft" + ,"hz70" : 40 + ,"hz180" : 35 + ,"hz320" : 30 + ,"hz600" : 28 + ,"hz1000" : 30 + ,"hz3000" : 39 + ,"hz6000" : 46 + ,"hz12000" : 48 + ,"hz14000" : 50 + ,"hz16000" : 52 + ,"preamp" : 33 + } + ,{ + "name" : "Ska" + ,"hz70" : 28 + ,"hz180" : 24 + ,"hz320" : 25 + ,"hz600" : 31 + ,"hz1000" : 39 + ,"hz3000" : 42 + ,"hz6000" : 47 + ,"hz12000" : 48 + ,"hz14000" : 50 + ,"hz16000" : 48 + ,"preamp" : 33 + } + ,{ + "name" : "Full Bass" + ,"hz70" : 48 + ,"hz180" : 48 + ,"hz320" : 48 + ,"hz600" : 42 + ,"hz1000" : 35 + ,"hz3000" : 25 + ,"hz6000" : 18 + ,"hz12000" : 15 + ,"hz14000" : 14 + ,"hz16000" : 14 + ,"preamp" : 33 + } + ,{ + "name" : "Soft Rock" + ,"hz70" : 39 + ,"hz180" : 39 + ,"hz320" : 36 + ,"hz600" : 31 + ,"hz1000" : 25 + ,"hz3000" : 23 + ,"hz6000" : 26 + ,"hz12000" : 31 + ,"hz14000" : 37 + ,"hz16000" : 47 + ,"preamp" : 33 + } + ,{ + "name" : "Full Treble" + ,"hz70" : 16 + ,"hz180" : 16 + ,"hz320" : 16 + ,"hz600" : 25 + ,"hz1000" : 37 + ,"hz3000" : 50 + ,"hz6000" : 58 + ,"hz12000" : 58 + ,"hz14000" : 58 + ,"hz16000" : 60 + ,"preamp" : 33 + } + ,{ + "name" : "Full Bass & Treble" + ,"hz70" : 44 + ,"hz180" : 42 + ,"hz320" : 33 + ,"hz600" : 20 + ,"hz1000" : 24 + ,"hz3000" : 35 + ,"hz6000" : 46 + ,"hz12000" : 50 + ,"hz14000" : 52 + ,"hz16000" : 52 + ,"preamp" : 33 + } + ,{ + "name" : "Live" + ,"hz70" : 24 + ,"hz180" : 33 + ,"hz320" : 39 + ,"hz600" : 41 + ,"hz1000" : 42 + ,"hz3000" : 42 + ,"hz6000" : 39 + ,"hz12000" : 37 + ,"hz14000" : 37 + ,"hz16000" : 36 + ,"preamp" : 33 + } + ,{ + "name" : "Techno" + ,"hz70" : 45 + ,"hz180" : 42 + ,"hz320" : 33 + ,"hz600" : 23 + ,"hz1000" : 24 + ,"hz3000" : 33 + ,"hz6000" : 45 + ,"hz12000" : 48 + ,"hz14000" : 48 + ,"hz16000" : 47 + ,"preamp" : 33 + } + ] +} diff --git a/Window/AUPlayerView.h b/Window/AUPlayerView.h index 078e2c50f..2c711c3aa 100644 --- a/Window/AUPlayerView.h +++ b/Window/AUPlayerView.h @@ -12,6 +12,7 @@ #import #import #import +#import @interface AUPluginUI : NSObject { @@ -36,12 +37,16 @@ @end @interface AUPluginWindow : NSWindow { + AudioUnit au; + AUParameterListenerRef listenerRef; + NSView *topView; NSView *auView; NSSplitView *splitView; + NSPopUpButton * presetButton; } -- (id) initWithAuView:(NSView *)_auView bringToFront:(BOOL)front relativeToWindow:(NSInteger)window; +- (id) initWithAuView:(NSView *)_auView withAu:(AudioUnit)au bringToFront:(BOOL)front relativeToWindow:(NSInteger)window; @end #endif diff --git a/Window/AUPlayerView.m b/Window/AUPlayerView.m index ec0714484..a2c7b78ea 100644 --- a/Window/AUPlayerView.m +++ b/Window/AUPlayerView.m @@ -12,6 +12,127 @@ #import "AUPlayerView.h" +#import "json.h" +static NSArray * equalizer_presets_processed = nil; +static json_value * equalizer_presets = NULL; + +static const float winamp_equalizer_bands[10] = { 70, 180, 320, 600, 1000, 3000, 6000, 12000, 14000, 16000 }; +static const NSString* winamp_equalizer_items[] = { @"name", @"hz70", @"hz180", @"hz320", @"hz600", @"hz1000", @"hz3000", @"hz6000", @"hz12000", @"hz14000", @"hz16000", @"preamp" }; + +static const float apple_equalizer_bands_31[31] = { 20, 25, 31.5, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800, 1000, 1200, 1600, 2000, 2500, 3100, 4000, 5000, 6300, 8000, 10000, 12000, 16000, 20000 }; +static const float apple_equalizer_bands_10[10] = { 32, 64, 128, 256, 512, 1000, 2000, 4000, 8000, 16000 }; + +static inline float interpolatePoint(NSDictionary * preset, float freqTarget) { + if (freqTarget <= winamp_equalizer_bands[0]) { + return [[preset objectForKey:winamp_equalizer_items[1]] floatValue]; + } + else if (freqTarget >= winamp_equalizer_bands[9]) { + return [[preset objectForKey:winamp_equalizer_items[10]] floatValue]; + } + + // interpolation time! + + for (size_t i = 0; i < 9; ++i) { + if (freqTarget >= winamp_equalizer_bands[i] && + freqTarget < winamp_equalizer_bands[i + 1]) { + float freqLow = winamp_equalizer_bands[i]; + float freqHigh = winamp_equalizer_bands[i + 1]; + float valueLow = [[preset objectForKey:winamp_equalizer_items[i + 1]] floatValue]; + float valueHigh = [[preset objectForKey:winamp_equalizer_items[i + 2]] floatValue]; + + float delta = (freqTarget - freqLow) / (freqHigh - freqLow); + + return valueLow + (valueHigh - valueLow) * delta; + } + } + + return 0.0; +} + +static void interpolateBandsTo10(float * out, NSDictionary * preset) { + for (size_t i = 0; i < 10; ++i) { + out[i] = interpolatePoint(preset, apple_equalizer_bands_10[i]); + } +} + +static void interpolateBandsTo31(float * out, NSDictionary * preset) { + for (size_t i = 0; i < 31; ++i) { + out[i] = interpolatePoint(preset, apple_equalizer_bands_31[i]); + } +} + +static void loadPresets() +{ + if ([equalizer_presets_processed count]) return; + + CFURLRef appUrlRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("Winamp.q1"), CFSTR("json"), NULL); + + CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle); + + NSFileHandle * fileHandle = [NSFileHandle fileHandleForReadingAtPath:(__bridge NSString *)macPath]; + if (fileHandle) { + NSError *err; + NSData *data; + if (@available(macOS 10.15, *)) { + data = [fileHandle readDataToEndOfFileAndReturnError:&err]; + } + else { + data = [fileHandle readDataToEndOfFile]; + err = nil; + } + if (!err && data) { + equalizer_presets = json_parse(data.bytes, data.length); + + if (equalizer_presets->type == json_object && + equalizer_presets->u.object.length == 2 && + strncmp(equalizer_presets->u.object.values[0].name, "type", equalizer_presets->u.object.values[0].name_length) == 0 && + equalizer_presets->u.object.values[0].value->type == json_string && + strncmp(equalizer_presets->u.object.values[0].value->u.string.ptr, "Winamp EQ library file v1.1", equalizer_presets->u.object.values[0].value->u.string.length ) == 0 && + strncmp(equalizer_presets->u.object.values[1].name, "presets", equalizer_presets->u.object.values[1].name_length) == 0 && + equalizer_presets->u.object.values[1].value->type == json_array) + { + // Got the array of presets + NSMutableArray * array = [[NSMutableArray alloc] init]; + + size_t count = equalizer_presets->u.object.values[1].value->u.array.length; + json_value ** values = equalizer_presets->u.object.values[1].value->u.array.values; + + for (size_t i = 0; i < count; ++i) { + if (values[i]->type == json_object) { + size_t object_items = values[i]->u.object.length; + json_object_entry * object_entry = values[i]->u.object.values; + if (object_items == (sizeof(winamp_equalizer_items)/sizeof(winamp_equalizer_items[0]))) { + NSMutableDictionary * equalizerItem = [[NSMutableDictionary alloc] init]; + for (size_t j = 0; j < object_items; ++j) { + if (strncmp(object_entry[j].name, [winamp_equalizer_items[j] UTF8String], object_entry[j].name_length) == 0) { + if (j == 0 && object_entry[j].value->type == json_string) { + NSString * name = [NSString stringWithUTF8String:object_entry[j].value->u.string.ptr]; + [equalizerItem setObject:name forKey:winamp_equalizer_items[j]]; + } + else if (object_entry[j].value->type == json_integer) { + int64_t value = object_entry[j].value->u.integer; + float floatValue = ((value <= 64 && value >= 1) ? ((float)(value - 33) / 32.0 * 12.0) : 0.0); + [equalizerItem setObject:[NSNumber numberWithFloat:floatValue] forKey:winamp_equalizer_items[j]]; + } + } + } + [array addObject:[NSDictionary dictionaryWithDictionary:equalizerItem]]; + } + } + } + + equalizer_presets_processed = [NSArray arrayWithArray:array]; + } + } + [fileHandle closeFile]; + + json_value_free(equalizer_presets); + equalizer_presets = NULL; + } + CFRelease(macPath); + CFRelease(appUrlRef); +} + @interface AUPluginUI (Private) - (BOOL)test_cocoa_view_support; - (int)create_cocoa_view; @@ -38,7 +159,7 @@ if (au_view) { - cocoa_window = [[AUPluginWindow alloc] initWithAuView:au_view bringToFront:front relativeToWindow:window]; + cocoa_window = [[AUPluginWindow alloc] initWithAuView:au_view withAu:au bringToFront:front relativeToWindow:window]; if (cocoa_window) { windowOpen = YES; @@ -75,7 +196,7 @@ - (void)windowClosed:(NSNotification*)notification { - [cocoa_window saveFrameUsingName:@"GraphicEQ.position"]; + [cocoa_window saveFrameUsingName:@"GraphicEQposition"]; [[NSNotificationCenter defaultCenter] removeObserver:self]; windowOpen = NO; } @@ -196,7 +317,7 @@ @end @implementation AUPluginWindow -- (id) initWithAuView:(NSView *)_auView bringToFront:(BOOL)front relativeToWindow:(NSInteger)window +- (id) initWithAuView:(NSView *)_auView withAu:(AudioUnit)au bringToFront:(BOOL)front relativeToWindow:(NSInteger)window { NSRect frame = [_auView frame]; CGFloat req_width = frame.size.width; @@ -210,6 +331,7 @@ defer:NO]; if (self) { + self->au = au; auView = _auView; [self setAutodisplay:YES]; @@ -253,16 +375,72 @@ [topView addSubview:button]; + loadPresets(); + + NSRect popupFrame = NSMakeRect(req_width - 320, 0, 308, 26); + + presetButton = [[NSPopUpButton alloc] initWithFrame:popupFrame]; + [topView addSubview:presetButton]; + [presetButton setAction:@selector(changePreset:)]; + [presetButton setTarget:self]; + + NSMutableArray * array = [[NSMutableArray alloc] init]; + for (NSDictionary * preset in equalizer_presets_processed) + { + [array addObject:[preset objectForKey:@"name"]]; + } + [array addObject:@"Custom"]; + [presetButton addItemsWithTitles:array]; + + NSInteger presetSelected = [[NSUserDefaults standardUserDefaults] integerForKey:@"GraphicEQpreset"]; + if (presetSelected < 0 || presetSelected >= [equalizer_presets_processed count]) + presetSelected = [equalizer_presets_processed count]; + + [presetButton selectItemAtIndex:presetSelected]; + + NSTextField * presetLabel = [NSTextField labelWithString:@"Preset:"]; + + NSRect labelFrame = [presetLabel frame]; + labelFrame.origin = NSMakePoint(popupFrame.origin.x - labelFrame.size.width - 2, 6); + [presetLabel setFrame:labelFrame]; + [topView addSubview:presetLabel]; + [splitView adjustSubviews]; [splitView setDelegate:self]; - [self setFrameUsingName:@"GraphicEQ.position"]; + [self setFrameUsingName:@"GraphicEQposition"]; + + AUListenerCreateWithDispatchQueue(&listenerRef, 0.25, dispatch_get_main_queue(), ^void(void *inObject, const AudioUnitParameter *inParameter, AudioUnitParameterValue inValue) { + AUPluginWindow * _self = (__bridge AUPluginWindow *) inObject; + + if (inParameter->mParameterID >= 0 && inParameter->mParameterID <= 31) { + [_self->presetButton selectItemAtIndex:[equalizer_presets_processed count]]; + } + }); + + AudioUnitParameter param; + + param.mAudioUnit = au; + param.mElement = 0; + param.mScope = kAudioUnitScope_Global; + + for (unsigned int i = 0; i < 31; ++i) { + param.mParameterID = i; + AUListenerAddParameter(listenerRef, (__bridge void *)self, ¶m); + } } return self; } +- (void) dealloc +{ + if (listenerRef) { + AUListenerDispose(listenerRef); + } +} + - (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect ofDividerAtIndex:(NSInteger)dividerIndex { return NSZeroRect; @@ -274,5 +452,50 @@ [[NSUserDefaults standardUserDefaults] setBool:enabled forKey:@"GraphicEQenable"]; } + +- (void) changePreset:(id)sender +{ + AudioUnitParameterValue paramValue = 0; + if (AudioUnitGetParameter(au, kGraphicEQParam_NumberOfBands, kAudioUnitScope_Global, 0, ¶mValue)) + return; + + NSInteger index = [sender indexOfSelectedItem]; + + size_t numberOfBands = paramValue ? 31 : 10; + + if (index < [equalizer_presets_processed count]) + { + NSDictionary * preset = [equalizer_presets_processed objectAtIndex:index]; + + if (numberOfBands == 31) { + float presetValues[31]; + interpolateBandsTo31(presetValues, preset); + + for (unsigned int i = 0; i < 31; ++i) + { + AudioUnitSetParameter(au, i, kAudioUnitScope_Global, 0, presetValues[i], 0); + } + } + else if (numberOfBands == 10) { + float presetValues[10]; + interpolateBandsTo10(presetValues, preset); + + for (unsigned int i = 0; i < 10; ++i) + { + AudioUnitSetParameter(au, i, kAudioUnitScope_Global, 0, presetValues[i], 0); + } + } + + NSEvent * event = [NSEvent mouseEventWithType:NSEventTypeLeftMouseDown + location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 windowNumber:[self windowNumber] context:nil eventNumber:0 clickCount:1 pressure:1.0]; + + [auView mouseDown:event]; + + [[NSUserDefaults standardUserDefaults] setInteger:index forKey:@"GraphicEQpreset"]; + } + else + [[NSUserDefaults standardUserDefaults] setInteger:-1 forKey:@"GraphicEQpreset"]; +} + @end