From 4035ca861fe3af7ce61d25affef723df9d523045 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 22 May 2022 15:26:27 -0700 Subject: [PATCH] Spectrum Visualizer: Add customization options Add options to the Appearance preferences page to allow changing the spectrum's projection between a 2D-like one and 3D perspective, and add options to change the bar and peak dot colors. Signed-off-by: Christopher Snowhill --- Application/AppController.m | 17 +++++ Cog.xcodeproj/project.pbxproj | 6 ++ .../Preferences/Base.lproj/Preferences.xib | 65 +++++++++++++++++-- .../Preferences/ColorToValueTransformer.h | 16 +++++ .../Preferences/ColorToValueTransformer.m | 60 +++++++++++++++++ .../Preferences/GeneralPreferencesPlugin.m | 5 ++ .../Preferences.xcodeproj/project.pbxproj | 6 ++ Visualization/SpectrumView.m | 52 +++++++++++++++ 8 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 Preferences/Preferences/ColorToValueTransformer.h create mode 100644 Preferences/Preferences/ColorToValueTransformer.m diff --git a/Application/AppController.m b/Application/AppController.m index 494432b13..bd6d64900 100644 --- a/Application/AppController.m +++ b/Application/AppController.m @@ -19,6 +19,8 @@ #import "Logging.h" #import "MiniModeMenuTitleTransformer.h" +#import "ColorToValueTransformer.h" + #import "Shortcuts.h" #import @@ -47,6 +49,10 @@ void *kAppControllerContext = &kAppControllerContext; NSValueTransformer *miniModeMenuTitleTransformer = [[MiniModeMenuTitleTransformer alloc] init]; [NSValueTransformer setValueTransformer:miniModeMenuTitleTransformer forName:@"MiniModeMenuTitleTransformer"]; + + NSValueTransformer *colorToValueTransformer = [[ColorToValueTransformer alloc] init]; + [NSValueTransformer setValueTransformer:colorToValueTransformer + forName:@"ColorToValueTransformer"]; } - (id)init { @@ -460,6 +466,17 @@ void *kAppControllerContext = &kAppControllerContext; [userDefaultsValuesDict setObject:[NSNumber numberWithBool:NO] forKey:@"quitOnNaturalStop"]; + [userDefaultsValuesDict setObject:[NSNumber numberWithBool:NO] forKey:@"spectrumFreqMode"]; + [userDefaultsValuesDict setObject:[NSNumber numberWithBool:YES] forKey:@"spectrumProjectionMode"]; + + NSValueTransformer *colorToValueTransformer = [NSValueTransformer valueTransformerForName:@"ColorToValueTransformer"]; + + NSData *barColor = [colorToValueTransformer reverseTransformedValue:[NSColor colorWithSRGBRed:1.0 green:0.5 blue:0 alpha:1.0]]; + NSData *dotColor = [colorToValueTransformer reverseTransformedValue:[NSColor systemRedColor]]; + + [userDefaultsValuesDict setObject:barColor forKey:@"spectrumBarColor"]; + [userDefaultsValuesDict setObject:dotColor forKey:@"spectrumDotColor"]; + // Register and sync defaults [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict]; [[NSUserDefaults standardUserDefaults] synchronize]; diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 8e99b10a0..2e2f7a442 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -171,6 +171,7 @@ 8399D4E21805A55000B503B1 /* XmlContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8399D4E01805A55000B503B1 /* XmlContainer.m */; }; 839DA7CF274A2D4C001B18E5 /* NSDictionary+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = 839DA7CE274A2D4C001B18E5 /* NSDictionary+Merge.m */; }; 83A360B220E4E81D00192DAB /* Flac.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8303A30C20E4E3D000951EF8 /* Flac.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 83A3B734283AE89000CC6593 /* ColorToValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A3B72F283AE6AA00CC6593 /* ColorToValueTransformer.m */; }; 83AA7D04279EBCA900087AA4 /* libavcodec.59.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83AA7D00279EBC8200087AA4 /* libavcodec.59.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 83AA7D05279EBCAB00087AA4 /* libavformat.59.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83AA7D03279EBC8300087AA4 /* libavformat.59.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 83AA7D06279EBCAD00087AA4 /* libavutil.57.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83AA7D02279EBC8200087AA4 /* libavutil.57.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -1004,6 +1005,8 @@ 8399D4E11805A55000B503B1 /* XmlContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XmlContainer.h; sourceTree = ""; }; 839DA7CB274A2D4C001B18E5 /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Merge.h"; sourceTree = ""; }; 839DA7CE274A2D4C001B18E5 /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Merge.m"; sourceTree = ""; }; + 83A3B72F283AE6AA00CC6593 /* ColorToValueTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ColorToValueTransformer.m; path = Preferences/Preferences/ColorToValueTransformer.m; sourceTree = ""; }; + 83A3B733283AE6AA00CC6593 /* ColorToValueTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ColorToValueTransformer.h; path = Preferences/Preferences/ColorToValueTransformer.h; sourceTree = ""; }; 83AA7D00279EBC8200087AA4 /* libavcodec.59.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libavcodec.59.dylib; path = ThirdParty/ffmpeg/lib/libavcodec.59.dylib; sourceTree = ""; }; 83AA7D01279EBC8200087AA4 /* libswresample.4.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libswresample.4.dylib; path = ThirdParty/ffmpeg/lib/libswresample.4.dylib; sourceTree = ""; }; 83AA7D02279EBC8200087AA4 /* libavutil.57.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libavutil.57.dylib; path = ThirdParty/ffmpeg/lib/libavutil.57.dylib; sourceTree = ""; }; @@ -1438,6 +1441,8 @@ 17E0D5F60F520F42005B6FED /* Transformers */ = { isa = PBXGroup; children = ( + 83A3B733283AE6AA00CC6593 /* ColorToValueTransformer.h */, + 83A3B72F283AE6AA00CC6593 /* ColorToValueTransformer.m */, 17E0D6120F520F87005B6FED /* FontSizetoLineHeightTransformer.h */, 17E0D6130F520F87005B6FED /* FontSizetoLineHeightTransformer.m */, 17E0D6140F520F87005B6FED /* StringToURLTransformer.h */, @@ -2523,6 +2528,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 83A3B734283AE89000CC6593 /* ColorToValueTransformer.m in Sources */, 8D11072D0486CEB800E47090 /* main.m in Sources */, 8E75757109F31D5A0080F1EE /* DNDArrayController.m in Sources */, 8E75757209F31D5A0080F1EE /* PlaylistController.m in Sources */, diff --git a/Preferences/Preferences/Base.lproj/Preferences.xib b/Preferences/Preferences/Base.lproj/Preferences.xib index 3dc67ab9a..b8b80e12c 100644 --- a/Preferences/Preferences/Base.lproj/Preferences.xib +++ b/Preferences/Preferences/Base.lproj/Preferences.xib @@ -1,8 +1,8 @@ - + - + @@ -470,11 +470,11 @@ - + + + + + + + + + + ColorToValueTransformer + + + + + + + + + + + + + + + + + + + + + ColorToValueTransformer + + + + + + + + + + + + + - + diff --git a/Preferences/Preferences/ColorToValueTransformer.h b/Preferences/Preferences/ColorToValueTransformer.h new file mode 100644 index 000000000..8532f917b --- /dev/null +++ b/Preferences/Preferences/ColorToValueTransformer.h @@ -0,0 +1,16 @@ +// +// ColorToValueTransformer.h +// Preferences +// +// Created by Christopher Snowhill on 5/22/22. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ColorToValueTransformer : NSValueTransformer + +@end + +NS_ASSUME_NONNULL_END diff --git a/Preferences/Preferences/ColorToValueTransformer.m b/Preferences/Preferences/ColorToValueTransformer.m new file mode 100644 index 000000000..782835719 --- /dev/null +++ b/Preferences/Preferences/ColorToValueTransformer.m @@ -0,0 +1,60 @@ +// +// ColorToValueTransformer.m +// Preferences +// +// Created by Christopher Snowhill on 5/22/22. +// + +#import "ColorToValueTransformer.h" + +@implementation ColorToValueTransformer + ++ (Class)transformedValueClass { + return [NSColor class]; +} ++ (BOOL)allowsReverseTransformation { + return YES; +} + +// Convert from string to NSURL +- (id)reverseTransformedValue:(id)value { + if(value == nil) return nil; + + NSError *error; + NSData *data; + if(@available(macOS 10.13, *)) { + data = [NSKeyedArchiver archivedDataWithRootObject:value + requiringSecureCoding:YES + error:&error]; + } else { + data = [NSArchiver archivedDataWithRootObject:value]; + } + + return data; +} + +- (id)transformedValue:(id)value { + if(value == nil) return [NSColor colorWithRed:0 green:0 blue:0 alpha:1.0]; + + NSError *error; + NSColor *color = nil; + + if(@available(macOS 11.0, *)) { + color = (NSColor *)[NSKeyedUnarchiver unarchivedArrayOfObjectsOfClass:[NSColor class] + fromData:value + error:&error]; + } else { + if(@available(macOS 10.13, *)) { + NSSet *allowed = [NSSet setWithArray:@[[NSColor class]]]; + color = (NSColor *)[NSKeyedUnarchiver unarchivedObjectOfClasses:allowed + fromData:value + error:&error]; + } else { + color = (NSColor *)[NSUnarchiver unarchiveObjectWithData:value]; + } + } + + return color; +} + +@end diff --git a/Preferences/Preferences/GeneralPreferencesPlugin.m b/Preferences/Preferences/GeneralPreferencesPlugin.m index fadebcd46..1590aad4c 100644 --- a/Preferences/Preferences/GeneralPreferencesPlugin.m +++ b/Preferences/Preferences/GeneralPreferencesPlugin.m @@ -7,6 +7,7 @@ // #import "GeneralPreferencesPlugin.h" +#import "ColorToValueTransformer.h" #import "PathToFileTransformer.h" @implementation GeneralPreferencesPlugin @@ -15,6 +16,10 @@ NSValueTransformer *pathToFileTransformer = [[PathToFileTransformer alloc] init]; [NSValueTransformer setValueTransformer:pathToFileTransformer forName:@"PathToFileTransformer"]; + + NSValueTransformer *colorToValueTransformer = [[ColorToValueTransformer alloc] init]; + [NSValueTransformer setValueTransformer:colorToValueTransformer + forName:@"ColorToValueTransformer"]; } + (NSArray *)preferencePanes { diff --git a/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj b/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj index a35e2421d..30eb79d4b 100644 --- a/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj +++ b/Preferences/Preferences/Preferences.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */; }; 8384917718084D9F00E7332D /* appearance.png in Resources */ = {isa = PBXBuildFile; fileRef = 8384917518084D9F00E7332D /* appearance.png */; }; 8384917818084D9F00E7332D /* growl.png in Resources */ = {isa = PBXBuildFile; fileRef = 8384917618084D9F00E7332D /* growl.png */; }; + 83A3B72C283AE04800CC6593 /* ColorToValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 83A3B72B283AE04800CC6593 /* ColorToValueTransformer.m */; }; 83B06729180D85B8008E3612 /* MIDIPane.m in Sources */ = {isa = PBXBuildFile; fileRef = 83B06728180D85B8008E3612 /* MIDIPane.m */; }; 83B0672B180D8B39008E3612 /* midi.png in Resources */ = {isa = PBXBuildFile; fileRef = 83B0672A180D8B39008E3612 /* midi.png */; }; 83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83EF495E17FBC96A00642E3C /* VolumeBehaviorArrayController.m */; }; @@ -105,6 +106,8 @@ 8384913618081ECB00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; 8384917518084D9F00E7332D /* appearance.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = appearance.png; path = Icons/appearance.png; sourceTree = ""; }; 8384917618084D9F00E7332D /* growl.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = growl.png; path = Icons/growl.png; sourceTree = ""; }; + 83A3B72A283AE04800CC6593 /* ColorToValueTransformer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColorToValueTransformer.h; sourceTree = ""; }; + 83A3B72B283AE04800CC6593 /* ColorToValueTransformer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ColorToValueTransformer.m; sourceTree = ""; }; 83B06727180D85B8008E3612 /* MIDIPane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIPane.h; sourceTree = ""; }; 83B06728180D85B8008E3612 /* MIDIPane.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIPane.m; sourceTree = ""; }; 83B0672A180D8B39008E3612 /* midi.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = midi.png; path = Icons/midi.png; sourceTree = ""; }; @@ -286,6 +289,8 @@ children = ( 83F27E721810E45D00CEF538 /* PathToFileTransformer.h */, 83F27E731810E45D00CEF538 /* PathToFileTransformer.m */, + 83A3B72A283AE04800CC6593 /* ColorToValueTransformer.h */, + 83A3B72B283AE04800CC6593 /* ColorToValueTransformer.m */, ); name = Transformers; sourceTree = ""; @@ -454,6 +459,7 @@ 8E07AA8A0AAC8EA200A4B32F /* GeneralPreferencesPlugin.m in Sources */, 83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */, 17C643380B8A77CC00C53518 /* OutputsArrayController.m in Sources */, + 83A3B72C283AE04800CC6593 /* ColorToValueTransformer.m in Sources */, 837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */, 17C6433F0B8A783F00C53518 /* OutputPane.m in Sources */, 99F1813F0DE01D7A00FD5FFB /* PlaylistBehaviorArrayController.m in Sources */, diff --git a/Visualization/SpectrumView.m b/Visualization/SpectrumView.m index 97c413630..64577b285 100644 --- a/Visualization/SpectrumView.m +++ b/Visualization/SpectrumView.m @@ -11,6 +11,8 @@ #define LOWER_BOUND -80 +void *kSpectrumViewContext = &kSpectrumViewContext; + extern NSString *CogPlaybackDidBeginNotficiation; extern NSString *CogPlaybackDidPauseNotficiation; extern NSString *CogPlaybackDidResumeNotficiation; @@ -57,6 +59,46 @@ extern NSString *CogPlaybackDidStopNotficiation; } } +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if(context == kSpectrumViewContext) { + [self updateControls]; + } +} + +- (void)updateControls { + BOOL projectionMode = [[NSUserDefaults standardUserDefaults] boolForKey:@"spectrumProjectionMode"]; + SCNNode *rootNode = [[self scene] rootNode]; + SCNNode *cameraNode = [rootNode childNodeWithName:@"camera" recursively:NO]; + SCNCamera *camera = [cameraNode camera]; + [camera setUsesOrthographicProjection:projectionMode]; + + NSValueTransformer *colorToValueTransformer = [NSValueTransformer valueTransformerForName:@"ColorToValueTransformer"]; + + NSColor *barColor = [colorToValueTransformer transformedValue:[[NSUserDefaults standardUserDefaults] dataForKey:@"spectrumBarColor"]]; + NSColor *dotColor = [colorToValueTransformer transformedValue:[[NSUserDefaults standardUserDefaults] dataForKey:@"spectrumDotColor"]]; + + { + SCNNode *barNode = [rootNode childNodeWithName:@"cylinder0" recursively:NO]; + SCNGeometry *geometry = [barNode geometry]; + NSArray *materials = [geometry materials]; + SCNMaterial *material = materials[0]; + material.diffuse.contents = barColor; + material.emission.contents = barColor; + } + + { + SCNNode *dotNode = [rootNode childNodeWithName:@"sphere0" recursively:NO]; + SCNGeometry *geometry = [dotNode geometry]; + NSArray *materials = [geometry materials]; + SCNMaterial *material = materials[0]; + material.diffuse.contents = dotColor; + material.emission.contents = dotColor; + } +} + - (void)setup { visController = [NSClassFromString(@"VisualizationController") sharedController]; timer = nil; @@ -69,6 +111,8 @@ extern NSString *CogPlaybackDidStopNotficiation; SCNScene *theScene = [SCNScene sceneNamed:@"Scenes.scnassets/Spectrum.scn"]; [self setScene:theScene]; + [self updateControls]; + bandsReset = NO; [self drawBaseBands]; @@ -88,6 +132,10 @@ extern NSString *CogPlaybackDidStopNotficiation; _analyzer.freq_is_log = 0; _analyzer.mode = freqMode ? DDB_ANALYZER_MODE_FREQUENCIES : DDB_ANALYZER_MODE_OCTAVE_NOTE_BANDS; + [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.spectrumProjectionMode" options:0 context:kSpectrumViewContext]; + [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.spectrumBarColor" options:0 context:kSpectrumViewContext]; + [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.spectrumDotColor" options:0 context:kSpectrumViewContext]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackDidBegin:) name:CogPlaybackDidBeginNotficiation @@ -110,6 +158,10 @@ extern NSString *CogPlaybackDidStopNotficiation; ddb_analyzer_dealloc(&_analyzer); ddb_analyzer_draw_data_dealloc(&_draw_data); + [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.spectrumProjectionMode"]; + [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.spectrumBarColor"]; + [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.spectrumDotColor"]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:CogPlaybackDidBeginNotficiation object:nil];