Visualization: Greatly improve spectrum design
Improvement includes greatly reducing the CPU usage by not using an NSImage based painting system. Signed-off-by: Christopher Snowhill <kode54@gmail.com>CQTexperiment
parent
417687600b
commit
992b716193
|
@ -210,7 +210,7 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="gpC-Oe-Rog">
|
||||
<rect key="frame" x="234.5" y="3" width="149" height="18"/>
|
||||
<rect key="frame" x="235" y="3" width="149" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1WK-qN-Mgj">
|
||||
|
@ -289,7 +289,7 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="hhB-nv-e78">
|
||||
<rect key="frame" x="540.5" y="3" width="95" height="18"/>
|
||||
<rect key="frame" x="541" y="3" width="95" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tHy-sM-HDB">
|
||||
|
@ -366,7 +366,7 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="rRl-p9-Awr">
|
||||
<rect key="frame" x="735.5" y="3" width="144" height="18"/>
|
||||
<rect key="frame" x="736" y="3" width="144" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yW6-2w-6mN">
|
||||
|
@ -402,7 +402,7 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="hgh-VE-5kl">
|
||||
<rect key="frame" x="882.5" y="3" width="38" height="18"/>
|
||||
<rect key="frame" x="883" y="3" width="38" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yEY-MI-d3o">
|
||||
|
@ -876,13 +876,12 @@
|
|||
</connections>
|
||||
</button>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="5E0A643B-09FC-45CF-A562-C56F1E388E62" label="Spectrum" paletteLabel="Spectrum" sizingBehavior="auto" id="gui-fC-qTP">
|
||||
<toolbarItem implicitItemIdentifier="80D8CDBD-A6E9-47A6-B9C0-213C450E45FA" label="Spectrum" paletteLabel="Spectrum" tag="-1" sizingBehavior="auto" id="NtB-XF-g07" customClass="SpectrumItem">
|
||||
<nil key="toolTip"/>
|
||||
<imageView key="view" horizontalHuggingPriority="251" verticalHuggingPriority="251" id="Zaq-sS-aTV" customClass="SpectrumView">
|
||||
<customView key="view" id="lVy-2P-05b" customClass="SpectrumView">
|
||||
<rect key="frame" x="0.0" y="14" width="64" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="VDu-2p-2bJ"/>
|
||||
</imageView>
|
||||
</customView>
|
||||
</toolbarItem>
|
||||
</allowedToolbarItems>
|
||||
<defaultToolbarItems>
|
||||
|
@ -896,7 +895,7 @@
|
|||
<toolbarItem reference="1630"/>
|
||||
<toolbarItem reference="1629"/>
|
||||
<toolbarItem reference="1529"/>
|
||||
<toolbarItem reference="gui-fC-qTP"/>
|
||||
<toolbarItem reference="NtB-XF-g07"/>
|
||||
<toolbarItem reference="1568"/>
|
||||
<toolbarItem reference="1551"/>
|
||||
<toolbarItem reference="1610"/>
|
||||
|
@ -1131,13 +1130,12 @@
|
|||
</connections>
|
||||
</button>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="1A931C99-28FC-4209-BD5C-38E5CF96F7AF" label="Spectrum" paletteLabel="Spectrum" sizingBehavior="auto" id="K64-ro-2GI">
|
||||
<toolbarItem implicitItemIdentifier="09140C29-FF34-4BF2-92C8-54C7D9AA4A27" label="Spectrum" paletteLabel="Spectrum" tag="-1" sizingBehavior="auto" id="sf3-l1-fJw" customClass="SpectrumItem">
|
||||
<nil key="toolTip"/>
|
||||
<imageView key="view" horizontalHuggingPriority="251" verticalHuggingPriority="251" id="F4M-9A-fZv" customClass="SpectrumView">
|
||||
<customView key="view" id="gyu-hn-EUs" customClass="SpectrumView">
|
||||
<rect key="frame" x="0.0" y="14" width="64" height="26"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="br1-X9-N6H"/>
|
||||
</imageView>
|
||||
</customView>
|
||||
</toolbarItem>
|
||||
</allowedToolbarItems>
|
||||
<defaultToolbarItems>
|
||||
|
|
|
@ -125,6 +125,7 @@
|
|||
8370D73D277419F700245CE0 /* SQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8370D73C277419F700245CE0 /* SQLiteStore.m */; };
|
||||
8370D73F2775AE1300245CE0 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8370D73E2775AE1300245CE0 /* libsqlite3.tbd */; };
|
||||
8377C66327B8CF6300E8BC0F /* SpectrumView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C66127B8CF6300E8BC0F /* SpectrumView.m */; };
|
||||
8377C6B927B900F000E8BC0F /* SpectrumItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C6B827B900F000E8BC0F /* SpectrumItem.m */; };
|
||||
8384914018083E4E00E7332D /* filetype.icns in Resources */ = {isa = PBXBuildFile; fileRef = 8384913D18083E4E00E7332D /* filetype.icns */; };
|
||||
8384915918083EAB00E7332D /* infoTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 8384914318083EAB00E7332D /* infoTemplate.pdf */; };
|
||||
8384915A18083EAB00E7332D /* missingArt@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8384914418083EAB00E7332D /* missingArt@2x.png */; };
|
||||
|
@ -946,6 +947,8 @@
|
|||
8377C66127B8CF6300E8BC0F /* SpectrumView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpectrumView.m; path = Visualization/SpectrumView.m; sourceTree = "<group>"; };
|
||||
8377C66227B8CF6300E8BC0F /* SpectrumView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpectrumView.h; path = Visualization/SpectrumView.h; sourceTree = "<group>"; };
|
||||
8377C66427B8CF7A00E8BC0F /* VisualizationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VisualizationController.h; path = Audio/Visualization/VisualizationController.h; sourceTree = "<group>"; };
|
||||
8377C6B727B900F000E8BC0F /* SpectrumItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpectrumItem.h; path = Visualization/SpectrumItem.h; sourceTree = "<group>"; };
|
||||
8377C6B827B900F000E8BC0F /* SpectrumItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SpectrumItem.m; path = Visualization/SpectrumItem.m; sourceTree = "<group>"; };
|
||||
8384912518080F2D00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; };
|
||||
8384913D18083E4E00E7332D /* filetype.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = filetype.icns; sourceTree = "<group>"; };
|
||||
8384914318083EAB00E7332D /* infoTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = infoTemplate.pdf; path = Images/infoTemplate.pdf; sourceTree = "<group>"; };
|
||||
|
@ -1697,6 +1700,8 @@
|
|||
8377C66427B8CF7A00E8BC0F /* VisualizationController.h */,
|
||||
8377C66227B8CF6300E8BC0F /* SpectrumView.h */,
|
||||
8377C66127B8CF6300E8BC0F /* SpectrumView.m */,
|
||||
8377C6B727B900F000E8BC0F /* SpectrumItem.h */,
|
||||
8377C6B827B900F000E8BC0F /* SpectrumItem.m */,
|
||||
);
|
||||
name = Visualization;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2459,6 +2464,7 @@
|
|||
8E75757409F31D5A0080F1EE /* PlaylistView.m in Sources */,
|
||||
8E75757509F31D5A0080F1EE /* Shuffle.m in Sources */,
|
||||
8E07AB790AAC930B00A4B32F /* PreferencesController.m in Sources */,
|
||||
8377C6B927B900F000E8BC0F /* SpectrumItem.m in Sources */,
|
||||
177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */,
|
||||
177EC0270B8BC2CF0000BC8C /* TrackingCell.m in Sources */,
|
||||
177EC0290B8BC2CF0000BC8C /* TrackingSlider.m in Sources */,
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// SpectrumItem.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Christopher Snowhill on 2/13/22.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "SpectrumView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SpectrumItem : NSToolbarItem
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// SpectrumItem.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Christopher Snowhill on 2/13/22.
|
||||
//
|
||||
|
||||
#import "SpectrumItem.h"
|
||||
|
||||
@implementation SpectrumItem
|
||||
|
||||
- (void)awakeFromNib {
|
||||
SpectrumView *view = [[SpectrumView alloc] initWithFrame:NSMakeRect(0, 0, 64, 26)];
|
||||
[self setView:view];
|
||||
}
|
||||
|
||||
@end
|
|
@ -11,12 +11,20 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SpectrumView : NSImageView {
|
||||
@interface SpectrumView : NSView {
|
||||
VisualizationController *visController;
|
||||
NSTimer *timer;
|
||||
NSImage *theImage;
|
||||
BOOL paused;
|
||||
BOOL stopped;
|
||||
BOOL isListening;
|
||||
|
||||
float FFTMax[256];
|
||||
|
||||
NSColor *baseColor;
|
||||
NSColor *peakColor;
|
||||
NSColor *backgroundColor;
|
||||
}
|
||||
@property(nonatomic) BOOL isListening;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#import "SpectrumView.h"
|
||||
|
||||
#import <Accelerate/Accelerate.h>
|
||||
|
||||
extern NSString *CogPlaybackDidBeginNotficiation;
|
||||
extern NSString *CogPlaybackDidPauseNotficiation;
|
||||
extern NSString *CogPlaybackDidResumeNotficiation;
|
||||
|
@ -14,21 +16,36 @@ extern NSString *CogPlaybackDidStopNotficiation;
|
|||
|
||||
@implementation SpectrumView
|
||||
|
||||
- (void)awakeFromNib {
|
||||
@synthesize isListening;
|
||||
|
||||
- (id)initWithFrame:(NSRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if(self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateVisListening {
|
||||
if(self.isListening && (paused || stopped)) {
|
||||
[self stopTimer];
|
||||
self.isListening = NO;
|
||||
} else if(!self.isListening && (!stopped && !paused)) {
|
||||
[self startTimer];
|
||||
self.isListening = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setup {
|
||||
visController = [NSClassFromString(@"VisualizationController") sharedController];
|
||||
timer = nil;
|
||||
theImage = [NSImage imageWithSize:NSMakeSize(64, 26)
|
||||
flipped:NO
|
||||
drawingHandler:^BOOL(NSRect dstRect) {
|
||||
NSColor *backColor = [NSColor textBackgroundColor];
|
||||
[backColor drawSwatchInRect:dstRect];
|
||||
return YES;
|
||||
}];
|
||||
|
||||
stopped = YES;
|
||||
paused = NO;
|
||||
isListening = NO;
|
||||
|
||||
[self setImage:theImage];
|
||||
[self setImageScaling:NSImageScaleAxesIndependently];
|
||||
[self colorsDidChange:nil];
|
||||
|
||||
vDSP_vclr(&FFTMax[0], 1, 256);
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(colorsDidChange:)
|
||||
|
@ -52,43 +69,31 @@ extern NSString *CogPlaybackDidStopNotficiation;
|
|||
object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSSystemColorsDidChangeNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:CogPlaybackDidBeginNotficiation
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:CogPlaybackDidPauseNotficiation
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:CogPlaybackDidResumeNotficiation
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:CogPlaybackDidStopNotficiation
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)repaint {
|
||||
{
|
||||
[theImage lockFocus];
|
||||
|
||||
NSColor *backColor = [NSColor textBackgroundColor];
|
||||
[backColor drawSwatchInRect:NSMakeRect(0, 0, 64, 26)];
|
||||
|
||||
NSBezierPath *bezierPath = [[NSBezierPath alloc] init];
|
||||
|
||||
float visAudio[512], visFFT[256];
|
||||
|
||||
if(!self->stopped) {
|
||||
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0]];
|
||||
} else {
|
||||
memset(visFFT, 0, sizeof(visFFT));
|
||||
}
|
||||
|
||||
for(int i = 0; i < 60; ++i) {
|
||||
CGFloat y = MAX(MIN(visFFT[i], 0.25), 0.0) * 4.0 * 22.0 + 2.0;
|
||||
[bezierPath moveToPoint:NSMakePoint(2 + i, 2)];
|
||||
[bezierPath lineToPoint:NSMakePoint(2 + i, y)];
|
||||
}
|
||||
|
||||
NSColor *lineColor = [NSColor textColor];
|
||||
[lineColor setStroke];
|
||||
|
||||
[bezierPath stroke];
|
||||
|
||||
[theImage unlockFocus];
|
||||
}
|
||||
|
||||
[self setNeedsDisplay];
|
||||
self.needsDisplay = YES;
|
||||
}
|
||||
|
||||
- (void)startTimer {
|
||||
[self stopTimer];
|
||||
timer = [NSTimer timerWithTimeInterval:0.02
|
||||
timer = [NSTimer timerWithTimeInterval:1.0 / 60.0
|
||||
target:self
|
||||
selector:@selector(timerRun:)
|
||||
userInfo:nil
|
||||
|
@ -106,32 +111,82 @@ extern NSString *CogPlaybackDidStopNotficiation;
|
|||
}
|
||||
|
||||
- (void)colorsDidChange:(NSNotification *)notification {
|
||||
backgroundColor = [NSColor textBackgroundColor];
|
||||
|
||||
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;
|
||||
[self startTimer];
|
||||
paused = NO;
|
||||
[self updateVisListening];
|
||||
}
|
||||
|
||||
- (void)playbackDidPause:(NSNotification *)notification {
|
||||
stopped = NO;
|
||||
[self stopTimer];
|
||||
paused = YES;
|
||||
[self updateVisListening];
|
||||
}
|
||||
|
||||
- (void)playbackDidResume:(NSNotification *)notification {
|
||||
stopped = NO;
|
||||
[self startTimer];
|
||||
paused = NO;
|
||||
[self updateVisListening];
|
||||
}
|
||||
|
||||
- (void)playbackDidStop:(NSNotification *)notification {
|
||||
[self stopTimer];
|
||||
stopped = YES;
|
||||
paused = NO;
|
||||
[self updateVisListening];
|
||||
[self repaint];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
[super drawRect:dirtyRect];
|
||||
|
||||
[self updateVisListening];
|
||||
|
||||
[backgroundColor setFill];
|
||||
NSRectFill(dirtyRect);
|
||||
|
||||
float visAudio[512], visFFT[256];
|
||||
|
||||
if(!self->stopped) {
|
||||
[self->visController copyVisPCM:&visAudio[0] visFFT:&visFFT[0]];
|
||||
} else {
|
||||
memset(visFFT, 0, sizeof(visFFT));
|
||||
}
|
||||
|
||||
float scale = 0.95;
|
||||
vDSP_vsmul(&FFTMax[0], 1, &scale, &FFTMax[0], 1, 256);
|
||||
vDSP_vmax(&visFFT[0], 1, &FFTMax[0], 1, &FFTMax[0], 1, 256);
|
||||
|
||||
CGContextRef context = NSGraphicsContext.currentContext.CGContext;
|
||||
|
||||
for(int i = 0; i < 60; ++i) {
|
||||
CGFloat y = MAX(MIN(visFFT[i], 0.25), 0.0) * 4.0 * 22.0;
|
||||
CGContextMoveToPoint(context, 2.0 + i, 2.0);
|
||||
CGContextAddLineToPoint(context, 2.0 + i, 2.0 + y);
|
||||
}
|
||||
CGContextSetStrokeColorWithColor(context, baseColor.CGColor);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
for(int i = 0; i < 60; ++i) {
|
||||
CGFloat y = MAX(MIN(FFTMax[i], 0.25), 0.0) * 4.0 * 22.0;
|
||||
CGContextMoveToPoint(context, 2.0 + i, 1.5 + y);
|
||||
CGContextAddLineToPoint(context, 2.0 + i, 2.5 + y);
|
||||
}
|
||||
CGContextSetStrokeColorWithColor(context, peakColor.CGColor);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue