From fce0e129a5022b26b6541d40bc73b00e5073d389 Mon Sep 17 00:00:00 2001 From: Christopher Snowhill Date: Sun, 22 May 2022 00:03:52 -0700 Subject: [PATCH] Spectrum Visualization: Replaced spectrum view Introduced a brand new spectrum view based on SceneKit, with a scene created by @kddlb and then altered by me to add the peak spheres. This new scene should be lighter on display resources, even though it's fully 3D instead of a vector 2D scene done in Cocoa drawing primitives. Co-authored-by: Kevin Lopez Brante Signed-off-by: Christopher Snowhill --- Cog.xcodeproj/project.pbxproj | 4 + Scenes.scnassets/Spectrum.scn | Bin 0 -> 24658 bytes Visualization/SpectrumView.h | 4 +- Visualization/SpectrumView.m | 181 +++++++++++++++++----------------- 4 files changed, 95 insertions(+), 94 deletions(-) create mode 100644 Scenes.scnassets/Spectrum.scn diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 13be2aa0f..8e99b10a0 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -97,6 +97,7 @@ 830C37A527B95EB300E02BB0 /* EqualizerWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 830C37A427B95EB300E02BB0 /* EqualizerWindowController.m */; }; 830C37FC27B9956C00E02BB0 /* analyzer.c in Sources */ = {isa = PBXBuildFile; fileRef = 830C37F227B9956C00E02BB0 /* analyzer.c */; }; 8314A46F27A28C29000EBE7E /* equalizerTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 8314A46527A28C28000EBE7E /* equalizerTemplate.pdf */; }; + 8316B3932839FFD5004CC392 /* Scenes.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = 8316B3922839FFD5004CC392 /* Scenes.scnassets */; }; 831B99BF27C23E88005A969B /* Cog.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 831B99BE27C23E88005A969B /* Cog.sdef */; }; 832923AF279FAC400048201E /* Cog.q1.json in Resources */ = {isa = PBXBuildFile; fileRef = 832923AE279FAC400048201E /* Cog.q1.json */; }; 83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8329306D277885790010C07E /* OpenMPTOld.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -904,6 +905,7 @@ 830C37F227B9956C00E02BB0 /* analyzer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = analyzer.c; sourceTree = ""; }; 8314A46527A28C28000EBE7E /* equalizerTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = equalizerTemplate.pdf; path = Images/equalizerTemplate.pdf; sourceTree = ""; }; 8314D63B1A354DFE00EEE8E6 /* sidplay.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = sidplay.xcodeproj; path = Plugins/sidplay/sidplay.xcodeproj; sourceTree = ""; }; + 8316B3922839FFD5004CC392 /* Scenes.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = Scenes.scnassets; sourceTree = ""; }; 831B99BE27C23E88005A969B /* Cog.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Cog.sdef; sourceTree = ""; }; 832923AE279FAC400048201E /* Cog.q1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Cog.q1.json; sourceTree = ""; }; 83293065277885790010C07E /* OpenMPTOld.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpenMPTOld.xcodeproj; path = Plugins/OpenMPT.old/OpenMPTOld.xcodeproj; sourceTree = ""; }; @@ -1505,6 +1507,7 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( + 8316B3922839FFD5004CC392 /* Scenes.scnassets */, 832C1252180BD1E2005507C1 /* Cog.help */, 8E07AD280AAC9BE600A4B32F /* Preference Panes */, 8E75758E09F31D800080F1EE /* Icons */, @@ -2443,6 +2446,7 @@ 17E41E070C130DFF00AC744D /* Credits.html in Resources */, 836F462B28207FA4005B9B87 /* StopColorful.png in Resources */, 8314A46F27A28C29000EBE7E /* equalizerTemplate.pdf in Resources */, + 8316B3932839FFD5004CC392 /* Scenes.scnassets in Resources */, 8384916618083EAB00E7332D /* repeatModeOneTemplate.pdf in Resources */, 8E7575DB09F31E930080F1EE /* Localizable.strings in Resources */, 83E5E54C18087CA5001F3284 /* miniModeOffTemplate.pdf in Resources */, diff --git a/Scenes.scnassets/Spectrum.scn b/Scenes.scnassets/Spectrum.scn new file mode 100644 index 0000000000000000000000000000000000000000..15f7cbfb87a65ff92bcd1cd05ae1b68b78415eb4 GIT binary patch literal 24658 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 E0}C}2NdN!< literal 0 HcmV?d00001 diff --git a/Visualization/SpectrumView.h b/Visualization/SpectrumView.h index c788622eb..f32c6e1d4 100644 --- a/Visualization/SpectrumView.h +++ b/Visualization/SpectrumView.h @@ -7,11 +7,13 @@ #import +#import + #import "VisualizationController.h" NS_ASSUME_NONNULL_BEGIN -@interface SpectrumView : NSView +@interface SpectrumView : SCNView @property(nonatomic) BOOL isListening; @end diff --git a/Visualization/SpectrumView.m b/Visualization/SpectrumView.m index 64f4347be..97c413630 100644 --- a/Visualization/SpectrumView.m +++ b/Visualization/SpectrumView.m @@ -22,11 +22,9 @@ extern NSString *CogPlaybackDidStopNotficiation; BOOL paused; BOOL stopped; BOOL isListening; + BOOL bandsReset; - NSColor *baseColor; - NSColor *peakColor; NSColor *backgroundColor; - NSColor *borderColor; ddb_analyzer_t _analyzer; ddb_analyzer_draw_data_t _draw_data; } @@ -37,7 +35,12 @@ extern NSString *CogPlaybackDidStopNotficiation; @synthesize isListening; - (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; + NSDictionary *sceneOptions = @{ + SCNPreferredRenderingAPIKey: @(SCNRenderingAPIMetal), + SCNPreferLowPowerDeviceKey: @(YES) + }; + + self = [super initWithFrame:frame options:sceneOptions]; if(self) { [self setup]; } @@ -61,7 +64,15 @@ extern NSString *CogPlaybackDidStopNotficiation; paused = NO; isListening = NO; - [self colorsDidChange:nil]; + [self setBackgroundColor:[NSColor clearColor]]; + + SCNScene *theScene = [SCNScene sceneNamed:@"Scenes.scnassets/Spectrum.scn"]; + [self setScene:theScene]; + + bandsReset = NO; + [self drawBaseBands]; + + //[self colorsDidChange:nil]; BOOL freqMode = [[NSUserDefaults standardUserDefaults] boolForKey:@"spectrumFreqMode"]; @@ -70,17 +81,13 @@ extern NSString *CogPlaybackDidStopNotficiation; _analyzer.min_freq = 10; _analyzer.max_freq = 22000; _analyzer.peak_hold = 10; - _analyzer.view_width = 64; + _analyzer.view_width = 11; _analyzer.fractional_bars = 1; _analyzer.octave_bars_step = 2; _analyzer.max_of_stereo_data = 1; _analyzer.freq_is_log = 0; _analyzer.mode = freqMode ? DDB_ANALYZER_MODE_FREQUENCIES : DDB_ANALYZER_MODE_OCTAVE_NOTE_BANDS; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(colorsDidChange:) - name:NSSystemColorsDidChangeNotification - object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackDidBegin:) name:CogPlaybackDidBeginNotficiation @@ -103,9 +110,6 @@ extern NSString *CogPlaybackDidStopNotficiation; ddb_analyzer_dealloc(&_analyzer); ddb_analyzer_draw_data_dealloc(&_draw_data); - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSSystemColorsDidChangeNotification - object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:CogPlaybackDidBeginNotficiation object:nil]; @@ -121,7 +125,22 @@ extern NSString *CogPlaybackDidStopNotficiation; } - (void)repaint { - self.needsDisplay = YES; + [self updateVisListening]; + + if(stopped) { + [self drawBaseBands]; + return; + } + + float visAudio[4096], visFFT[2048]; + + [self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0]]; + + ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048); + ddb_analyzer_tick(&_analyzer); + ddb_analyzer_get_draw_data(&_analyzer, 11.0, 1.0, &_draw_data); + + [self drawAnalyzer]; } - (void)startTimer { @@ -143,23 +162,6 @@ extern NSString *CogPlaybackDidStopNotficiation; [self repaint]; } -- (void)colorsDidChange:(NSNotification *)notification { - backgroundColor = [NSColor textBackgroundColor]; - backgroundColor = [backgroundColor colorWithAlphaComponent:0.0]; - borderColor = [NSColor systemGrayColor]; - - if(@available(macOS 10.14, *)) { - baseColor = [NSColor textColor]; - peakColor = [NSColor controlAccentColor]; - peakColor = [peakColor colorWithAlphaComponent:0.7]; - } else { - peakColor = [NSColor textColor]; - baseColor = [peakColor colorWithAlphaComponent:0.6]; - } - - [self repaint]; -} - - (void)playbackDidBegin:(NSNotification *)notification { stopped = NO; paused = NO; @@ -185,78 +187,71 @@ extern NSString *CogPlaybackDidStopNotficiation; [self repaint]; } -- (void)drawAnalyzerDescreteFrequencies { - CGContextRef context = NSGraphicsContext.currentContext.CGContext; - ddb_analyzer_draw_bar_t *bar = _draw_data.bars; - for(int i = 0; i < _draw_data.bar_count; i++, bar++) { - CGContextMoveToPoint(context, bar->xpos, 0); - CGContextAddLineToPoint(context, bar->xpos, bar->bar_height); - } - CGContextSetStrokeColorWithColor(context, baseColor.CGColor); - CGContextStrokePath(context); +- (void)drawBaseBands { + if(bandsReset) return; - bar = _draw_data.bars; - for(int i = 0; i < _draw_data.bar_count; i++, bar++) { - CGContextMoveToPoint(context, bar->xpos - 0.5, bar->peak_ypos); - CGContextAddLineToPoint(context, bar->xpos + 0.5, bar->peak_ypos); + SCNScene *scene = [self scene]; + SCNNode *rootNode = [scene rootNode]; + NSArray *nodes = [rootNode childNodes]; + + for(int i = 0; i < 11; ++i) { + SCNNode *node = nodes[i + 1]; + SCNNode *dotNode = nodes[i + 1 + 11]; + SCNVector3 position = node.position; + position.y = 0.0; + node.scale = SCNVector3Make(1.0, 0.0, 1.0); + node.position = position; + + position = dotNode.position; + position.y = 0; + dotNode.position = position; } - CGContextSetStrokeColorWithColor(context, peakColor.CGColor); - CGContextStrokePath(context); + + bandsReset = YES; } - (void)drawAnalyzerOctaveBands { - CGContextRef context = NSGraphicsContext.currentContext.CGContext; - ddb_analyzer_draw_bar_t *bar = _draw_data.bars; - for(int i = 0; i < _draw_data.bar_count; i++, bar++) { - CGContextAddRect(context, CGRectMake(bar->xpos, 0, _draw_data.bar_width, bar->bar_height)); - } - CGContextSetFillColorWithColor(context, baseColor.CGColor); - CGContextFillPath(context); + const int maxBars = (int)(ceilf((float)(_draw_data.bar_count) / 11.0)); + const int barStep = (int)(floorf((float)(_draw_data.bar_count) / 11.0)); - bar = _draw_data.bars; - for(int i = 0; i < _draw_data.bar_count; i++, bar++) { - CGContextAddRect(context, CGRectMake(bar->xpos, bar->peak_ypos, _draw_data.bar_width, 1.0)); + ddb_analyzer_draw_bar_t *bar = _draw_data.bars; + + SCNScene *scene = [self scene]; + SCNNode *rootNode = [scene rootNode]; + NSArray *nodes = [rootNode childNodes]; + + for(int i = 0; i < 11; ++i) { + float maxValue = 0.0; + float maxMax = 0.0; + for(int j = 0; j < maxBars; ++j) { + const int barBase = i * barStep; + const int barIndex = barBase + j; + if(barIndex < _draw_data.bar_count) { + if(bar[barIndex].bar_height > maxValue) { + maxValue = bar[barIndex].bar_height; + } + if(bar[barIndex].peak_ypos > maxMax) { + maxMax = bar[barIndex].peak_ypos; + } + } + } + SCNNode *node = nodes[i + 1]; + SCNNode *dotNode = nodes[i + 1 + 11]; + SCNVector3 position = node.position; + position.y = maxValue * 0.5; + node.scale = SCNVector3Make(1.0, maxValue, 1.0); + node.position = position; + + position = dotNode.position; + position.y = maxMax; + dotNode.position = position; } - CGContextSetFillColorWithColor(context, peakColor.CGColor); - CGContextFillPath(context); + + bandsReset = NO; } - (void)drawAnalyzer { - if(_analyzer.mode == DDB_ANALYZER_MODE_FREQUENCIES) { - [self drawAnalyzerDescreteFrequencies]; - } else { - [self drawAnalyzerOctaveBands]; - } -} - -- (void)drawRect:(NSRect)dirtyRect { - [super drawRect:dirtyRect]; - - [self updateVisListening]; - - [backgroundColor setFill]; - NSRectFill(dirtyRect); - - CGContextRef context = NSGraphicsContext.currentContext.CGContext; - CGContextMoveToPoint(context, 0.0, 0.0); - CGContextAddLineToPoint(context, 64.0, 0.0); - CGContextAddLineToPoint(context, 64.0, 26.0); - CGContextAddLineToPoint(context, 0.0, 26.0); - CGContextAddLineToPoint(context, 0.0, 0.0); - CGContextSetStrokeColorWithColor(context, borderColor.CGColor); - CGContextStrokePath(context); - - if(stopped) return; - - float visAudio[4096], visFFT[2048]; - - [self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0]]; - - ddb_analyzer_process(&_analyzer, [self->visController readSampleRate] / 2.0, 1, visFFT, 2048); - ddb_analyzer_tick(&_analyzer); - ddb_analyzer_get_draw_data(&_analyzer, self.bounds.size.width, self.bounds.size.height, &_draw_data); - - [self drawAnalyzer]; + [self drawAnalyzerOctaveBands]; } - (void)mouseDown:(NSEvent *)event {