Equalizer: Replace dialog with custom job

New custom equalizer dialog, painstakingly hand assembled.
CQTexperiment
Christopher Snowhill 2022-02-13 11:05:32 -08:00
parent 8033256c4d
commit 7ef583340d
10 changed files with 1453 additions and 893 deletions

View File

@ -13,7 +13,7 @@
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/CoreAudioTypes.h>
#import "AUPlayerView.h"
#import "EqualizerWindowController.h"
#define DEFAULT_VOLUME_DOWN 5
#define DEFAULT_VOLUME_UP DEFAULT_VOLUME_DOWN
@ -36,6 +36,8 @@ extern NSDictionary *makeRGInfo(PlaylistEntry *pe);
IBOutlet PlaylistView *playlistView;
IBOutlet PlaylistLoader *playlistLoader;
IBOutlet EqualizerWindowController *equalizerWindowController;
IBOutlet NSSlider *volumeSlider;
IBOutlet NSArrayController *outputDevices;
@ -53,10 +55,7 @@ extern NSDictionary *makeRGInfo(PlaylistEntry *pe);
// progress bar display
double progressBarStatus;
BOOL _eqWasOpen;
BOOL _eqStubbed;
AudioUnit _eq;
AUPluginUI *_equi;
}
@property CogStatus playbackStatus;
@ -89,8 +88,6 @@ extern NSDictionary *makeRGInfo(PlaylistEntry *pe);
- (IBAction)spam:(id)sender;
- (IBAction)showEq:(id)sender;
- (void)sendMetaData;
- (void)initDefaults;

View File

@ -43,8 +43,6 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation";
seekable = NO;
fading = NO;
_eqWasOpen = NO;
_equi = nil;
progressBarStatus = -1;
@ -509,114 +507,17 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer volume] forKey:@"volume"];
}
- (void)eqAlloc {
// Show a stopped equalizer as a stub
OSStatus err;
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Effect;
desc.componentSubType = kAudioUnitSubType_GraphicEQ;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
AudioComponent comp = NULL;
desc.componentType = kAudioUnitType_Effect;
desc.componentSubType = kAudioUnitSubType_GraphicEQ;
comp = AudioComponentFindNext(comp, &desc);
if(!comp)
return;
err = AudioComponentInstanceNew(comp, &_eq);
if(err)
return;
AudioUnitInitialize(_eq);
}
- (void)eqDealloc {
AudioUnitUninitialize(_eq);
AudioComponentInstanceDispose(_eq);
_eq = nil;
_eqStubbed = NO;
}
- (IBAction)showEq:(id)sender {
if(_eq) {
if(_equi && [_equi isOpen])
[_equi bringToFront];
else
_equi = [[AUPluginUI alloc] initWithSampler:_eq bringToFront:YES orWindowNumber:0];
} else {
[self eqAlloc];
_eqWasOpen = YES;
[self audioPlayer:nil displayEqualizer:_eq];
[_equi bringToFront];
}
}
- (void)audioPlayer:(AudioPlayer *)player displayEqualizer:(AudioUnit)eq {
if(_equi) {
_eqWasOpen = [_equi isOpen];
_equi = nil;
}
if(_eq && _eq != eq) {
OSStatus err;
CFPropertyListRef classData;
UInt32 size;
size = sizeof(classData);
err = AudioUnitGetProperty(_eq, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, &size);
if(err == noErr) {
CFPreferencesSetAppValue(CFSTR("GraphEQ_Preset"), classData, kCFPreferencesCurrentApplication);
CFRelease(classData);
}
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
// Caller relinquishes EQ to us
[self eqDealloc];
[equalizerWindowController setEQ:nil];
}
_eq = eq;
{
OSStatus err;
ComponentDescription cd;
CFPropertyListRef classData;
CFDictionaryRef dict;
CFNumberRef cfnum;
equalizerLoadPreset(eq);
classData = CFPreferencesCopyAppValue(CFSTR("GraphEQ_Preset"), kCFPreferencesCurrentApplication);
if(classData) {
dict = (CFDictionaryRef)classData;
cfnum = (CFNumberRef)(CFDictionaryGetValue(dict, CFSTR("type")));
CFNumberGetValue(cfnum, kCFNumberSInt32Type, &cd.componentType);
cfnum = (CFNumberRef)(CFDictionaryGetValue(dict, CFSTR("subtype")));
CFNumberGetValue(cfnum, kCFNumberSInt32Type, &cd.componentSubType);
cfnum = (CFNumberRef)(CFDictionaryGetValue(dict, CFSTR("manufacturer")));
CFNumberGetValue(cfnum, kCFNumberSInt32Type, &cd.componentManufacturer);
if((cd.componentType == kAudioUnitType_Effect) &&
(cd.componentSubType == kAudioUnitSubType_GraphicEQ) &&
(cd.componentManufacturer == kAudioUnitManufacturer_Apple))
err = AudioUnitSetProperty(eq, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, sizeof(classData));
CFRelease(classData);
}
equalizerLoadPreset(eq);
}
if(_eqWasOpen) {
NSWindow *window = appController.miniMode ? appController.miniWindow : appController.mainWindow;
_equi = [[AUPluginUI alloc] initWithSampler:_eq bringToFront:NO orWindowNumber:window.windowNumber];
_eqWasOpen = NO;
}
[equalizerWindowController setEQ:eq];
}
- (void)audioPlayer:(AudioPlayer *)player refreshEqualizer:(AudioUnit)eq {
@ -638,16 +539,9 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
if(_equi) {
_eqWasOpen = [_equi isOpen];
}
[equalizerWindowController setEQ:nil];
_equi = nil;
[self eqDealloc];
if(_eqWasOpen) {
[self showEq:nil];
}
_eq = nil;
}
}

View File

@ -813,8 +813,9 @@ default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const
[writeSemaphore timedWait:5000];
}
if(_eq) {
// This takes the EQ and frees it after disposing of any present UIs
[outputController endEqualizer:_eq];
AudioUnitUninitialize(_eq);
AudioComponentInstanceDispose(_eq);
_eq = NULL;
}
if(downmixer) {

828
Base.lproj/Equalizer.xib Normal file
View File

@ -0,0 +1,828 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="EqualizerWindowController">
<connections>
<outlet property="eq100Hz" destination="EGw-lI-PqR" id="FVY-XJ-Yoy"/>
<outlet property="eq10kHz" destination="9gv-Wd-2i5" id="PQB-Q6-ycv"/>
<outlet property="eq125Hz" destination="X8Q-3I-fRk" id="3rN-Ie-jMH"/>
<outlet property="eq12kHz" destination="Rvd-Av-rse" id="aTc-z8-DGt"/>
<outlet property="eq160Hz" destination="I4W-MG-Od0" id="tVV-nY-FDi"/>
<outlet property="eq16kHz" destination="dvb-hD-7Oi" id="zFL-Fh-Vpl"/>
<outlet property="eq1kHz" destination="isJ-yy-cVT" id="zVY-rZ-5Zc"/>
<outlet property="eq1p2kHz" destination="Ofb-Ik-Wts" id="sAa-33-Hfy"/>
<outlet property="eq1p6kHz" destination="uHS-pU-fuc" id="FcO-gx-5Gi"/>
<outlet property="eq200Hz" destination="0B6-CW-taL" id="kfR-Vc-sac"/>
<outlet property="eq20Hz" destination="pPz-qk-lF0" id="7jj-lM-FgT"/>
<outlet property="eq20kHz" destination="eZl-bk-YsW" id="JLx-pG-K6Z"/>
<outlet property="eq250Hz" destination="7mz-zz-KJz" id="OMI-tE-WES"/>
<outlet property="eq25Hz" destination="erW-Z5-NX6" id="G1h-Fe-1Hz"/>
<outlet property="eq2kHz" destination="rYY-dc-oG4" id="02t-yQ-WZf"/>
<outlet property="eq2p5kHz" destination="L98-xd-bPa" id="vbB-CL-Pxn"/>
<outlet property="eq315Hz" destination="QfZ-Ds-evI" id="kYV-Bo-otU"/>
<outlet property="eq31p5Hz" destination="cxB-Qf-gzG" id="Bml-tV-spm"/>
<outlet property="eq3p1kHz" destination="6QJ-lg-2Xy" id="eOn-bP-Q8b"/>
<outlet property="eq400Hz" destination="zSu-v6-Cxg" id="XIv-Hs-Uft"/>
<outlet property="eq40Hz" destination="pJ2-G6-rbj" id="2QX-GQ-qMp"/>
<outlet property="eq4kHz" destination="kUj-cr-bJi" id="9zM-Xv-93t"/>
<outlet property="eq500Hz" destination="zmo-mN-TXD" id="Ggn-fR-bJc"/>
<outlet property="eq50Hz" destination="b9g-iG-0ew" id="PLP-oR-Ivw"/>
<outlet property="eq5kHz" destination="Myp-Hz-rh5" id="nwc-1k-pUu"/>
<outlet property="eq630Hz" destination="tLh-1Y-fqH" id="16J-zc-kJn"/>
<outlet property="eq63Hz" destination="Vak-Bg-ArA" id="wFU-TY-12V"/>
<outlet property="eq6p3kHz" destination="uoj-ua-fqp" id="ibL-h5-ysZ"/>
<outlet property="eq800Hz" destination="e0e-rr-aQg" id="RMV-Bf-9xd"/>
<outlet property="eq80Hz" destination="NLK-Il-XXU" id="XJY-sG-33A"/>
<outlet property="eq8kHz" destination="2aq-E2-UeA" id="Ydx-Bd-y7v"/>
<outlet property="eqPreamp" destination="1pv-lR-sLq" id="HBh-J0-ZGh"/>
<outlet property="presetSelector" destination="hB0-9d-EW2" id="heP-Dq-v7u"/>
<outlet property="window" destination="8K8-Ba-m19" id="bjj-JF-4Ww"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Equalizer" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" tabbingMode="disallowed" titlebarAppearsTransparent="YES" id="8K8-Ba-m19">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="206" width="705" height="426"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1055"/>
<view key="contentView" id="YYZ-oD-Hbm">
<rect key="frame" x="0.0" y="0.0" width="705" height="426"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Dvm-2j-T8B">
<rect key="frame" x="18" y="389" width="75" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Enabled" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="vvQ-pQ-dxe">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleEnable:" target="-2" id="n9t-dq-N51"/>
<binding destination="pqA-8k-29n" name="value" keyPath="values.GraphicEQenable" id="WSA-uI-ytt"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JzM-Lt-El8">
<rect key="frame" x="99" y="389" width="147" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Tracking genre tags" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="PAb-Y5-dhH">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleTracking:" target="-2" id="T3F-Y9-Rr5"/>
<binding destination="pqA-8k-29n" name="value" keyPath="values.GraphicEQtrackgenre" id="hcT-Pq-vNr"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5PZ-fy-yl6">
<rect key="frame" x="254" y="385" width="87" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="bevel" title="Flatten EQ" bezelStyle="regularSquare" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="f5z-bW-rIg">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="flattenEQ:" target="-2" id="oYI-9F-lFn"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yW1-Co-d7O">
<rect key="frame" x="344" y="385" width="98" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="bevel" title="Level Preamp" bezelStyle="regularSquare" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="c9p-rw-VrL">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="levelPreamp:" target="-2" id="Ot9-Ih-FbR"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jBv-uq-ZdT">
<rect key="frame" x="446" y="390" width="47" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Preset:" id="eaD-pH-YcM">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hB0-9d-EW2">
<rect key="frame" x="494" y="385" width="194" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="bevel" bezelStyle="regularSquare" alignment="left" lineBreakMode="truncatingTail" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="JA4-b3-w9Z">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="iFk-24-yfc"/>
</popUpButtonCell>
<connections>
<action selector="changePreset:" target="-2" id="RS5-jE-15H"/>
<binding destination="uog-xg-KWw" name="content" keyPath="arrangedObjects" id="2TP-bv-D4r"/>
<binding destination="uog-xg-KWw" name="contentObjects" keyPath="arrangedObjects.preference" previousBinding="2TP-bv-D4r" id="Vjp-oC-CPG"/>
<binding destination="uog-xg-KWw" name="contentValues" keyPath="arrangedObjects.name" previousBinding="Vjp-oC-CPG" id="29G-lA-2S7"/>
<binding destination="pqA-8k-29n" name="selectedIndex" keyPath="values.GraphicEQpreset" previousBinding="29G-lA-2S7" id="IZo-mP-VOa"/>
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Mi-pL-Tae">
<rect key="frame" x="47" y="364" width="49" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Preamp" id="urv-wC-ASQ">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vc5-V1-XIx">
<rect key="frame" x="74" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="20Hz" id="YOZ-BW-wQq">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c44-J3-Fxk">
<rect key="frame" x="92" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="25" id="5xs-HW-sZU">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cty-7a-d5I">
<rect key="frame" x="112" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="31.5" id="v50-ZU-hvp">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="V5g-Wg-yB4">
<rect key="frame" x="131" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="40" id="yee-yE-UoY">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5Uy-CF-Hvq">
<rect key="frame" x="151" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="50" id="WgE-Nf-TO9">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kFj-2k-qot">
<rect key="frame" x="170" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="63" id="arC-W0-Xrq">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dwg-F0-g7D">
<rect key="frame" x="190" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="80" id="0fc-Lj-S47">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FAN-Lu-XfQ">
<rect key="frame" x="209" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="100" id="Hkn-Se-53p">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BQh-C9-GcT">
<rect key="frame" x="229" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="125" id="PcC-V1-7DF">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="n3f-Iv-GVK">
<rect key="frame" x="248" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="160" id="0XK-Pc-xvP">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ilf-dH-8YC">
<rect key="frame" x="267" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="200" id="PtG-Li-QZp">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9eH-l2-Hyo">
<rect key="frame" x="287" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="250" id="XBS-Et-cRs">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xpu-T0-G04">
<rect key="frame" x="306" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="315" id="kHq-qU-vhM">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="reP-Iu-TTL">
<rect key="frame" x="326" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="400" id="Qej-u4-5b2">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Dwe-BM-5AQ">
<rect key="frame" x="345" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="500" id="nuU-eX-gcU">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xyb-fb-6B6">
<rect key="frame" x="365" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="630" id="LJg-SG-a19">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="olv-6U-M6S">
<rect key="frame" x="384" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="800" id="QOh-n3-Ee9">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bfw-2N-qW1">
<rect key="frame" x="404" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="1k" id="fn6-lu-Aye">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lwl-Bd-vYw">
<rect key="frame" x="423" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="1.2" id="b5Z-53-yzX">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9re-vr-dgc">
<rect key="frame" x="442" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="1.6" id="Qs5-PC-5G5">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EZc-rU-RfA">
<rect key="frame" x="462" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="2" id="cGE-96-1eR">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0vB-af-8db">
<rect key="frame" x="481" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="2.5" id="cEz-0N-Se6">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JED-5u-DXc">
<rect key="frame" x="501" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="3.1" id="7Ib-VD-of6">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Hd0-7Q-ADK">
<rect key="frame" x="520" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="4" id="Vjz-pX-vc3">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rgx-oK-lhx">
<rect key="frame" x="540" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="5" id="RJb-UX-Q3a">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="UCz-C8-2wq">
<rect key="frame" x="559" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="6.3" id="JsK-Yw-8DC">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9Ck-oD-sW8">
<rect key="frame" x="579" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="8" id="2AZ-qX-UBG">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BTz-fa-ExO">
<rect key="frame" x="598" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="10" id="Q94-YA-SeH">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fpD-dz-a1j">
<rect key="frame" x="618" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="12" id="rbr-Hv-AeM">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9av-QY-hrG">
<rect key="frame" x="637" y="364" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="16" id="j2U-Xg-lnG">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iz4-A3-dfN">
<rect key="frame" x="656" y="347" width="37" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="20kHz" id="ZoT-YY-K4R">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kn8-BR-bR6">
<rect key="frame" x="16" y="323" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="20 dB" id="9Uz-CE-x97">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pHj-76-ca0">
<rect key="frame" x="16" y="263" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="12 dB" id="s1h-RU-MJP">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T1H-bX-CdY">
<rect key="frame" x="16" y="217" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="6 dB" id="24d-dI-KaX">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7MJ-ik-v9u">
<rect key="frame" x="16" y="194" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="3 dB" id="YDE-sR-N8w">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Tz1-Iy-x5M">
<rect key="frame" x="16" y="173" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="0 dB" id="FJj-mN-le8">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="B7L-6g-dTH">
<rect key="frame" x="16" y="150" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="-3 dB" id="EbA-SI-KTP">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="puc-it-e5q">
<rect key="frame" x="16" y="127" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="-6 dB" id="BkT-Cf-U9W">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jl8-y5-gpV">
<rect key="frame" x="16" y="82" width="39" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="-12 dB" id="8wE-gA-sJk">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AHR-OK-hvT">
<rect key="frame" x="14" y="21" width="41" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="-20 dB" id="w4Q-0G-uHb">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="K80-dz-6b9">
<rect key="frame" x="62" y="290" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="wSi-KB-GeL">
<rect key="frame" x="62" y="314" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="eY4-WC-caQ">
<rect key="frame" x="62" y="328" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="YAu-Fw-s8v">
<rect key="frame" x="62" y="268" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="QsF-eK-6Rs">
<rect key="frame" x="62" y="245" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="Boj-8D-0qq">
<rect key="frame" x="62" y="222" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="pQa-6m-Cj2">
<rect key="frame" x="62" y="199" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="woM-CK-WUs">
<rect key="frame" x="62" y="177" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="4Gc-hi-b0h">
<rect key="frame" x="62" y="154" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="Zvd-2C-bmH">
<rect key="frame" x="62" y="131" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="ngi-iZ-iy5">
<rect key="frame" x="62" y="109" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="9jB-3w-xCT">
<rect key="frame" x="62" y="86" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="AA9-ce-lOu">
<rect key="frame" x="62" y="63" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="gz0-Pi-wtc">
<rect key="frame" x="62" y="40" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="9pz-KJ-Dnx">
<rect key="frame" x="62" y="25" width="623" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<slider horizontalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1pv-lR-sLq" customClass="EqualizerSlider">
<rect key="frame" x="60" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="BBt-Io-qN6"/>
<connections>
<action selector="adjustSlider:" target="-2" id="cwH-oW-g7e"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="pPz-qk-lF0" customClass="EqualizerSlider">
<rect key="frame" x="80" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="rV6-Z8-E1C"/>
<connections>
<action selector="adjustSlider:" target="-2" id="tQ4-0w-zNg"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="2" translatesAutoresizingMaskIntoConstraints="NO" id="erW-Z5-NX6" customClass="EqualizerSlider">
<rect key="frame" x="99" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="3VS-IF-6Gq"/>
<connections>
<action selector="adjustSlider:" target="-2" id="b6Y-Is-8JI"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="3" translatesAutoresizingMaskIntoConstraints="NO" id="cxB-Qf-gzG" customClass="EqualizerSlider">
<rect key="frame" x="119" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="rFz-I2-WwL"/>
<connections>
<action selector="adjustSlider:" target="-2" id="uXl-Oc-geJ"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="4" translatesAutoresizingMaskIntoConstraints="NO" id="pJ2-G6-rbj" customClass="EqualizerSlider">
<rect key="frame" x="138" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="9lc-MR-2w6"/>
<connections>
<action selector="adjustSlider:" target="-2" id="YFe-0w-puF"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="b9g-iG-0ew" customClass="EqualizerSlider">
<rect key="frame" x="158" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="Ku5-j3-tEZ"/>
<connections>
<action selector="adjustSlider:" target="-2" id="r13-02-WNs"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="6" translatesAutoresizingMaskIntoConstraints="NO" id="Vak-Bg-ArA" customClass="EqualizerSlider">
<rect key="frame" x="177" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="RD1-OD-LFs"/>
<connections>
<action selector="adjustSlider:" target="-2" id="9hs-Iq-mR4"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="7" translatesAutoresizingMaskIntoConstraints="NO" id="NLK-Il-XXU" customClass="EqualizerSlider">
<rect key="frame" x="197" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="Ynb-we-L85"/>
<connections>
<action selector="adjustSlider:" target="-2" id="aMB-FE-WHi"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="8" translatesAutoresizingMaskIntoConstraints="NO" id="EGw-lI-PqR" customClass="EqualizerSlider">
<rect key="frame" x="216" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="kTZ-ZV-44Z"/>
<connections>
<action selector="adjustSlider:" target="-2" id="sIe-fY-WAt"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="X8Q-3I-fRk" customClass="EqualizerSlider">
<rect key="frame" x="236" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="Exz-67-Qm8"/>
<connections>
<action selector="adjustSlider:" target="-2" id="Nmg-Io-NSr"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="10" translatesAutoresizingMaskIntoConstraints="NO" id="I4W-MG-Od0" customClass="EqualizerSlider">
<rect key="frame" x="255" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="eLk-fm-D6E"/>
<connections>
<action selector="adjustSlider:" target="-2" id="WLA-Ns-Sn8"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="11" translatesAutoresizingMaskIntoConstraints="NO" id="0B6-CW-taL" customClass="EqualizerSlider">
<rect key="frame" x="274" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="SKT-Dc-cq5"/>
<connections>
<action selector="adjustSlider:" target="-2" id="KAC-Hf-L4u"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="12" translatesAutoresizingMaskIntoConstraints="NO" id="7mz-zz-KJz" customClass="EqualizerSlider">
<rect key="frame" x="294" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="oyp-pB-2i5"/>
<connections>
<action selector="adjustSlider:" target="-2" id="f1t-hA-aQP"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="13" translatesAutoresizingMaskIntoConstraints="NO" id="QfZ-Ds-evI" customClass="EqualizerSlider">
<rect key="frame" x="313" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="AMh-UG-aGF"/>
<connections>
<action selector="adjustSlider:" target="-2" id="hoV-qd-4ZV"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="14" translatesAutoresizingMaskIntoConstraints="NO" id="zSu-v6-Cxg" customClass="EqualizerSlider">
<rect key="frame" x="333" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="PSo-He-COO"/>
<connections>
<action selector="adjustSlider:" target="-2" id="B3f-ho-VVs"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="15" translatesAutoresizingMaskIntoConstraints="NO" id="zmo-mN-TXD" customClass="EqualizerSlider">
<rect key="frame" x="352" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="xkB-Wr-zeT"/>
<connections>
<action selector="adjustSlider:" target="-2" id="Zvu-3e-Mcw"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="16" translatesAutoresizingMaskIntoConstraints="NO" id="tLh-1Y-fqH" customClass="EqualizerSlider">
<rect key="frame" x="372" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="lQF-Ys-tHL"/>
<connections>
<action selector="adjustSlider:" target="-2" id="iW7-IV-ngn"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="17" translatesAutoresizingMaskIntoConstraints="NO" id="e0e-rr-aQg" customClass="EqualizerSlider">
<rect key="frame" x="391" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="qVu-Je-O2M"/>
<connections>
<action selector="adjustSlider:" target="-2" id="q51-7C-AT0"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="18" translatesAutoresizingMaskIntoConstraints="NO" id="isJ-yy-cVT" customClass="EqualizerSlider">
<rect key="frame" x="411" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="Avj-sw-Igv"/>
<connections>
<action selector="adjustSlider:" target="-2" id="90W-wc-wW8"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="19" translatesAutoresizingMaskIntoConstraints="NO" id="Ofb-Ik-Wts" customClass="EqualizerSlider">
<rect key="frame" x="430" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="pmx-eb-Kfb"/>
<connections>
<action selector="adjustSlider:" target="-2" id="3ba-ih-SK6"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="20" translatesAutoresizingMaskIntoConstraints="NO" id="uHS-pU-fuc" customClass="EqualizerSlider">
<rect key="frame" x="449" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="iU6-3A-VBd"/>
<connections>
<action selector="adjustSlider:" target="-2" id="G1r-cA-raU"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="21" translatesAutoresizingMaskIntoConstraints="NO" id="rYY-dc-oG4" customClass="EqualizerSlider">
<rect key="frame" x="469" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="Xsy-2o-spf"/>
<connections>
<action selector="adjustSlider:" target="-2" id="Guj-GJ-0b6"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="22" translatesAutoresizingMaskIntoConstraints="NO" id="L98-xd-bPa" customClass="EqualizerSlider">
<rect key="frame" x="488" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="EhX-oM-x7Z"/>
<connections>
<action selector="adjustSlider:" target="-2" id="oTn-8d-42e"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="23" translatesAutoresizingMaskIntoConstraints="NO" id="6QJ-lg-2Xy" customClass="EqualizerSlider">
<rect key="frame" x="508" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="M6Y-pj-oe9"/>
<connections>
<action selector="adjustSlider:" target="-2" id="FK9-UQ-0c9"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="24" translatesAutoresizingMaskIntoConstraints="NO" id="kUj-cr-bJi" customClass="EqualizerSlider">
<rect key="frame" x="527" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="y7V-sl-vdA"/>
<connections>
<action selector="adjustSlider:" target="-2" id="ptm-FB-oL3"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="25" translatesAutoresizingMaskIntoConstraints="NO" id="Myp-Hz-rh5" customClass="EqualizerSlider">
<rect key="frame" x="547" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="7tQ-K8-Sh7"/>
<connections>
<action selector="adjustSlider:" target="-2" id="lzX-iG-LtJ"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="26" translatesAutoresizingMaskIntoConstraints="NO" id="uoj-ua-fqp" customClass="EqualizerSlider">
<rect key="frame" x="566" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="1bJ-ur-Oo6"/>
<connections>
<action selector="adjustSlider:" target="-2" id="0Ed-gR-1cb"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="27" translatesAutoresizingMaskIntoConstraints="NO" id="2aq-E2-UeA" customClass="EqualizerSlider">
<rect key="frame" x="586" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="4AT-bd-L0M"/>
<connections>
<action selector="adjustSlider:" target="-2" id="Itn-6c-xzS"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="28" translatesAutoresizingMaskIntoConstraints="NO" id="9gv-Wd-2i5" customClass="EqualizerSlider">
<rect key="frame" x="605" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="CQl-uv-0ZH"/>
<connections>
<action selector="adjustSlider:" target="-2" id="cq8-b9-tua"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="29" translatesAutoresizingMaskIntoConstraints="NO" id="Rvd-Av-rse" customClass="EqualizerSlider">
<rect key="frame" x="625" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="uHg-Ir-fDT"/>
<connections>
<action selector="adjustSlider:" target="-2" id="Z2D-4e-Vjc"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="30" translatesAutoresizingMaskIntoConstraints="NO" id="dvb-hD-7Oi" customClass="EqualizerSlider">
<rect key="frame" x="644" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="v1e-qx-nA6"/>
<connections>
<action selector="adjustSlider:" target="-2" id="vi5-Zw-zGt"/>
</connections>
</slider>
<slider horizontalHuggingPriority="750" fixedFrame="YES" tag="31" translatesAutoresizingMaskIntoConstraints="NO" id="eZl-bk-YsW" customClass="EqualizerSlider">
<rect key="frame" x="663" y="18" width="24" height="323"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="small" alignment="left" minValue="-20" maxValue="20" tickMarkPosition="right" sliderType="linear" id="Jtl-Sr-6Me"/>
<connections>
<action selector="adjustSlider:" target="-2" id="gvf-vg-IuQ"/>
</connections>
</slider>
</subviews>
</view>
<point key="canvasLocation" x="432.5" y="-521"/>
</window>
<arrayController objectClassName="NSDictionary" id="uog-xg-KWw" userLabel="EqPresetBehavior" customClass="EqPresetBehaviorArrayController">
<declaredKeys>
<string>name</string>
<string>slug</string>
<string>preference</string>
</declaredKeys>
<classReference key="objectClass" className="NSDictionary"/>
</arrayController>
<userDefaultsController representsSharedInstance="YES" id="pqA-8k-29n"/>
</objects>
</document>

View File

@ -836,7 +836,7 @@
<font key="font" metaFont="smallSystem"/>
</buttonCell>
<connections>
<action selector="showEq:" target="705" id="2LD-Rh-0rq"/>
<action selector="toggleWindow:" target="dJ9-b3-BFu" id="Vzd-iT-4dO"/>
</connections>
</button>
</toolbarItem>
@ -1092,7 +1092,7 @@
<font key="font" metaFont="smallSystem"/>
</buttonCell>
<connections>
<action selector="showEq:" target="705" id="0gX-vd-Rlu"/>
<action selector="toggleWindow:" target="dJ9-b3-BFu" id="oEn-0F-9dV"/>
</connections>
</button>
</toolbarItem>
@ -1382,7 +1382,7 @@
<menuItem title="Show Equalizer" keyEquivalent="e" id="nBU-pH-J3I">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="showEq:" target="705" id="8VC-ml-1Zz"/>
<action selector="showWindow:" target="dJ9-b3-BFu" id="l8q-wn-w0b"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="1854">
@ -2097,6 +2097,7 @@ Gw
<customObject id="705" userLabel="PlaybackController" customClass="PlaybackController">
<connections>
<outlet property="appController" destination="226" id="TnP-DA-nJl"/>
<outlet property="equalizerWindowController" destination="dJ9-b3-BFu" id="gB5-Bu-vqC"/>
<outlet property="playlistController" destination="218" id="706"/>
<outlet property="playlistLoader" destination="1319" id="ghZ-65-60L"/>
<outlet property="playlistView" destination="207" id="717"/>
@ -2324,6 +2325,7 @@ Gw
<outlet property="playlistSelectionController" destination="2020" id="2540"/>
</connections>
</customObject>
<customObject id="dJ9-b3-BFu" customClass="EqualizerWindowController"/>
</objects>
<resources>
<image name="deadItemsTemplate" width="20" height="20"/>

View File

@ -97,6 +97,8 @@
8305963C277F013200EBFAAE /* File_Extractor.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83059639277F011100EBFAAE /* File_Extractor.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
83059690277F04AB00EBFAAE /* Ogg.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8305968D277F049600EBFAAE /* Ogg.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
830596EE277F05EE00EBFAAE /* Vorbis.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 830596E7277F05E200EBFAAE /* Vorbis.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
830C37A127B95E3000E02BB0 /* Equalizer.xib in Resources */ = {isa = PBXBuildFile; fileRef = 830C379F27B95E3000E02BB0 /* Equalizer.xib */; };
830C37A527B95EB300E02BB0 /* EqualizerWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 830C37A427B95EB300E02BB0 /* EqualizerWindowController.m */; };
8314A46F27A28C29000EBE7E /* equalizerTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 8314A46527A28C28000EBE7E /* equalizerTemplate.pdf */; };
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, ); }; };
@ -174,7 +176,6 @@
83D0380F24A40DFB004CF90F /* CogAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83D0380E24A40DF2004CF90F /* CogAssets.xcassets */; };
83E5E54C18087CA5001F3284 /* miniModeOffTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 83E5E54A18087CA5001F3284 /* miniModeOffTemplate.pdf */; };
83E5E54D18087CA5001F3284 /* miniModeOnTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 83E5E54B18087CA5001F3284 /* miniModeOnTemplate.pdf */; };
83E88FD227945204003D6FE5 /* AUPlayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 83E88FD027945204003D6FE5 /* AUPlayerView.m */; };
83ED3AD1279A91C000904199 /* hdcdLogoTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 83ED3AC7279A91C000904199 /* hdcdLogoTemplate.pdf */; };
83F9D8071A884C54007ABEC2 /* SilenceDecoder.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83F9D7F61A884B46007ABEC2 /* SilenceDecoder.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
@ -912,6 +913,9 @@
83059634277F011100EBFAAE /* File_Extractor.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = File_Extractor.xcodeproj; path = Frameworks/File_Extractor/File_Extractor.xcodeproj; sourceTree = "<group>"; };
83059684277F049600EBFAAE /* Ogg.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Ogg.xcodeproj; path = Frameworks/Ogg/macosx/Ogg.xcodeproj; sourceTree = "<group>"; };
830596DA277F05E200EBFAAE /* Vorbis.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Vorbis.xcodeproj; path = Frameworks/Vorbis/macosx/Vorbis.xcodeproj; sourceTree = "<group>"; };
830C37A027B95E3000E02BB0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Equalizer.xib; sourceTree = "<group>"; };
830C37A327B95EB300E02BB0 /* EqualizerWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EqualizerWindowController.h; path = Equalizer/EqualizerWindowController.h; sourceTree = "<group>"; };
830C37A427B95EB300E02BB0 /* EqualizerWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = EqualizerWindowController.m; path = Equalizer/EqualizerWindowController.m; sourceTree = "<group>"; };
8314A46527A28C28000EBE7E /* equalizerTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = equalizerTemplate.pdf; path = Images/equalizerTemplate.pdf; sourceTree = "<group>"; };
8314D63B1A354DFE00EEE8E6 /* sidplay.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = sidplay.xcodeproj; path = Plugins/sidplay/sidplay.xcodeproj; sourceTree = "<group>"; };
832923AE279FAC400048201E /* Cog.q1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Cog.q1.json; sourceTree = "<group>"; };
@ -1015,8 +1019,6 @@
83E5E54A18087CA5001F3284 /* miniModeOffTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = miniModeOffTemplate.pdf; path = Images/miniModeOffTemplate.pdf; sourceTree = "<group>"; };
83E5E54B18087CA5001F3284 /* miniModeOnTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = miniModeOnTemplate.pdf; path = Images/miniModeOnTemplate.pdf; sourceTree = "<group>"; };
83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpenMPT.xcodeproj; path = Plugins/OpenMPT/OpenMPT.xcodeproj; sourceTree = "<group>"; };
83E88FD027945204003D6FE5 /* AUPlayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AUPlayerView.m; path = Window/AUPlayerView.m; sourceTree = "<group>"; };
83E88FD127945204003D6FE5 /* AUPlayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AUPlayerView.h; path = Window/AUPlayerView.h; sourceTree = "<group>"; };
83ED3AC7279A91C000904199 /* hdcdLogoTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = hdcdLogoTemplate.pdf; path = Images/hdcdLogoTemplate.pdf; sourceTree = "<group>"; };
83F9D7F11A884B44007ABEC2 /* SilenceDecoder.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SilenceDecoder.xcodeproj; path = Plugins/SilenceDecoder/SilenceDecoder.xcodeproj; sourceTree = "<group>"; };
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
@ -1084,6 +1086,7 @@
8E75752A09F31D5A0080F1EE /* Playlist */,
8E07AAEA0AAC90DC00A4B32F /* Preferences */,
17DDF6400E0CB6F100A2E4AD /* FileTree */,
830C37A227B95E6000E02BB0 /* Equalizer */,
17D1B0FE0F63252900694C57 /* InfoInspector */,
569C52C50D5F2BD500BDBDC9 /* Spotlight */,
1766C68D0B911DF1004A7AE4 /* AudioScrobbler */,
@ -1371,8 +1374,6 @@
17E0D5D20F520E75005B6FED /* Window */ = {
isa = PBXGroup;
children = (
83E88FD127945204003D6FE5 /* AUPlayerView.h */,
83E88FD027945204003D6FE5 /* AUPlayerView.m */,
83BC5AB120E4C87100631CD4 /* DualWindow.h */,
83BC5AB020E4C87100631CD4 /* DualWindow.m */,
17E0D5E10F520F02005B6FED /* MainWindow.h */,
@ -1483,6 +1484,7 @@
1791005D0CB44D6D0070BC5C /* Cog.scriptTerminology */,
832923AE279FAC400048201E /* Cog.q1.json */,
835EDD8027A000E8001EDCCE /* gsx.wv */,
830C379F27B95E3000E02BB0 /* Equalizer.xib */,
17D1B0D00F6320EA00694C57 /* InfoInspector.xib */,
17342A980D5FD20B00E8D854 /* MainMenu.xib */,
17342ABD0D5FD36400E8D854 /* OpenURLPanel.xib */,
@ -1620,6 +1622,15 @@
name = Products;
sourceTree = "<group>";
};
830C37A227B95E6000E02BB0 /* Equalizer */ = {
isa = PBXGroup;
children = (
830C37A327B95EB300E02BB0 /* EqualizerWindowController.h */,
830C37A427B95EB300E02BB0 /* EqualizerWindowController.m */,
);
name = Equalizer;
sourceTree = "<group>";
};
8314D63C1A354DFE00EEE8E6 /* Products */ = {
isa = PBXGroup;
children = (
@ -2393,6 +2404,7 @@
171B57DD0C091F2B00F6AFAF /* flac.icns in Resources */,
171B57DE0C091F2B00F6AFAF /* m4a.icns in Resources */,
8384916C18083EAB00E7332D /* stopTemplate.pdf in Resources */,
830C37A127B95E3000E02BB0 /* Equalizer.xib in Resources */,
171B57DF0C091F2B00F6AFAF /* mp3.icns in Resources */,
171B57E00C091F2B00F6AFAF /* ogg.icns in Resources */,
17818A950C0B27AC001C4916 /* aiff.icns in Resources */,
@ -2482,6 +2494,7 @@
5604D45B0D60349B004F5C5D /* SpotlightWindowController.m in Sources */,
5604D4F60D60726E004F5C5D /* SpotlightPlaylistEntry.m in Sources */,
56462EAF0D6341F6000AB68C /* SpotlightTransformers.m in Sources */,
830C37A527B95EB300E02BB0 /* EqualizerWindowController.m in Sources */,
56462EB20D634206000AB68C /* SpotlightPlaylistController.m in Sources */,
07E18DF30D62B38400BB0E11 /* NSArray+ShuffleUtils.m in Sources */,
56C63D910D647DF300EAE25A /* NSComparisonPredicate+CogPredicate.m in Sources */,
@ -2493,7 +2506,6 @@
179D031F0E0CB2500064A77A /* ContainerNode.m in Sources */,
839DA7CF274A2D4C001B18E5 /* NSDictionary+Merge.m in Sources */,
179D03200E0CB2500064A77A /* DirectoryNode.m in Sources */,
83E88FD227945204003D6FE5 /* AUPlayerView.m in Sources */,
179D03210E0CB2500064A77A /* FileIconCell.m in Sources */,
179D03220E0CB2500064A77A /* FileNode.m in Sources */,
179D03230E0CB2500064A77A /* FileTreeDataSource.m in Sources */,
@ -2768,6 +2780,14 @@
name = Credits.html;
sourceTree = "<group>";
};
830C379F27B95E3000E02BB0 /* Equalizer.xib */ = {
isa = PBXVariantGroup;
children = (
830C37A027B95E3000E02BB0 /* Base */,
);
name = Equalizer.xib;
sourceTree = "<group>";
};
8E7575D909F31E930080F1EE /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (

View File

@ -0,0 +1,79 @@
//
// EqualizerWindowController.h
// Cog
//
// Created by Christopher Snowhill on 2/13/22.
//
#import <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <AudioUnit/AudioUnitCarbonView.h>
void equalizerApplyGenre(AudioUnit _Nullable au, const NSString *_Nonnull genre);
void equalizerLoadPreset(AudioUnit _Nullable au);
void equalizerApplyPreset(AudioUnit _Nullable au, const NSDictionary *_Nonnull preset);
NS_ASSUME_NONNULL_BEGIN
@interface EqPresetBehaviorArrayController : NSArrayController
@end
@interface EqualizerSlider : NSSlider
@end
@interface EqualizerWindowController : NSWindowController {
IBOutlet NSPopUpButton *presetSelector;
IBOutlet EqualizerSlider *eqPreamp;
IBOutlet EqualizerSlider *eq20Hz;
IBOutlet EqualizerSlider *eq25Hz;
IBOutlet EqualizerSlider *eq31p5Hz;
IBOutlet EqualizerSlider *eq40Hz;
IBOutlet EqualizerSlider *eq50Hz;
IBOutlet EqualizerSlider *eq63Hz;
IBOutlet EqualizerSlider *eq80Hz;
IBOutlet EqualizerSlider *eq100Hz;
IBOutlet EqualizerSlider *eq125Hz;
IBOutlet EqualizerSlider *eq160Hz;
IBOutlet EqualizerSlider *eq200Hz;
IBOutlet EqualizerSlider *eq250Hz;
IBOutlet EqualizerSlider *eq315Hz;
IBOutlet EqualizerSlider *eq400Hz;
IBOutlet EqualizerSlider *eq500Hz;
IBOutlet EqualizerSlider *eq630Hz;
IBOutlet EqualizerSlider *eq800Hz;
IBOutlet EqualizerSlider *eq1kHz;
IBOutlet EqualizerSlider *eq1p2kHz;
IBOutlet EqualizerSlider *eq1p6kHz;
IBOutlet EqualizerSlider *eq2kHz;
IBOutlet EqualizerSlider *eq2p5kHz;
IBOutlet EqualizerSlider *eq3p1kHz;
IBOutlet EqualizerSlider *eq4kHz;
IBOutlet EqualizerSlider *eq5kHz;
IBOutlet EqualizerSlider *eq6p3kHz;
IBOutlet EqualizerSlider *eq8kHz;
IBOutlet EqualizerSlider *eq10kHz;
IBOutlet EqualizerSlider *eq12kHz;
IBOutlet EqualizerSlider *eq16kHz;
IBOutlet EqualizerSlider *eq20kHz;
AudioUnit au;
}
- (void)setEQ:(AudioUnit _Nullable)au;
- (IBAction)toggleWindow:(id)sender;
- (IBAction)toggleEnable:(id)sender;
- (IBAction)toggleTracking:(id)sender;
- (IBAction)flattenEQ:(id)sender;
- (IBAction)levelPreamp:(id)sender;
- (IBAction)adjustSlider:(id)sender;
- (IBAction)changePreset:(id)sender;
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,505 @@
//
// EqualizerWindowController.m
// Cog
//
// Created by Christopher Snowhill on 2/13/22.
//
#import "EqualizerWindowController.h"
#import "json.h"
#import "Logging.h"
static const NSString *equalizerGenre = @"";
static const NSString *equalizerDefaultGenre = @"Flat";
static NSArray *equalizer_presets_processed = nil;
static NSDictionary *equalizer_presets_by_name = nil;
static json_value *equalizer_presets = NULL;
static NSString *_cog_equalizer_type = @"Cog EQ library file v1.0";
static NSArray *_cog_equalizer_items() {
return @[@"name", @"hz32", @"hz64", @"hz128", @"hz256", @"hz512", @"hz1000", @"hz2000", @"hz4000", @"hz8000", @"hz16000", @"preamp"];
}
static NSArray *_cog_equalizer_band_settings() {
return @[@"eqPreamp", @"eq20Hz", @"eq25Hz", @"eq31p5Hz", @"eq40Hz", @"eq50Hz", @"eq63Hz", @"eq80Hz", @"eq100Hz", @"eq125Hz", @"eq160Hz", @"eq200Hz", @"eq250Hz", @"eq315Hz", @"eq400Hz", @"eq500Hz", @"eq630Hz", @"eq800Hz", @"eq1kHz", @"eq1p2kHz", @"eq1p6kHz", @"eq2kHz", @"eq2p5kHz", @"eq3p1kHz", @"eq4kHz", @"eq5kHz", @"eq6p3kHz", @"eq8kHz", @"eq10kHz", @"eq12kHz", @"eq16kHz", @"eq20kHz"];
}
static const float cog_equalizer_bands[10] = { 32, 64, 128, 256, 512, 1000, 2000, 4000, 8000, 16000 };
static NSArray *cog_equalizer_items = nil;
static NSArray *cog_equalizer_band_settings = nil;
static NSString *cog_equalizer_extra_genres = @"altGenres";
static const float apple_equalizer_bands[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 inline float interpolatePoint(const NSDictionary *preset, float freqTarget) {
if(!cog_equalizer_items)
cog_equalizer_items = _cog_equalizer_items();
// predict extra bands! lpc was too broken, quadra was broken, let's try simple linear steps
if(freqTarget < cog_equalizer_bands[0]) {
float work[14];
float work_freq[14];
for(unsigned int i = 0; i < 10; ++i) {
work[9 - i] = [[preset objectForKey:[cog_equalizer_items objectAtIndex:1 + i]] floatValue];
work_freq[9 - i] = cog_equalizer_bands[i];
}
for(unsigned int i = 10; i < 14; ++i) {
work[i] = work[i - 1] + (work[i - 1] - work[i - 2]) * 1.05;
work_freq[i] = work_freq[i - 1] + (work_freq[i - 1] - work_freq[i - 2]) * 1.05;
}
for(unsigned int i = 0; i < 13; ++i) {
if(freqTarget >= work_freq[13 - i] &&
freqTarget < work_freq[12 - i]) {
float freqLow = work_freq[13 - i];
float freqHigh = work_freq[12 - i];
float valueLow = work[13 - i];
float valueHigh = work[12 - i];
float delta = (freqTarget - freqLow) / (freqHigh - freqLow);
return valueLow + (valueHigh - valueLow) * delta;
}
}
return work[13];
} else if(freqTarget > cog_equalizer_bands[9]) {
float work[14];
float work_freq[14];
for(unsigned int i = 0; i < 10; ++i) {
work[i] = [[preset objectForKey:[cog_equalizer_items objectAtIndex:1 + i]] floatValue];
work_freq[i] = cog_equalizer_bands[i];
}
for(unsigned int i = 10; i < 14; ++i) {
work[i] = work[i - 1] + (work[i - 1] - work[i - 2]) * 1.05;
work_freq[i] = work_freq[i - 1] + (work_freq[i - 1] - work_freq[i - 2]) * 1.05;
}
for(unsigned int i = 0; i < 13; ++i) {
if(freqTarget >= work_freq[i] &&
freqTarget < work_freq[i + 1]) {
float freqLow = work_freq[i];
float freqHigh = work_freq[i + 1];
float valueLow = work[i];
float valueHigh = work[i + 1];
float delta = (freqTarget - freqLow) / (freqHigh - freqLow);
return valueLow + (valueHigh - valueLow) * delta;
}
}
return work[13];
}
// Pick the extremes
if(freqTarget == cog_equalizer_bands[0])
return [[preset objectForKey:[cog_equalizer_items objectAtIndex:1]] floatValue];
else if(freqTarget == cog_equalizer_bands[9])
return [[preset objectForKey:[cog_equalizer_items objectAtIndex:10]] floatValue];
// interpolation time! linear is fine for this
for(size_t i = 0; i < 9; ++i) {
if(freqTarget >= cog_equalizer_bands[i] &&
freqTarget < cog_equalizer_bands[i + 1]) {
float freqLow = cog_equalizer_bands[i];
float freqHigh = cog_equalizer_bands[i + 1];
float valueLow = [[preset objectForKey:[cog_equalizer_items objectAtIndex:i + 1]] floatValue];
float valueHigh = [[preset objectForKey:[cog_equalizer_items objectAtIndex:i + 2]] floatValue];
float delta = (freqTarget - freqLow) / (freqHigh - freqLow);
return valueLow + (valueHigh - valueLow) * delta;
}
}
return 0.0;
}
static void interpolateBands(float *out, const NSDictionary *preset) {
for(size_t i = 0; i < 31; ++i) {
out[i] = interpolatePoint(preset, apple_equalizer_bands[i]);
}
}
static float getPreamp(const NSDictionary *preset) {
return [[preset objectForKey:[cog_equalizer_items objectAtIndex:11]] floatValue];
}
static void loadPresets() {
if([equalizer_presets_processed count]) return;
NSURL *url = [[NSBundle mainBundle] URLForResource:@"Cog.q1" withExtension:@"json"];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:[url path]];
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, [_cog_equalizer_type UTF8String], 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];
NSMutableDictionary *dict = [[NSMutableDictionary 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;
cog_equalizer_items = _cog_equalizer_items();
const size_t cog_object_minimum = [cog_equalizer_items count];
for(size_t i = 0; i < count; ++i) {
if(values[i]->type == json_object) {
NSMutableArray<NSString *> *extraGenres = [[NSMutableArray alloc] init];
size_t object_items = values[i]->u.object.length;
json_object_entry *object_entry = values[i]->u.object.values;
size_t requiredItemsPresent = 0;
if(object_items >= cog_object_minimum) {
NSMutableDictionary *equalizerItem = [[NSMutableDictionary alloc] init];
for(size_t j = 0; j < object_items; ++j) {
NSString *key = [NSString stringWithUTF8String:object_entry[j].name];
NSInteger index = [cog_equalizer_items indexOfObject:key];
if(index != NSNotFound) {
if(index == 0 && object_entry[j].value->type == json_string) {
NSString *name = [NSString stringWithUTF8String:object_entry[j].value->u.string.ptr];
[equalizerItem setObject:name forKey:key];
++requiredItemsPresent;
} else if(object_entry[j].value->type == json_integer) {
int64_t value = object_entry[j].value->u.integer;
float floatValue = ((value <= 401 && value >= 1) ? ((float)(value - 201) / 10.0) : 0.0);
[equalizerItem setObject:[NSNumber numberWithFloat:floatValue] forKey:key];
++requiredItemsPresent;
}
} else if([key isEqualToString:cog_equalizer_extra_genres]) {
// Process alternate genre matches
if(object_entry[j].value->type == json_array) {
size_t value_count = object_entry[j].value->u.array.length;
json_value **values = object_entry[j].value->u.array.values;
for(size_t k = 0; k < value_count; ++k) {
if(values[k]->type == json_string) {
[extraGenres addObject:[NSString stringWithUTF8String:values[i]->u.string.ptr]];
}
}
}
}
}
if(requiredItemsPresent == cog_object_minimum) {
// Add the base item
NSDictionary *outItem = [NSDictionary dictionaryWithDictionary:equalizerItem];
[array addObject:outItem];
[dict setObject:outItem forKey:[outItem objectForKey:@"name"]];
// Add the alternate genres, if any
for(NSString *genre in extraGenres) {
[dict setObject:outItem forKey:genre];
}
}
}
}
}
equalizer_presets_processed = [NSArray arrayWithArray:array];
equalizer_presets_by_name = [NSDictionary dictionaryWithDictionary:dict];
}
}
[fileHandle closeFile];
json_value_free(equalizer_presets);
equalizer_presets = NULL;
}
}
void equalizerApplyGenre(AudioUnit au, const NSString *genre) {
equalizerGenre = genre;
if([[NSUserDefaults standardUserDefaults] boolForKey:@"GraphicEQtrackgenre"]) {
loadPresets();
NSDictionary *preset = [equalizer_presets_by_name objectForKey:genre];
if(!preset) {
// Find a match
if(genre && ![genre isEqualToString:@""]) {
NSUInteger matchLength = 0;
NSString *lowerCaseGenre = [genre lowercaseString];
for(NSString *key in [equalizer_presets_by_name allKeys]) {
NSString *lowerCaseKey = [key lowercaseString];
if([lowerCaseGenre containsString:lowerCaseKey]) {
if([key length] > matchLength) {
matchLength = [key length];
preset = [equalizer_presets_by_name objectForKey:key];
}
}
}
}
if(!preset) {
preset = [equalizer_presets_by_name objectForKey:equalizerDefaultGenre];
}
}
if(preset) {
NSInteger index = [equalizer_presets_processed indexOfObject:preset];
[[NSUserDefaults standardUserDefaults] setInteger:index forKey:@"GraphicEQpreset"];
equalizerApplyPreset(au, preset);
}
}
}
void equalizerLoadPreset(AudioUnit au) {
NSInteger index = [[NSUserDefaults standardUserDefaults] integerForKey:@"GraphicEQpreset"];
if(index >= 0 && index < [equalizer_presets_processed count]) {
NSDictionary *preset = [equalizer_presets_processed objectAtIndex:index];
equalizerApplyPreset(au, preset);
} else if(au) {
float preamp = [[NSUserDefaults standardUserDefaults] floatForKey:[cog_equalizer_band_settings objectAtIndex:0]];
AudioUnitSetParameter(au, kGraphicEQParam_NumberOfBands, kAudioUnitScope_Global, 0, 1, 0);
for(NSInteger i = 1; i < [cog_equalizer_band_settings count]; ++i) {
float value = [[NSUserDefaults standardUserDefaults] floatForKey:[cog_equalizer_band_settings objectAtIndex:i]];
AudioUnitSetParameter(au, (int)(i - 1), kAudioUnitScope_Global, 0, value + preamp, 0);
}
}
}
void equalizerApplyPreset(AudioUnit au, const NSDictionary *preset) {
if(au && preset) {
AudioUnitParameterValue paramValue = 0;
if(AudioUnitGetParameter(au, kGraphicEQParam_NumberOfBands, kAudioUnitScope_Global, 0, &paramValue))
return;
float presetValues[31];
interpolateBands(presetValues, preset);
float preamp = getPreamp(preset);
AudioUnitSetParameter(au, kGraphicEQParam_NumberOfBands, kAudioUnitScope_Global, 0, 1, 0);
for(unsigned int i = 0; i < 31; ++i) {
AudioUnitSetParameter(au, i, kAudioUnitScope_Global, 0, presetValues[i] + preamp, 0);
}
}
}
@implementation EqPresetBehaviorArrayController
- (void)awakeFromNib {
[self removeObjects:[self arrangedObjects]];
loadPresets();
for(NSDictionary *preset in equalizer_presets_processed) {
[self addObject:@{ @"name": [preset objectForKey:@"name"], @"preference": [preset objectForKey:@"name"] }];
}
[self addObject:@{ @"name": @"Custom", @"preference": @"Custom" }];
}
@end
@implementation EqualizerSlider
- (void)awakeFromNib {
if(@available(macOS 10.12.2, *)) {
[self setTrackFillColor:[NSColor systemGrayColor]];
}
}
@end
@interface EqualizerWindowController ()
@end
@implementation EqualizerWindowController
+ (void)initialize {
cog_equalizer_band_settings = _cog_equalizer_band_settings();
}
- (id)init {
return [super initWithWindowNibName:@"Equalizer"];
}
- (void)windowDidLoad {
[super windowDidLoad];
[self changePreset:presetSelector];
}
- (void)setEQ:(AudioUnit)au {
self->au = au;
}
- (IBAction)toggleWindow:(id)sender {
if([[self window] isVisible])
[[self window] orderOut:self];
else
[self showWindow:self];
}
- (IBAction)toggleEnable:(id)sender {
}
- (IBAction)toggleTracking:(id)sender {
equalizerApplyGenre(au, equalizerGenre);
[self changePreset:presetSelector];
}
- (IBAction)flattenEQ:(id)sender {
[presetSelector selectItemWithTitle:@"Flat"];
[self changePreset:presetSelector];
}
- (EqualizerSlider *)sliderForIndex:(NSInteger)index {
switch(index) {
case 0:
return eqPreamp;
case 1:
return eq20Hz;
case 2:
return eq25Hz;
case 3:
return eq31p5Hz;
case 4:
return eq40Hz;
case 5:
return eq50Hz;
case 6:
return eq63Hz;
case 7:
return eq80Hz;
case 8:
return eq100Hz;
case 9:
return eq125Hz;
case 10:
return eq160Hz;
case 11:
return eq200Hz;
case 12:
return eq250Hz;
case 13:
return eq315Hz;
case 14:
return eq400Hz;
case 15:
return eq500Hz;
case 16:
return eq630Hz;
case 17:
return eq800Hz;
case 18:
return eq1kHz;
case 19:
return eq1p2kHz;
case 20:
return eq1p6kHz;
case 21:
return eq2kHz;
case 22:
return eq2p5kHz;
case 23:
return eq3p1kHz;
case 24:
return eq4kHz;
case 25:
return eq5kHz;
case 26:
return eq6p3kHz;
case 27:
return eq8kHz;
case 28:
return eq10kHz;
case 29:
return eq12kHz;
case 30:
return eq16kHz;
case 31:
return eq20kHz;
default:
return nil;
}
}
- (IBAction)levelPreamp:(id)sender {
float preamp = [eqPreamp floatValue];
float maxValue = 0.0;
for(NSInteger i = 1; i < [cog_equalizer_band_settings count]; ++i) {
float value = [[self sliderForIndex:i] floatValue];
if(value > maxValue) maxValue = value;
}
if(maxValue > 0.0 && preamp != -maxValue) {
[presetSelector selectItemAtIndex:[equalizer_presets_processed count]];
[[NSUserDefaults standardUserDefaults] setInteger:[equalizer_presets_processed count] forKey:@"GraphicEQpreset"];
[eqPreamp setFloatValue:-maxValue];
[[NSUserDefaults standardUserDefaults] setFloat:-maxValue forKey:[cog_equalizer_band_settings objectAtIndex:0]];
if(au)
equalizerLoadPreset(au);
}
}
- (IBAction)adjustSlider:(id)sender {
NSInteger tag = [sender tag];
if(tag == 0) {
float preamp = [eqPreamp floatValue];
[[NSUserDefaults standardUserDefaults] setFloat:preamp forKey:[cog_equalizer_band_settings objectAtIndex:0]];
equalizerLoadPreset(au);
} else if(tag < [cog_equalizer_band_settings count]) {
float preamp = [eqPreamp floatValue];
float value = [sender floatValue];
[[NSUserDefaults standardUserDefaults] setFloat:value forKey:[cog_equalizer_band_settings objectAtIndex:tag]];
if(au)
AudioUnitSetParameter(au, (int)(tag - 1), kAudioUnitScope_Global, 0, value + preamp, 0);
}
}
- (void)changePreset:(id)sender {
NSInteger index = [sender indexOfSelectedItem];
if(index >= 0 && index < [equalizer_presets_processed count]) {
NSDictionary *preset = [equalizer_presets_processed objectAtIndex:index];
equalizerApplyPreset(au, preset);
float preamp = getPreamp(preset);
float presetValues[31];
interpolateBands(presetValues, preset);
for(NSInteger i = 0; i < [cog_equalizer_band_settings count]; ++i) {
EqualizerSlider *slider = [self sliderForIndex:i];
if(i == 0) {
[slider setFloatValue:preamp];
[[NSUserDefaults standardUserDefaults] setFloat:preamp forKey:[cog_equalizer_band_settings objectAtIndex:i]];
} else {
[slider setFloatValue:presetValues[i - 1]];
[[NSUserDefaults standardUserDefaults] setFloat:presetValues[i - 1] forKey:[cog_equalizer_band_settings objectAtIndex:i]];
}
}
}
}
@end

View File

@ -1,55 +0,0 @@
//
// AUPlayerView.h
// Output
//
// Created by Christopher Snowhill on 1/29/16.
// Copyright © 2016-2022 Christopher Snowhill. All rights reserved.
//
#ifndef __AUPlayerView_h__
#define __AUPlayerView_h__
#import <AppKit/AppKit.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AudioUnit/AudioUnit.h>
#import <AudioUnit/AudioUnitCarbonView.h>
void equalizerApplyGenre(AudioUnit au, NSString *genre);
void equalizerLoadPreset(AudioUnit au);
void equalizerApplyPreset(AudioUnit au, NSDictionary *preset);
@interface AUPluginUI : NSObject {
AudioUnit au;
BOOL windowOpen;
/* Cocoa */
NSWindow *cocoa_window;
NSView *au_view;
NSRect last_au_frame;
}
- (id)initWithSampler:(AudioUnit)_au bringToFront:(BOOL)front orWindowNumber:(NSInteger)window;
- (void)dealloc;
- (BOOL)isOpen;
- (void)bringToFront;
@end
@interface AUPluginWindow : NSWindow <NSSplitViewDelegate> {
AudioUnit au;
AUParameterListenerRef listenerRef;
NSView *topView;
NSView *auView;
NSSplitView *splitView;
NSPopUpButton *presetButton;
}
- (id)initWithAuView:(NSView *)_auView withAu:(AudioUnit)au bringToFront:(BOOL)front relativeToWindow:(NSInteger)window;
@end
#endif

View File

@ -1,711 +0,0 @@
//
// AUPlayerView.m
// Output
//
// Created by Christopher Snowhill on 1/29/16.
// Copyright © 2016-2022 Christopher Snowhill. All rights reserved.
//
#import <AudioUnit/AUCocoaUIView.h>
#import <CoreAudioKit/AUGenericView.h>
#import <Foundation/Foundation.h>
#import "AUPlayerView.h"
#import "json.h"
#import "Logging.h"
static NSString *equalizerGenre = @"";
static const NSString *equalizerDefaultGenre = @"Flat";
static NSArray *equalizer_presets_processed = nil;
static NSDictionary *equalizer_presets_by_name = nil;
static json_value *equalizer_presets = NULL;
static NSString *_cog_equalizer_type = @"Cog EQ library file v1.0";
static NSArray *_cog_equalizer_items() {
return @[@"name", @"hz32", @"hz64", @"hz128", @"hz256", @"hz512", @"hz1000", @"hz2000", @"hz4000", @"hz8000", @"hz16000", @"preamp"];
}
static const float cog_equalizer_bands[10] = { 32, 64, 128, 256, 512, 1000, 2000, 4000, 8000, 16000 };
static NSArray *cog_equalizer_items = nil;
static NSString *cog_equalizer_extra_genres = @"altGenres";
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(!cog_equalizer_items)
cog_equalizer_items = _cog_equalizer_items();
// predict extra bands! lpc was too broken, quadra was broken, let's try simple linear steps
if(freqTarget < cog_equalizer_bands[0]) {
float work[14];
float work_freq[14];
for(unsigned int i = 0; i < 10; ++i) {
work[9 - i] = [[preset objectForKey:[cog_equalizer_items objectAtIndex:1 + i]] floatValue];
work_freq[9 - i] = cog_equalizer_bands[i];
}
for(unsigned int i = 10; i < 14; ++i) {
work[i] = work[i - 1] + (work[i - 1] - work[i - 2]) * 1.05;
work_freq[i] = work_freq[i - 1] + (work_freq[i - 1] - work_freq[i - 2]) * 1.05;
}
for(unsigned int i = 0; i < 13; ++i) {
if(freqTarget >= work_freq[13 - i] &&
freqTarget < work_freq[12 - i]) {
float freqLow = work_freq[13 - i];
float freqHigh = work_freq[12 - i];
float valueLow = work[13 - i];
float valueHigh = work[12 - i];
float delta = (freqTarget - freqLow) / (freqHigh - freqLow);
return valueLow + (valueHigh - valueLow) * delta;
}
}
return work[13];
} else if(freqTarget > cog_equalizer_bands[9]) {
float work[14];
float work_freq[14];
for(unsigned int i = 0; i < 10; ++i) {
work[i] = [[preset objectForKey:[cog_equalizer_items objectAtIndex:1 + i]] floatValue];
work_freq[i] = cog_equalizer_bands[i];
}
for(unsigned int i = 10; i < 14; ++i) {
work[i] = work[i - 1] + (work[i - 1] - work[i - 2]) * 1.05;
work_freq[i] = work_freq[i - 1] + (work_freq[i - 1] - work_freq[i - 2]) * 1.05;
}
for(unsigned int i = 0; i < 13; ++i) {
if(freqTarget >= work_freq[i] &&
freqTarget < work_freq[i + 1]) {
float freqLow = work_freq[i];
float freqHigh = work_freq[i + 1];
float valueLow = work[i];
float valueHigh = work[i + 1];
float delta = (freqTarget - freqLow) / (freqHigh - freqLow);
return valueLow + (valueHigh - valueLow) * delta;
}
}
return work[13];
}
// Pick the extremes
if(freqTarget == cog_equalizer_bands[0])
return [[preset objectForKey:[cog_equalizer_items objectAtIndex:1]] floatValue];
else if(freqTarget == cog_equalizer_bands[9])
return [[preset objectForKey:[cog_equalizer_items objectAtIndex:10]] floatValue];
// interpolation time! linear is fine for this
for(size_t i = 0; i < 9; ++i) {
if(freqTarget >= cog_equalizer_bands[i] &&
freqTarget < cog_equalizer_bands[i + 1]) {
float freqLow = cog_equalizer_bands[i];
float freqHigh = cog_equalizer_bands[i + 1];
float valueLow = [[preset objectForKey:[cog_equalizer_items objectAtIndex:i + 1]] floatValue];
float valueHigh = [[preset objectForKey:[cog_equalizer_items objectAtIndex: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;
NSURL *url = [[NSBundle mainBundle] URLForResource:@"Cog.q1" withExtension:@"json"];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:[url path]];
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, [_cog_equalizer_type UTF8String], 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];
NSMutableDictionary *dict = [[NSMutableDictionary 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;
cog_equalizer_items = _cog_equalizer_items();
const size_t cog_object_minimum = [cog_equalizer_items count];
for(size_t i = 0; i < count; ++i) {
if(values[i]->type == json_object) {
NSMutableArray<NSString *> *extraGenres = [[NSMutableArray alloc] init];
size_t object_items = values[i]->u.object.length;
json_object_entry *object_entry = values[i]->u.object.values;
size_t requiredItemsPresent = 0;
if(object_items >= cog_object_minimum) {
NSMutableDictionary *equalizerItem = [[NSMutableDictionary alloc] init];
for(size_t j = 0; j < object_items; ++j) {
NSString *key = [NSString stringWithUTF8String:object_entry[j].name];
NSInteger index = [cog_equalizer_items indexOfObject:key];
if(index != NSNotFound) {
if(index == 0 && object_entry[j].value->type == json_string) {
NSString *name = [NSString stringWithUTF8String:object_entry[j].value->u.string.ptr];
[equalizerItem setObject:name forKey:key];
++requiredItemsPresent;
} else if(object_entry[j].value->type == json_integer) {
int64_t value = object_entry[j].value->u.integer;
float floatValue = ((value <= 401 && value >= 1) ? ((float)(value - 201) / 10.0) : 0.0);
[equalizerItem setObject:[NSNumber numberWithFloat:floatValue] forKey:key];
++requiredItemsPresent;
}
} else if([key isEqualToString:cog_equalizer_extra_genres]) {
// Process alternate genre matches
if(object_entry[j].value->type == json_array) {
size_t value_count = object_entry[j].value->u.array.length;
json_value **values = object_entry[j].value->u.array.values;
for(size_t k = 0; k < value_count; ++k) {
if(values[k]->type == json_string) {
[extraGenres addObject:[NSString stringWithUTF8String:values[i]->u.string.ptr]];
}
}
}
}
}
if(requiredItemsPresent == cog_object_minimum) {
// Add the base item
NSDictionary *outItem = [NSDictionary dictionaryWithDictionary:equalizerItem];
[array addObject:outItem];
[dict setObject:outItem forKey:[outItem objectForKey:@"name"]];
// Add the alternate genres, if any
for(NSString *genre in extraGenres) {
[dict setObject:outItem forKey:genre];
}
}
}
}
}
equalizer_presets_processed = [NSArray arrayWithArray:array];
equalizer_presets_by_name = [NSDictionary dictionaryWithDictionary:dict];
}
}
[fileHandle closeFile];
json_value_free(equalizer_presets);
equalizer_presets = NULL;
}
}
void equalizerApplyGenre(AudioUnit au, NSString *genre) {
equalizerGenre = genre;
if([[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"GraphicEQtrackgenre"]) {
loadPresets();
NSDictionary *preset = [equalizer_presets_by_name objectForKey:genre];
if(!preset) {
// Find a match
if(genre && ![genre isEqualToString:@""]) {
NSUInteger matchLength = 0;
NSString *lowerCaseGenre = [genre lowercaseString];
for(NSString *key in [equalizer_presets_by_name allKeys]) {
NSString *lowerCaseKey = [key lowercaseString];
if([lowerCaseGenre containsString:lowerCaseKey]) {
if([key length] > matchLength) {
matchLength = [key length];
preset = [equalizer_presets_by_name objectForKey:key];
}
}
}
}
if(!preset) {
preset = [equalizer_presets_by_name objectForKey:equalizerDefaultGenre];
}
}
if(preset) {
NSInteger index = [equalizer_presets_processed indexOfObject:preset];
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setInteger:index forKey:@"GraphicEQpreset"];
equalizerApplyPreset(au, preset);
}
}
}
void equalizerLoadPreset(AudioUnit au) {
NSInteger index = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] integerForKey:@"GraphicEQpreset"];
if(index >= 0 && index < [equalizer_presets_processed count]) {
NSDictionary *preset = [equalizer_presets_processed objectAtIndex:index];
equalizerApplyPreset(au, preset);
}
}
void equalizerApplyPreset(AudioUnit au, NSDictionary *preset) {
if(au && preset) {
AudioUnitParameterValue paramValue = 0;
if(AudioUnitGetParameter(au, kGraphicEQParam_NumberOfBands, kAudioUnitScope_Global, 0, &paramValue))
return;
size_t numberOfBands = paramValue ? 31 : 10;
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);
}
}
}
}
@interface AUPluginUI (Private)
- (BOOL)test_cocoa_view_support;
- (int)create_cocoa_view;
- (BOOL)plugin_class_valid:(Class)pluginClass;
@end
@implementation AUPluginUI
- (id)initWithSampler:(AudioUnit)_au bringToFront:(BOOL)front orWindowNumber:(NSInteger)window {
self = [super init];
if(self) {
au = _au;
windowOpen = NO;
cocoa_window = nil;
au_view = nil;
if([self test_cocoa_view_support]) {
[self create_cocoa_view];
}
if(au_view) {
cocoa_window = [[AUPluginWindow alloc] initWithAuView:au_view withAu:au bringToFront:front relativeToWindow:window];
if(cocoa_window) {
windowOpen = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowClosed:) name:NSWindowWillCloseNotification object:cocoa_window];
}
}
}
return self;
}
- (void)dealloc {
if(windowOpen) {
[self windowClosed:nil];
}
[cocoa_window close];
cocoa_window = nil;
au_view = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (BOOL)isOpen {
return windowOpen;
}
- (void)bringToFront {
[cocoa_window orderFront:cocoa_window];
}
- (void)windowClosed:(NSNotification *)notification {
[cocoa_window saveFrameUsingName:@"GraphicEQposition"];
[[NSNotificationCenter defaultCenter] removeObserver:self];
windowOpen = NO;
}
- (BOOL)test_cocoa_view_support {
UInt32 dataSize = 0;
Boolean isWritable = 0;
OSStatus err = AudioUnitGetPropertyInfo(au,
kAudioUnitProperty_CocoaUI, kAudioUnitScope_Global,
0, &dataSize, &isWritable);
return dataSize > 0 && err == noErr;
}
- (BOOL)plugin_class_valid:(Class)pluginClass {
if([pluginClass conformsToProtocol:@protocol(AUCocoaUIBase)]) {
if([pluginClass instancesRespondToSelector:@selector(interfaceVersion)] &&
[pluginClass instancesRespondToSelector:@selector(uiViewForAudioUnit:withSize:)]) {
return true;
}
}
return false;
}
- (int)create_cocoa_view {
bool wasAbleToLoadCustomView = false;
AudioUnitCocoaViewInfo *cocoaViewInfo = NULL;
UInt32 numberOfClasses = 0;
UInt32 dataSize;
Boolean isWritable;
NSString *factoryClassName = 0;
NSURL *CocoaViewBundlePath = NULL;
OSStatus result = AudioUnitGetPropertyInfo(au,
kAudioUnitProperty_CocoaUI,
kAudioUnitScope_Global,
0,
&dataSize,
&isWritable);
numberOfClasses = (dataSize - sizeof(CFURLRef)) / sizeof(CFStringRef);
// Does view have custom Cocoa UI?
if((result == noErr) && (numberOfClasses > 0)) {
cocoaViewInfo = (AudioUnitCocoaViewInfo *)malloc(dataSize);
if(AudioUnitGetProperty(au,
kAudioUnitProperty_CocoaUI,
kAudioUnitScope_Global,
0,
cocoaViewInfo,
&dataSize) == noErr) {
CocoaViewBundlePath = (__bridge NSURL *)cocoaViewInfo->mCocoaAUViewBundleLocation;
// we only take the first view in this example.
factoryClassName = (__bridge NSString *)cocoaViewInfo->mCocoaAUViewClass[0];
} else {
if(cocoaViewInfo != NULL) {
free(cocoaViewInfo);
cocoaViewInfo = NULL;
}
}
}
// [A] Show custom UI if view has it
if(CocoaViewBundlePath && factoryClassName) {
NSBundle *viewBundle = [NSBundle bundleWithPath:[CocoaViewBundlePath path]];
if(viewBundle == NULL) {
return -1;
} else {
Class factoryClass = [viewBundle classNamed:factoryClassName];
if(!factoryClass) {
return -1;
}
// make sure 'factoryClass' implements the AUCocoaUIBase protocol
if(![self plugin_class_valid:factoryClass]) {
return -1;
}
// make a factory
id factory = [[factoryClass alloc] init];
if(factory == NULL) {
return -1;
}
// make a view
au_view = [factory uiViewForAudioUnit:au withSize:NSZeroSize];
// cleanup
if(cocoaViewInfo) {
UInt32 i;
for(i = 0; i < numberOfClasses; i++)
CFRelease(cocoaViewInfo->mCocoaAUViewClass[i]);
free(cocoaViewInfo);
}
wasAbleToLoadCustomView = true;
}
}
if(!wasAbleToLoadCustomView) {
// load generic Cocoa view
au_view = [[AUGenericView alloc] initWithAudioUnit:au];
[(AUGenericView *)au_view setShowsExpertParameters:1];
}
return 0;
}
@end
@implementation AUPluginWindow
- (id)initWithAuView:(NSView *)_auView withAu:(AudioUnit)au bringToFront:(BOOL)front relativeToWindow:(NSInteger)window {
NSRect frame = [_auView frame];
CGFloat req_width = frame.size.width;
CGFloat req_height = frame.size.height;
// BOOL resizable = [_auView autoresizingMask];
self = [super initWithContentRect:NSMakeRect(0, 0, req_width, req_height + 32)
styleMask:(NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable)
backing:NSBackingStoreBuffered
defer:NO];
if(self) {
self->au = au;
auView = _auView;
[self setAutodisplay:YES];
[self setOneShot:YES];
[self setReleasedWhenClosed:NO];
NSRect topRect = NSMakeRect(0, 0, req_width, 32);
topView = [[NSView alloc] initWithFrame:topRect];
NSRect topFrame = NSMakeRect(0, req_height, req_width, topRect.size.height);
NSRect newFrame = NSMakeRect(0, 0, req_width, req_height);
topRect = NSMakeRect(0, 0, req_width, req_height + topRect.size.height);
splitView = [[NSSplitView alloc] initWithFrame:topRect];
[splitView setDividerStyle:NSSplitViewDividerStyleThin];
[splitView setSubviews:@[topView, auView]];
[self setContentView:splitView];
[topView setFrame:topFrame];
[auView setFrame:newFrame];
BOOL enabled = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"GraphicEQenable"];
NSButton *button = [NSButton checkboxWithTitle:@"Enabled" target:self action:@selector(toggleEnable:)];
[button setState:enabled ? NSControlStateValueOn : NSControlStateValueOff];
NSRect buttonFrame = [button frame];
buttonFrame.origin = NSMakePoint(18, 7);
[button setFrame:buttonFrame];
[topView addSubview:button];
enabled = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"GraphicEQtrackgenre"];
NSButton *trackButton = [NSButton checkboxWithTitle:@"Tracking genre tags" target:self action:@selector(toggleTracking:)];
[trackButton setState:enabled ? NSControlStateValueOn : NSControlStateValueOff];
NSRect trackButtonFrame = [trackButton frame];
trackButtonFrame.origin = NSMakePoint(buttonFrame.origin.x + buttonFrame.size.width + 4, 7);
[trackButton setFrame:trackButtonFrame];
[topView addSubview:trackButton];
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 = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] integerForKey:@"GraphicEQpreset"];
if(presetSelected < 0 || presetSelected >= [equalizer_presets_processed count])
presetSelected = [equalizer_presets_processed count];
[presetButton selectItemAtIndex:presetSelected];
equalizerLoadPreset(au);
NSTextField *presetLabel = [NSTextField labelWithString:@"Preset:"];
NSRect labelFrame = [presetLabel frame];
labelFrame.origin = NSMakePoint(popupFrame.origin.x - labelFrame.size.width - 2, 7);
[presetLabel setFrame:labelFrame];
[topView addSubview:presetLabel];
[splitView adjustSubviews];
[splitView setDelegate:self];
[self setFrameUsingName:@"GraphicEQposition"];
AUListenerCreateWithDispatchQueue(&listenerRef, 0.5, 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 savePresetToDefaults];
if([_self->presetButton indexOfSelectedItem] != [equalizer_presets_processed count]) {
[_self->presetButton selectItemAtIndex:[equalizer_presets_processed count]];
[_self changePreset:_self->presetButton];
}
} else if(inParameter->mParameterID == kGraphicEQParam_NumberOfBands) {
[_self changePreset:self->presetButton];
}
});
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, &param);
}
param.mParameterID = kGraphicEQParam_NumberOfBands;
AUListenerAddParameter(listenerRef, (__bridge void *)self, &param);
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.GraphicEQpreset" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:nil];
#if 0 // I have been told this makes the view look unbalanced, so whatevs
// Time to hack the auView
NSButton * flattenButton = nil;
NSPopUpButton * bandsButton = nil;
NSArray * views = [auView subviews];
for (NSView * view in views) {
if ([view isKindOfClass:[NSPopUpButton class]]) {
NSPopUpButton * popupButton = (NSPopUpButton *) view;
bandsButton = popupButton;
}
else if ([view isKindOfClass:[NSButton class]]) {
NSButton * button = (NSButton *) view;
flattenButton = button;
}
}
[flattenButton setHidden:YES];
// Hacking done, showing window
#endif
if(front) {
[self orderFront:self];
} else
[self orderWindow:NSWindowBelow relativeTo:window];
}
return self;
}
- (void)dealloc {
if(listenerRef) {
AUListenerDispose(listenerRef);
}
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.GraphicEQpreset" context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:@"values.GraphicEQpreset"]) {
NSInteger index = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] integerForKey:@"GraphicEQpreset"];
if(index < 0 || index > [equalizer_presets_processed count])
index = [equalizer_presets_processed count];
NSInteger selectedIndex = [presetButton indexOfSelectedItem];
// Don't want to get into an observe/modify loop here
if(selectedIndex != index) {
[presetButton selectItemAtIndex:index];
[self changePreset:presetButton];
}
}
}
- (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect ofDividerAtIndex:(NSInteger)dividerIndex {
return NSZeroRect;
}
- (void)toggleEnable:(id)sender {
BOOL enabled = [sender state] == NSControlStateValueOn;
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setBool:enabled forKey:@"GraphicEQenable"];
}
- (void)toggleTracking:(id)sender {
BOOL enabled = [sender state] == NSControlStateValueOn;
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setBool:enabled forKey:@"GraphicEQtrackgenre"];
equalizerApplyGenre(au, equalizerGenre);
[self changePreset:presetButton];
}
- (void)changePreset:(id)sender {
NSInteger index = [sender indexOfSelectedItem];
// Prevent circular application
if(index == [[[NSUserDefaultsController sharedUserDefaultsController] defaults] integerForKey:@"GraphicEQpreset"])
return;
if(index < [equalizer_presets_processed count]) {
NSDictionary *preset = [equalizer_presets_processed objectAtIndex:index];
equalizerApplyPreset(au, preset);
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];
[auView mouseUp:event];
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setInteger:index forKey:@"GraphicEQpreset"];
} else {
[[[NSUserDefaultsController sharedUserDefaultsController] defaults] setInteger:-1 forKey:@"GraphicEQpreset"];
}
}
- (void)savePresetToDefaults {
OSStatus err;
CFPropertyListRef classData;
UInt32 size;
size = sizeof(classData);
err = AudioUnitGetProperty(au, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, &size);
if(err == noErr) {
CFPreferencesSetAppValue(CFSTR("GraphEQ_Preset"), classData, kCFPreferencesCurrentApplication);
CFRelease(classData);
}
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
}
@end