Implemented real pitch and time shifting using Rubber Band
I will implement the more complex setup of providing options for most of the configuration that Rubber Band provides, at a later date, when I feel like creating a complex configuration dialog for it, and asking for help translating every option and setting. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
59f3f416ba
commit
9c6915ecb2
34 changed files with 2326 additions and 359 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -47,6 +47,7 @@ Xcode-config/DEVELOPMENT_TEAM.xcconfig
|
|||
/ThirdParty/ogg/lib/libogg.0.dylib
|
||||
/ThirdParty/opus/lib/libopus.0.dylib
|
||||
/ThirdParty/opusfile/lib/libopusfile.0.dylib
|
||||
/ThirdParty/rubberband/lib/librubberband.3.dylib
|
||||
/ThirdParty/speex/libspeex.a
|
||||
/ThirdParty/vorbis/lib/libvorbisfile.3.dylib
|
||||
/ThirdParty/vorbis/lib/libvorbis.0.dylib
|
||||
|
|
|
@ -19,8 +19,11 @@
|
|||
#define DEFAULT_VOLUME_DOWN 5
|
||||
#define DEFAULT_VOLUME_UP DEFAULT_VOLUME_DOWN
|
||||
|
||||
#define DEFAULT_SPEED_DOWN 0.2
|
||||
#define DEFAULT_SPEED_UP DEFAULT_SPEED_DOWN
|
||||
#define DEFAULT_PITCH_DOWN 0.2
|
||||
#define DEFAULT_PITCH_UP DEFAULT_PITCH_DOWN
|
||||
|
||||
#define DEFAULT_TEMPO_DOWN 0.2
|
||||
#define DEFAULT_TEMPO_UP DEFAULT_TEMPO_DOWN
|
||||
|
||||
extern NSString *CogPlaybackDidBeginNotificiation;
|
||||
extern NSString *CogPlaybackDidPauseNotificiation;
|
||||
|
@ -43,7 +46,9 @@ extern NSDictionary *makeRGInfo(PlaylistEntry *pe);
|
|||
IBOutlet EqualizerWindowController *equalizerWindowController;
|
||||
|
||||
IBOutlet NSSlider *volumeSlider;
|
||||
IBOutlet NSSlider *speedSlider;
|
||||
IBOutlet NSSlider *pitchSlider;
|
||||
IBOutlet NSSlider *tempoSlider;
|
||||
IBOutlet NSButton *lockButton;
|
||||
|
||||
IBOutlet NSArrayController *outputDevices;
|
||||
|
||||
|
@ -73,9 +78,13 @@ extern NSDictionary *makeRGInfo(PlaylistEntry *pe);
|
|||
- (IBAction)volumeDown:(id)sender;
|
||||
- (IBAction)volumeUp:(id)sender;
|
||||
|
||||
- (IBAction)changeSpeed:(id)sender;
|
||||
- (IBAction)speedDown:(id)sender;
|
||||
- (IBAction)speedUp:(id)sender;
|
||||
- (IBAction)changePitch:(id)sender;
|
||||
- (IBAction)pitchDown:(id)sender;
|
||||
- (IBAction)pitchUp:(id)sender;
|
||||
|
||||
- (IBAction)changeTempo:(id)sender;
|
||||
- (IBAction)tempoDown:(id)sender;
|
||||
- (IBAction)tempoUp:(id)sender;
|
||||
|
||||
- (IBAction)playPauseResume:(id)sender;
|
||||
- (IBAction)pauseResume:(id)sender;
|
||||
|
|
|
@ -91,7 +91,9 @@ NSString *CogPlaybackDidStopNotificiation = @"CogPlaybackDidStopNotificiation";
|
|||
|
||||
- (void)initDefaults {
|
||||
NSDictionary *defaultsDictionary = @{ @"volume": @(75.0),
|
||||
@"speed": @(1.0),
|
||||
@"pitch": @(1.0),
|
||||
@"tempo": @(1.0),
|
||||
@"speedLock": @(YES),
|
||||
@"GraphicEQenable": @(NO),
|
||||
@"GraphicEQpreset": @(-1),
|
||||
@"GraphicEQtrackgenre": @(NO),
|
||||
|
@ -101,6 +103,16 @@ NSString *CogPlaybackDidStopNotificiation = @"CogPlaybackDidStopNotificiation";
|
|||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary];
|
||||
}
|
||||
|
||||
static double speedScale(double input, double min, double max) {
|
||||
input = (input - min) * 100.0 / (max - min);
|
||||
return ((input * input) * (5.0 - 0.2) / 10000.0) + 0.2;
|
||||
}
|
||||
|
||||
static double reverseSpeedScale(double input, double min, double max) {
|
||||
input = sqrtf((input - 0.2) * 10000.0 / (5.0 - 0.2));
|
||||
return (input * (max - min) / 100.0) + min;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
||||
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
||||
|
@ -110,8 +122,15 @@ NSString *CogPlaybackDidStopNotificiation = @"CogPlaybackDidStopNotificiation";
|
|||
[volumeSlider setDoubleValue:logarithmicToLinear(volume, MAX_VOLUME)];
|
||||
[audioPlayer setVolume:volume];
|
||||
|
||||
double speed = [[NSUserDefaults standardUserDefaults] doubleForKey:@"speed"];
|
||||
[audioPlayer setSpeed:speed];
|
||||
double pitch = [[NSUserDefaults standardUserDefaults] doubleForKey:@"pitch"];
|
||||
[audioPlayer setPitch:pitch];
|
||||
[pitchSlider setDoubleValue:reverseSpeedScale(pitch, [pitchSlider minValue], [pitchSlider maxValue])];
|
||||
double tempo = [[NSUserDefaults standardUserDefaults] doubleForKey:@"tempo"];
|
||||
[audioPlayer setTempo:tempo];
|
||||
[tempoSlider setDoubleValue:reverseSpeedScale(tempo, [tempoSlider minValue], [tempoSlider maxValue])];
|
||||
|
||||
BOOL speedLock = [[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"];
|
||||
[lockButton setTitle:speedLock ? @"🔒" : @"🔓"];
|
||||
|
||||
[self setSeekable:NO];
|
||||
}
|
||||
|
@ -253,7 +272,7 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
|
|||
|
||||
#if 0
|
||||
// Race here, but the worst that could happen is we re-read the data
|
||||
if ([pe metadataLoaded] != YES) {
|
||||
if([pe metadataLoaded] != YES) {
|
||||
[pe performSelectorOnMainThread:@selector(setMetadata:) withObject:[playlistLoader readEntryInfo:pe] waitUntilDone:YES];
|
||||
}
|
||||
#elif 0
|
||||
|
@ -381,7 +400,7 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
|
|||
NSImage *img = [NSImage imageNamed:name];
|
||||
// [img retain];
|
||||
|
||||
if (img == nil)
|
||||
if(img == nil)
|
||||
{
|
||||
DLog(@"Error loading image!");
|
||||
}
|
||||
|
@ -482,12 +501,34 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
|
|||
}
|
||||
}
|
||||
|
||||
- (IBAction)changeSpeed:(id)sender {
|
||||
DLog(@"SPEED: %lf", [sender doubleValue]);
|
||||
- (IBAction)changePitch:(id)sender {
|
||||
const double pitch = speedScale([sender doubleValue], [pitchSlider minValue], [pitchSlider maxValue]);
|
||||
DLog(@"PITCH: %lf", pitch);
|
||||
|
||||
[audioPlayer setSpeed:[sender doubleValue]];
|
||||
[audioPlayer setPitch:pitch];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer speed] forKey:@"speed"];
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer pitch] forKey:@"pitch"];
|
||||
|
||||
if([[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"]) {
|
||||
[audioPlayer setTempo:pitch];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer tempo] forKey:@"tempo"];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)changeTempo:(id)sender {
|
||||
const double tempo = speedScale([sender doubleValue], [tempoSlider minValue], [tempoSlider maxValue]);
|
||||
DLog(@"TEMPO: %lf", tempo);
|
||||
|
||||
[audioPlayer setTempo:tempo];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer tempo] forKey:@"tempo"];
|
||||
|
||||
if([[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"]) {
|
||||
[audioPlayer setPitch:tempo];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer pitch] forKey:@"pitch"];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)skipToNextAlbum:(id)sender {
|
||||
|
@ -591,18 +632,64 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
|
|||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer volume] forKey:@"volume"];
|
||||
}
|
||||
|
||||
- (IBAction)speedDown:(id)sender {
|
||||
double newSpeed = [audioPlayer speedDown:DEFAULT_SPEED_DOWN];
|
||||
[speedSlider setDoubleValue:[audioPlayer speed]];
|
||||
- (IBAction)pitchDown:(id)sender {
|
||||
/*double newPitch = */[audioPlayer pitchDown:DEFAULT_PITCH_DOWN];
|
||||
[pitchSlider setDoubleValue:reverseSpeedScale([audioPlayer pitch], [pitchSlider minValue], [pitchSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer speed] forKey:@"speed"];
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer pitch] forKey:@"pitch"];
|
||||
|
||||
if([[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"]) {
|
||||
[audioPlayer setTempo:[audioPlayer pitch]];
|
||||
|
||||
[tempoSlider setDoubleValue:reverseSpeedScale([audioPlayer tempo], [tempoSlider minValue], [tempoSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer tempo] forKey:@"tempo"];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)speedUp:(id)sender {
|
||||
double newSpeed = [audioPlayer speedUp:DEFAULT_SPEED_UP];
|
||||
[speedSlider setDoubleValue:[audioPlayer speed]];
|
||||
- (IBAction)pitchUp:(id)sender {
|
||||
/*double newPitch = */[audioPlayer tempoUp:DEFAULT_PITCH_UP];
|
||||
[pitchSlider setDoubleValue:reverseSpeedScale([audioPlayer pitch], [pitchSlider minValue], [pitchSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer speed] forKey:@"speed"];
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer pitch] forKey:@"pitch"];
|
||||
|
||||
if([[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"]) {
|
||||
[audioPlayer setTempo:[audioPlayer pitch]];
|
||||
|
||||
[tempoSlider setDoubleValue:reverseSpeedScale([audioPlayer tempo], [tempoSlider minValue], [tempoSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer tempo] forKey:@"tempo"];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)tempoDown:(id)sender {
|
||||
/*double newTempo = */[audioPlayer tempoDown:DEFAULT_TEMPO_DOWN];
|
||||
[tempoSlider setDoubleValue:reverseSpeedScale([audioPlayer tempo], [tempoSlider minValue], [tempoSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer tempo] forKey:@"tempo"];
|
||||
|
||||
if([[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"]) {
|
||||
[audioPlayer setPitch:[audioPlayer tempo]];
|
||||
|
||||
[pitchSlider setDoubleValue:reverseSpeedScale([audioPlayer pitch], [pitchSlider minValue], [pitchSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer pitch] forKey:@"pitch"];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)tempoUp:(id)sender {
|
||||
/*double newTempo = */[audioPlayer tempoUp:DEFAULT_PITCH_UP];
|
||||
[tempoSlider setDoubleValue:reverseSpeedScale([audioPlayer tempo], [tempoSlider minValue], [tempoSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer tempo] forKey:@"tempo"];
|
||||
|
||||
if([[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"]) {
|
||||
[audioPlayer setPitch:[audioPlayer tempo]];
|
||||
|
||||
[pitchSlider setDoubleValue:reverseSpeedScale([audioPlayer pitch], [pitchSlider minValue], [pitchSlider maxValue])];
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer pitch] forKey:@"pitch"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)audioPlayer:(AudioPlayer *)player displayEqualizer:(AudioUnit)eq {
|
||||
|
@ -764,7 +851,7 @@ NSDictionary *makeRGInfo(PlaylistEntry *pe) {
|
|||
|
||||
- (void)audioPlayer:(AudioPlayer *)player pushInfo:(NSDictionary *)info toTrack:(id)userInfo {
|
||||
PlaylistEntry *pe = (PlaylistEntry *)userInfo;
|
||||
if (!pe) pe = [playlistController currentEntry];
|
||||
if(!pe) pe = [playlistController currentEntry];
|
||||
[pe setMetadata:info];
|
||||
[playlistView refreshTrack:pe];
|
||||
// Delay the action until this function has returned to the audio thread
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
OutputNode *output;
|
||||
|
||||
double volume;
|
||||
double speed;
|
||||
double pitch;
|
||||
double tempo;
|
||||
|
||||
NSMutableArray *chainQueue;
|
||||
|
||||
|
@ -75,10 +76,15 @@
|
|||
- (double)volumeUp:(double)amount;
|
||||
- (double)volumeDown:(double)amount;
|
||||
|
||||
- (void)setSpeed:(double)s;
|
||||
- (double)speed;
|
||||
- (double)speedUp:(double)amount;
|
||||
- (double)speedDown:(double)amount;
|
||||
- (void)setPitch:(double)s;
|
||||
- (double)pitch;
|
||||
- (double)pitchUp:(double)amount;
|
||||
- (double)pitchDown:(double)amount;
|
||||
|
||||
- (void)setTempo:(double)s;
|
||||
- (double)tempo;
|
||||
- (double)tempoUp:(double)amount;
|
||||
- (double)tempoDown:(double)amount;
|
||||
|
||||
- (double)amountPlayed;
|
||||
- (double)amountPlayedInterval;
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
outputLaunched = NO;
|
||||
endOfInputReached = NO;
|
||||
|
||||
// Safety
|
||||
pitch = 1.0;
|
||||
tempo = 1.0;
|
||||
|
||||
chainQueue = [[NSMutableArray alloc] init];
|
||||
|
||||
semaphore = [[Semaphore alloc] init];
|
||||
|
@ -75,7 +79,8 @@
|
|||
}
|
||||
[output setup];
|
||||
[output setVolume:volume];
|
||||
[output setSpeed:speed];
|
||||
[output setPitch:pitch];
|
||||
[output setTempo:tempo];
|
||||
@synchronized(chainQueue) {
|
||||
for(id anObject in chainQueue) {
|
||||
[anObject setShouldContinue:NO];
|
||||
|
@ -211,14 +216,24 @@
|
|||
return volume;
|
||||
}
|
||||
|
||||
- (void)setSpeed:(double)s {
|
||||
speed = s;
|
||||
- (void)setPitch:(double)p {
|
||||
pitch = p;
|
||||
|
||||
[output setSpeed:s];
|
||||
[output setPitch:p];
|
||||
}
|
||||
|
||||
- (double)speed {
|
||||
return speed;
|
||||
- (double)pitch {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
- (void)setTempo:(double)t {
|
||||
tempo = t;
|
||||
|
||||
[output setTempo:t];
|
||||
}
|
||||
|
||||
- (double)tempo {
|
||||
return tempo;
|
||||
}
|
||||
|
||||
// This is called by the delegate DURING a requestNextStream request.
|
||||
|
@ -659,30 +674,56 @@
|
|||
return newVolume;
|
||||
}
|
||||
|
||||
- (double)speedUp:(double)amount {
|
||||
const double MAX_SPEED = 5.0;
|
||||
- (double)pitchUp:(double)amount {
|
||||
const double MAX_PITCH = 5.0;
|
||||
|
||||
double newSpeed;
|
||||
if((speed + amount) > MAX_SPEED)
|
||||
newSpeed = MAX_SPEED;
|
||||
double newPitch;
|
||||
if((pitch + amount) > MAX_PITCH)
|
||||
newPitch = MAX_PITCH;
|
||||
else
|
||||
newSpeed = speed + amount;
|
||||
newPitch = pitch + amount;
|
||||
|
||||
[self setSpeed:newSpeed];
|
||||
return newSpeed;
|
||||
[self setPitch:newPitch];
|
||||
return newPitch;
|
||||
}
|
||||
|
||||
- (double)speedDown:(double)amount {
|
||||
const double MIN_SPEED = 0.2;
|
||||
- (double)pitchDown:(double)amount {
|
||||
const double MIN_PITCH = 0.2;
|
||||
|
||||
double newSpeed;
|
||||
if((speed - amount) < MIN_SPEED)
|
||||
newSpeed = MIN_SPEED;
|
||||
double newPitch;
|
||||
if((pitch - amount) < MIN_PITCH)
|
||||
newPitch = MIN_PITCH;
|
||||
else
|
||||
newSpeed = speed - amount;
|
||||
newPitch = pitch - amount;
|
||||
|
||||
[self setSpeed:newSpeed];
|
||||
return newSpeed;
|
||||
[self setPitch:newPitch];
|
||||
return newPitch;
|
||||
}
|
||||
|
||||
- (double)tempoUp:(double)amount {
|
||||
const double MAX_TEMPO = 5.0;
|
||||
|
||||
double newTempo;
|
||||
if((tempo + amount) > MAX_TEMPO)
|
||||
newTempo = MAX_TEMPO;
|
||||
else
|
||||
newTempo = tempo + amount;
|
||||
|
||||
[self setTempo:newTempo];
|
||||
return newTempo;
|
||||
}
|
||||
|
||||
- (double)tempoDown:(double)amount {
|
||||
const double MIN_TEMPO = 0.2;
|
||||
|
||||
double newTempo;
|
||||
if((tempo - amount) < MIN_TEMPO)
|
||||
newTempo = MIN_TEMPO;
|
||||
else
|
||||
newTempo = tempo - amount;
|
||||
|
||||
[self setTempo:newTempo];
|
||||
return newTempo;
|
||||
}
|
||||
|
||||
- (void)waitUntilCallbacksExit {
|
||||
|
|
|
@ -61,7 +61,8 @@
|
|||
|
||||
- (void)setVolume:(double)v;
|
||||
|
||||
- (void)setSpeed:(double)s;
|
||||
- (void)setPitch:(double)p;
|
||||
- (void)setTempo:(double)t;
|
||||
|
||||
- (void)setShouldContinue:(BOOL)s;
|
||||
|
||||
|
|
|
@ -164,8 +164,12 @@
|
|||
[output setVolume:v];
|
||||
}
|
||||
|
||||
- (void)setSpeed:(double)s {
|
||||
[output setSpeed:s];
|
||||
- (void)setPitch:(double)p {
|
||||
[output setPitch:p];
|
||||
}
|
||||
|
||||
- (void)setTempo:(double)t {
|
||||
[output setTempo:t];
|
||||
}
|
||||
|
||||
- (void)setShouldContinue:(BOOL)s {
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
8377C64C27B8C51500E8BC0F /* fft_accelerate.c in Sources */ = {isa = PBXBuildFile; fileRef = 8377C64B27B8C51500E8BC0F /* fft_accelerate.c */; };
|
||||
8377C64E27B8C54400E8BC0F /* fft.h in Headers */ = {isa = PBXBuildFile; fileRef = 8377C64D27B8C54400E8BC0F /* fft.h */; };
|
||||
8384912718080FF100E7332D /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384912618080FF100E7332D /* Logging.h */; };
|
||||
838A33722D06A97D00D0D770 /* librubberband.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 838A33712D06A97D00D0D770 /* librubberband.3.dylib */; };
|
||||
839065F32853338700636FBB /* dsd2float.h in Headers */ = {isa = PBXBuildFile; fileRef = 839065F22853338700636FBB /* dsd2float.h */; };
|
||||
839366671815923C006DD712 /* CogPluginMulti.h in Headers */ = {isa = PBXBuildFile; fileRef = 839366651815923C006DD712 /* CogPluginMulti.h */; };
|
||||
839366681815923C006DD712 /* CogPluginMulti.m in Sources */ = {isa = PBXBuildFile; fileRef = 839366661815923C006DD712 /* CogPluginMulti.m */; };
|
||||
|
@ -192,6 +193,7 @@
|
|||
8377C64B27B8C51500E8BC0F /* fft_accelerate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fft_accelerate.c; sourceTree = "<group>"; };
|
||||
8377C64D27B8C54400E8BC0F /* fft.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fft.h; sourceTree = "<group>"; };
|
||||
8384912618080FF100E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||
838A33712D06A97D00D0D770 /* librubberband.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = librubberband.3.dylib; path = ../ThirdParty/rubberband/lib/librubberband.3.dylib; sourceTree = SOURCE_ROOT; };
|
||||
839065F22853338700636FBB /* dsd2float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsd2float.h; sourceTree = "<group>"; };
|
||||
839366651815923C006DD712 /* CogPluginMulti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogPluginMulti.h; sourceTree = "<group>"; };
|
||||
839366661815923C006DD712 /* CogPluginMulti.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CogPluginMulti.m; sourceTree = "<group>"; };
|
||||
|
@ -233,6 +235,7 @@
|
|||
17D21DAE0B8BE76800D1EBDE /* AudioUnit.framework in Frameworks */,
|
||||
17D21DAF0B8BE76800D1EBDE /* CoreAudio.framework in Frameworks */,
|
||||
17D21DB00B8BE76800D1EBDE /* CoreAudioKit.framework in Frameworks */,
|
||||
838A33722D06A97D00D0D770 /* librubberband.3.dylib in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -324,6 +327,7 @@
|
|||
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
838A33712D06A97D00D0D770 /* librubberband.3.dylib */,
|
||||
836DF615298F6E8900CD0580 /* libsoxr.0.dylib */,
|
||||
83725A7B27AA0D8A0003F694 /* Accelerate.framework */,
|
||||
17D21DAA0B8BE76800D1EBDE /* AudioUnit.framework */,
|
||||
|
@ -693,11 +697,18 @@
|
|||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
|
||||
HEADER_SEARCH_PATHS = ../ThirdParty/soxr/include;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../ThirdParty/soxr/include,
|
||||
../ThirdParty/rubberband/include,
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "@executable_path/../Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = ../ThirdParty/soxr/lib;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
../ThirdParty/rubberband/lib,
|
||||
../ThirdParty/soxr/lib,
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
|
||||
PRODUCT_NAME = CogAudio;
|
||||
|
@ -724,11 +735,18 @@
|
|||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "";
|
||||
HEADER_SEARCH_PATHS = ../ThirdParty/soxr/include;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../ThirdParty/soxr/include,
|
||||
../ThirdParty/rubberband/include,
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "@executable_path/../Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = ../ThirdParty/soxr/lib;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
../ThirdParty/rubberband/lib,
|
||||
../ThirdParty/soxr/lib,
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
|
||||
PRODUCT_NAME = CogAudio;
|
||||
|
|
|
@ -35,8 +35,6 @@ using std::atomic_long;
|
|||
#import <stdio.h>
|
||||
#endif
|
||||
|
||||
#import <soxr.h>
|
||||
|
||||
@class OutputNode;
|
||||
|
||||
@class FSurroundFilter;
|
||||
|
@ -56,7 +54,8 @@ using std::atomic_long;
|
|||
|
||||
double lastClippedSampleRate;
|
||||
|
||||
soxr_t rssimplespeed;
|
||||
void *ts;
|
||||
size_t blockSize, toDrop, samplesBuffered;
|
||||
double ssRenderedIn, ssLastRenderedIn;
|
||||
double ssRenderedOut;
|
||||
|
||||
|
@ -90,8 +89,8 @@ using std::atomic_long;
|
|||
float volume;
|
||||
float eqPreamp;
|
||||
|
||||
double speed;
|
||||
double lastSpeed;
|
||||
double pitch, tempo;
|
||||
double lastPitch, lastTempo;
|
||||
|
||||
AVAudioFormat *_deviceFormat;
|
||||
|
||||
|
@ -139,7 +138,9 @@ using std::atomic_long;
|
|||
|
||||
float *samplePtr;
|
||||
float tempBuffer[512 * 32];
|
||||
float rsInBuffer[8192 * 32];
|
||||
float *rsPtrs[32];
|
||||
float rsInBuffer[1024 * 32];
|
||||
float rsOutBuffer[65536 * 32];
|
||||
float inputBuffer[4096 * 32]; // 4096 samples times maximum supported channel count
|
||||
float fsurroundBuffer[8192 * 6];
|
||||
float hrtfBuffer[4096 * 2];
|
||||
|
@ -182,6 +183,7 @@ using std::atomic_long;
|
|||
|
||||
- (void)reportMotion:(simd_float4x4)matrix;
|
||||
|
||||
- (void)setSpeed:(double)s;
|
||||
- (void)setPitch:(double)p;
|
||||
- (void)setTempo:(double)t;
|
||||
|
||||
@end
|
||||
|
|
|
@ -23,12 +23,16 @@
|
|||
|
||||
#import "FSurroundFilter.h"
|
||||
|
||||
#import <rubberband/rubberband-c.h>
|
||||
|
||||
#define OCTAVES 5
|
||||
|
||||
extern void scale_by_volume(float *buffer, size_t count, float volume);
|
||||
|
||||
static NSString *CogPlaybackDidBeginNotificiation = @"CogPlaybackDidBeginNotificiation";
|
||||
|
||||
#define tts ((RubberBandState)ts)
|
||||
|
||||
simd_float4x4 convertMatrix(CMRotationMatrix r) {
|
||||
simd_float4x4 matrix = {
|
||||
simd_make_float4(r.m33, -r.m31, r.m32, 0.0f),
|
||||
|
@ -110,7 +114,7 @@ static void fillBuffers(AudioBufferList *ioData, const float *inbuffer, size_t c
|
|||
|
||||
static void clearBuffers(AudioBufferList *ioData, size_t count, size_t offset) {
|
||||
for(int i = 0; i < ioData->mNumberBuffers; ++i) {
|
||||
memset(ioData->mBuffers[i].mData + offset * sizeof(float), 0, count * sizeof(float));
|
||||
memset((uint8_t *)ioData->mBuffers[i].mData + offset * sizeof(float), 0, count * sizeof(float));
|
||||
ioData->mBuffers[i].mNumberChannels = 1;
|
||||
}
|
||||
}
|
||||
|
@ -338,8 +342,8 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
|
|||
|
||||
outputLock = [[NSLock alloc] init];
|
||||
|
||||
speed = 1.0;
|
||||
lastSpeed = 1.0;
|
||||
pitch = 1.0; tempo = 1.0;
|
||||
lastPitch = 1.0; lastTempo = 1.0;
|
||||
|
||||
#ifdef OUTPUT_LOG
|
||||
NSString *logName = [NSTemporaryDirectory() stringByAppendingPathComponent:@"CogAudioLog.raw"];
|
||||
|
@ -352,21 +356,21 @@ static OSStatus eqRenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioA
|
|||
|
||||
static OSStatus
|
||||
default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData) {
|
||||
OutputCoreAudio *this = (__bridge OutputCoreAudio *)inUserData;
|
||||
return [this setOutputDeviceByID:-1];
|
||||
OutputCoreAudio *_self = (__bridge OutputCoreAudio *)inUserData;
|
||||
return [_self setOutputDeviceByID:-1];
|
||||
}
|
||||
|
||||
static OSStatus
|
||||
current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData) {
|
||||
OutputCoreAudio *this = (__bridge OutputCoreAudio *)inUserData;
|
||||
OutputCoreAudio *_self = (__bridge OutputCoreAudio *)inUserData;
|
||||
for(UInt32 i = 0; i < inNumberAddresses; ++i) {
|
||||
switch(inAddresses[i].mSelector) {
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
return [this setOutputDeviceByID:-1];
|
||||
return [_self setOutputDeviceByID:-1];
|
||||
|
||||
case kAudioDevicePropertyNominalSampleRate:
|
||||
case kAudioDevicePropertyStreamFormat:
|
||||
this->outputdevicechanged = YES;
|
||||
_self->outputdevicechanged = YES;
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
|
@ -611,7 +615,7 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
|||
|
||||
__Verify_noErr(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &theAddress, 0, NULL, &propsize));
|
||||
UInt32 nDevices = propsize / (UInt32)sizeof(AudioDeviceID);
|
||||
AudioDeviceID *devids = malloc(propsize);
|
||||
AudioDeviceID *devids = (AudioDeviceID *)malloc(propsize);
|
||||
__Verify_noErr(AudioObjectGetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, &propsize, devids));
|
||||
|
||||
theAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
|
||||
|
@ -812,14 +816,35 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
|||
[outputLock unlock];
|
||||
}
|
||||
|
||||
if(rssimplespeed) {
|
||||
soxr_delete(rssimplespeed);
|
||||
if(ts) {
|
||||
rubberband_delete(tts);
|
||||
ts = NULL;
|
||||
}
|
||||
|
||||
soxr_error_t error;
|
||||
soxr_quality_spec_t q_spec = soxr_quality_spec(SOXR_HQ, SOXR_VR);
|
||||
rssimplespeed = soxr_create(1 << OCTAVES, 1, realStreamFormat.mChannelsPerFrame, &error, NULL, &q_spec, NULL);
|
||||
soxr_set_io_ratio(rssimplespeed, speed, 0);
|
||||
RubberBandOptions options = RubberBandOptionProcessRealTime;
|
||||
ts = rubberband_new(realStreamFormat.mSampleRate, realStreamFormat.mChannelsPerFrame, options, 1.0 / tempo, pitch);
|
||||
|
||||
blockSize = 1024;
|
||||
toDrop = rubberband_get_start_delay(tts);
|
||||
samplesBuffered = 0;
|
||||
rubberband_set_max_process_size(tts, (int)blockSize);
|
||||
|
||||
for(size_t i = 0; i < 32; ++i) {
|
||||
rsPtrs[i] = &rsInBuffer[1024 * i];
|
||||
}
|
||||
|
||||
size_t toPad = rubberband_get_preferred_start_pad(tts);
|
||||
if(toPad > 0) {
|
||||
for(size_t i = 0; i < realStreamFormat.mChannelsPerFrame; ++i) {
|
||||
memset(rsPtrs[i], 0, 1024 * sizeof(float));
|
||||
}
|
||||
while(toPad > 0) {
|
||||
size_t p = toPad;
|
||||
if(p > blockSize) p = blockSize;
|
||||
rubberband_process(tts, (const float * const *)rsPtrs, (int)p, false);
|
||||
toPad -= p;
|
||||
}
|
||||
}
|
||||
|
||||
ssRenderedIn = 0.0;
|
||||
ssLastRenderedIn = 0.0;
|
||||
|
@ -951,37 +976,65 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
|||
int simpleSpeedInput = samplesRendered;
|
||||
int simpleSpeedRendered = 0;
|
||||
int channels = realStreamFormat.mChannelsPerFrame;
|
||||
int max_block_len = 8192;
|
||||
size_t max_block_len = blockSize;
|
||||
|
||||
if (fabs(speed - lastSpeed) > 1e-5) {
|
||||
lastSpeed = speed;
|
||||
soxr_set_io_ratio(rssimplespeed, speed, max_block_len);
|
||||
if (fabs(pitch - lastPitch) > 1e-5 ||
|
||||
fabs(tempo - lastTempo) > 1e-5) {
|
||||
lastPitch = pitch;
|
||||
lastTempo = tempo;
|
||||
rubberband_set_pitch_scale(tts, pitch);
|
||||
rubberband_set_time_ratio(tts, 1.0 / tempo);
|
||||
}
|
||||
|
||||
const double inputRatio = 1.0 / realStreamFormat.mSampleRate;
|
||||
const double outputRatio = inputRatio * speed;
|
||||
const double outputRatio = inputRatio * tempo;
|
||||
|
||||
while (simpleSpeedInput > 0) {
|
||||
int block_len = max_block_len - simpleSpeedRendered;
|
||||
|
||||
if (!block_len)
|
||||
break;
|
||||
|
||||
float *ibuf = samplePtr;
|
||||
int len = simpleSpeedInput;
|
||||
float *obuf = &rsInBuffer[simpleSpeedRendered * channels];
|
||||
size_t idone = 0;
|
||||
size_t odone = 0;
|
||||
int error = soxr_process(rssimplespeed, ibuf, len, &idone, obuf, block_len, &odone);
|
||||
simpleSpeedInput -= idone;
|
||||
ibuf += channels * idone;
|
||||
simpleSpeedRendered += odone;
|
||||
ssRenderedIn += idone * inputRatio;
|
||||
ssRenderedOut += odone * outputRatio;
|
||||
size_t len = simpleSpeedInput;
|
||||
if(len > blockSize) len = blockSize;
|
||||
|
||||
for(size_t i = 0; i < channels; ++i) {
|
||||
cblas_scopy((int)len, ibuf + i, channels, rsPtrs[i], 1);
|
||||
}
|
||||
|
||||
rubberband_process(tts, (const float * const *)rsPtrs, (int)len, false);
|
||||
|
||||
simpleSpeedInput -= len;
|
||||
ibuf += len * channels;
|
||||
ssRenderedIn += len * inputRatio;
|
||||
|
||||
size_t samplesAvailable;
|
||||
while ((samplesAvailable = rubberband_available(tts)) > 0) {
|
||||
if(toDrop > 0) {
|
||||
size_t blockDrop = toDrop;
|
||||
if(blockDrop > blockSize) blockDrop = blockSize;
|
||||
rubberband_retrieve(tts, (float * const *)rsPtrs, (int)blockDrop);
|
||||
toDrop -= blockDrop;
|
||||
continue;
|
||||
}
|
||||
size_t maxAvailable = 65536 - samplesBuffered;
|
||||
if(samplesAvailable > maxAvailable) {
|
||||
samplesAvailable = maxAvailable;
|
||||
if(!samplesAvailable) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
size_t samplesOut = samplesAvailable;
|
||||
if(samplesOut > blockSize) samplesOut = blockSize;
|
||||
rubberband_retrieve(tts, (float * const *)rsPtrs, (int)samplesOut);
|
||||
for(size_t i = 0; i < channels; ++i) {
|
||||
cblas_scopy((int)samplesOut, rsPtrs[i], 1, &rsOutBuffer[samplesBuffered * channels + i], channels);
|
||||
}
|
||||
samplesBuffered += samplesOut;
|
||||
ssRenderedOut += samplesOut * outputRatio;
|
||||
simpleSpeedRendered += samplesOut;
|
||||
}
|
||||
samplePtr = ibuf;
|
||||
}
|
||||
samplePtr = &rsInBuffer[0];
|
||||
samplePtr = &rsOutBuffer[0];
|
||||
samplesRendered = simpleSpeedRendered;
|
||||
samplesBuffered = 0;
|
||||
}
|
||||
[outputLock lock];
|
||||
if(fsurround) {
|
||||
|
@ -1288,8 +1341,12 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
|||
volume = v * 0.01f;
|
||||
}
|
||||
|
||||
- (void)setSpeed:(double)s {
|
||||
speed = s;
|
||||
- (void)setPitch:(double)p {
|
||||
pitch = p;
|
||||
}
|
||||
|
||||
- (void)setTempo:(double)t {
|
||||
tempo = t;
|
||||
}
|
||||
|
||||
- (void)setEqualizerEnabled:(BOOL)enabled {
|
||||
|
@ -1406,9 +1463,9 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
|
|||
rsstate_delete(rsvis);
|
||||
rsvis = NULL;
|
||||
}
|
||||
if(rssimplespeed) {
|
||||
soxr_delete(rssimplespeed);
|
||||
rssimplespeed = NULL;
|
||||
if(ts) {
|
||||
rubberband_delete(tts);
|
||||
ts = NULL;
|
||||
}
|
||||
stopCompleted = YES;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23094" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23094"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
@ -25,17 +25,17 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<splitView dividerStyle="thin" vertical="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2123">
|
||||
<rect key="frame" x="0.0" y="334" width="1186" height="66"/>
|
||||
<rect key="frame" x="0.0" y="328" width="1205" height="72"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="24" horizontalPageScroll="0.0" verticalLineScroll="24" verticalPageScroll="0.0" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="206" userLabel="Scroll View - Playlist View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1186" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1217" height="72"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="KWC-Ti-8KY">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1186" height="66"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1217" height="72"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" alternatingRowBackgroundColors="YES" autosaveName="Playlist" rowHeight="18" headerView="1517" viewBased="YES" id="207" customClass="PlaylistView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1186" height="49"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1217" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="6"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -57,7 +57,7 @@
|
|||
<rect key="frame" x="11" y="3" width="69" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="w5u-JQ-3Hf">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="w5u-JQ-3Hf">
|
||||
<rect key="frame" x="0.0" y="1" width="69" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="right" title="Table View Cell" id="FMU-QZ-NdQ">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -102,7 +102,7 @@
|
|||
<rect key="frame" x="0.0" y="3" width="17" height="11"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="8rO-fU-Njw"/>
|
||||
</imageView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5cp-JI-ogI">
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5cp-JI-ogI">
|
||||
<rect key="frame" x="23" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="wky-z8-Cj5">
|
||||
<font key="font" metaFont="system"/>
|
||||
|
@ -127,7 +127,7 @@
|
|||
</tableCellView>
|
||||
</prototypeCellViews>
|
||||
</tableColumn>
|
||||
<tableColumn identifier="rating" editable="NO" width="109" minWidth="48" maxWidth="128" id="208" userLabel="Rating">
|
||||
<tableColumn identifier="rating" editable="NO" width="116" minWidth="48" maxWidth="128" id="208" userLabel="Rating">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Rating">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
@ -141,11 +141,11 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="ZCP-Dx-UBV">
|
||||
<rect key="frame" x="106" y="3" width="109" height="18"/>
|
||||
<rect key="frame" x="106" y="3" width="116" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="exY-Bg-Mjm">
|
||||
<rect key="frame" x="0.0" y="1" width="109" height="16"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="exY-Bg-Mjm">
|
||||
<rect key="frame" x="0.0" y="1" width="116" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="sdo-Sm-KPH">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -171,7 +171,7 @@
|
|||
</binding>
|
||||
</connections>
|
||||
</tableColumn>
|
||||
<tableColumn identifier="title" editable="NO" width="171" minWidth="96" maxWidth="1024" id="XBr-ec-D81">
|
||||
<tableColumn identifier="title" editable="NO" width="177.5" minWidth="96" maxWidth="1024" id="XBr-ec-D81">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Title">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
@ -185,11 +185,11 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="ZHl-H1-IIC">
|
||||
<rect key="frame" x="218" y="3" width="171" height="18"/>
|
||||
<rect key="frame" x="225" y="3" width="178" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="dQP-wC-mba">
|
||||
<rect key="frame" x="0.0" y="1" width="171" height="16"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="dQP-wC-mba">
|
||||
<rect key="frame" x="0.0" y="1" width="178" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="VVx-99-roJ">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -231,7 +231,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="ZWb-jm-i9i">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="ZWb-jm-i9i">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="3QN-Ok-QPu">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -259,7 +259,7 @@
|
|||
<binding destination="1689" name="fontSize" keyPath="values.fontSize" id="dJs-UO-m5r"/>
|
||||
</connections>
|
||||
</tableColumn>
|
||||
<tableColumn identifier="artist" editable="NO" width="195" minWidth="96" maxWidth="1024" id="391">
|
||||
<tableColumn identifier="artist" editable="NO" width="200.5" minWidth="96" maxWidth="1024" id="391">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Artist">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -273,11 +273,11 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="gpC-Oe-Rog">
|
||||
<rect key="frame" x="392" y="3" width="195" height="18"/>
|
||||
<rect key="frame" x="406" y="3" width="200" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="1WK-qN-Mgj">
|
||||
<rect key="frame" x="0.0" y="1" width="195" height="16"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="1WK-qN-Mgj">
|
||||
<rect key="frame" x="0.0" y="1" width="200" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="71l-3L-S3g">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -320,7 +320,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="4cz-aa-d2B">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="4cz-aa-d2B">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="DDa-1D-XYS">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -347,7 +347,7 @@
|
|||
</binding>
|
||||
</connections>
|
||||
</tableColumn>
|
||||
<tableColumn identifier="album" editable="NO" width="195.5" minWidth="96" maxWidth="1024" id="806">
|
||||
<tableColumn identifier="album" editable="NO" width="201" minWidth="96" maxWidth="1024" id="806">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Album">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -361,11 +361,11 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="1ed-gX-bct">
|
||||
<rect key="frame" x="590" y="3" width="196" height="18"/>
|
||||
<rect key="frame" x="609" y="3" width="201" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="nEt-s5-vRX">
|
||||
<rect key="frame" x="0.0" y="1" width="196" height="16"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="nEt-s5-vRX">
|
||||
<rect key="frame" x="0.0" y="1" width="201" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="moV-3G-GpB">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -404,10 +404,10 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="hhB-nv-e78">
|
||||
<rect key="frame" x="788.5" y="3" width="96" height="18"/>
|
||||
<rect key="frame" x="813" y="3" width="96" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tHy-sM-HDB">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tHy-sM-HDB">
|
||||
<rect key="frame" x="0.0" y="1" width="96" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Igo-5f-yim">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -448,10 +448,10 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="q93-oh-i5T">
|
||||
<rect key="frame" x="887.5" y="3" width="96" height="18"/>
|
||||
<rect key="frame" x="912" y="3" width="96" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="bOi-LI-TDx">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="bOi-LI-TDx">
|
||||
<rect key="frame" x="0.0" y="1" width="96" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="C2Q-qG-dwX">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -475,7 +475,7 @@
|
|||
<binding destination="1689" name="fontSize" keyPath="values.fontSize" id="1921"/>
|
||||
</connections>
|
||||
</tableColumn>
|
||||
<tableColumn identifier="genre" editable="NO" width="108.5" minWidth="32" maxWidth="512" id="849">
|
||||
<tableColumn identifier="genre" editable="NO" width="115" minWidth="32" maxWidth="512" id="849">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Genre">
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -489,11 +489,11 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="rRl-p9-Awr">
|
||||
<rect key="frame" x="986.5" y="3" width="108" height="18"/>
|
||||
<rect key="frame" x="1011" y="3" width="115" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="yW6-2w-6mN">
|
||||
<rect key="frame" x="0.0" y="1" width="108" height="16"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="yW6-2w-6mN">
|
||||
<rect key="frame" x="0.0" y="1" width="115" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="js2-sT-U4M">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -529,10 +529,10 @@
|
|||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView id="hgh-VE-5kl">
|
||||
<rect key="frame" x="1098" y="3" width="76" height="18"/>
|
||||
<rect key="frame" x="1129" y="3" width="76" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="yEY-MI-d3o">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="yEY-MI-d3o">
|
||||
<rect key="frame" x="0.0" y="1" width="76" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="tus-lr-RhS">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -572,7 +572,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="QFJ-4l-2O6">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="QFJ-4l-2O6">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="gKK-cS-RP5">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -616,7 +616,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Qvd-sk-vRc">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Qvd-sk-vRc">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="YwT-z9-2d2">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -660,7 +660,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="gXW-DX-EsQ">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="gXW-DX-EsQ">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="vaJ-Bc-ebE">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -704,7 +704,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="3V9-dD-ecy">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="3V9-dD-ecy">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="2ha-ys-sRi">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -748,7 +748,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="1rT-Fe-Pho">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="1rT-Fe-Pho">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="DdU-ro-7Yi">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -792,7 +792,7 @@
|
|||
<rect key="frame" x="1" y="3" width="0.0" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="L7E-1S-m3b">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="L7E-1S-m3b">
|
||||
<rect key="frame" x="0.0" y="1" width="4" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="cAf-1y-D7M">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
|
@ -844,11 +844,11 @@
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="1515">
|
||||
<rect key="frame" x="85" y="17" width="15" height="68"/>
|
||||
<rect key="frame" x="1202" y="17" width="15" height="11"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<tableHeaderView key="headerView" wantsLayer="YES" id="1517">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1186" height="17"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="1217" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableHeaderView>
|
||||
</scrollView>
|
||||
|
@ -860,8 +860,8 @@
|
|||
<outlet property="delegate" destination="2172" id="2182"/>
|
||||
</connections>
|
||||
</splitView>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="778">
|
||||
<rect key="frame" x="463" y="4" width="261" height="14"/>
|
||||
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="778">
|
||||
<rect key="frame" x="472" y="4" width="261" height="14"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" title="Total Duration: 00 hours 00 minutes 00 seconds" bezelStyle="round" id="1473">
|
||||
<font key="font" metaFont="controlContent" size="11"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -923,7 +923,7 @@
|
|||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="0D05748D-3258-44F5-9D1C-CBF211C15E2D" label="Search" paletteLabel="Search" sizingBehavior="auto" id="1533" customClass="NSSearchToolbarItem">
|
||||
<nil key="toolTip"/>
|
||||
<searchField key="view" wantsLayer="YES" focusRingType="none" verticalHuggingPriority="750" id="1531">
|
||||
<searchField key="view" wantsLayer="YES" verticalHuggingPriority="750" id="1531">
|
||||
<rect key="frame" x="0.0" y="14" width="79" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" placeholderString="All" bezelStyle="round" recentsAutosaveName="CogFilter" id="1532">
|
||||
|
@ -988,7 +988,7 @@
|
|||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="B042D8A5-AFF4-43B2-9DFB-E87A09B7F861" label="Current Time" paletteLabel="Current Time" visibilityPriority="5" sizingBehavior="auto" id="1568">
|
||||
<nil key="toolTip"/>
|
||||
<textField key="view" focusRingType="none" verticalHuggingPriority="750" id="1566" customClass="TimeField">
|
||||
<textField key="view" verticalHuggingPriority="750" id="1566" customClass="TimeField">
|
||||
<rect key="frame" x="15" y="14" width="47" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" borderStyle="bezel" alignment="center" title="0:00" usesSingleLineMode="YES" bezelStyle="round" id="1567">
|
||||
|
@ -1022,7 +1022,11 @@
|
|||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<outlet property="_popView" destination="6P4-yi-9TK" id="3d2-Sw-J9J"/>
|
||||
<outlet property="_LockButton" destination="OQS-2p-1yP" id="F1I-fb-SDQ"/>
|
||||
<outlet property="_PitchSlider" destination="6P4-yi-9TK" id="Ni0-G0-USM"/>
|
||||
<outlet property="_ResetButton" destination="3Zc-Xv-g24" id="C7x-EU-QpA"/>
|
||||
<outlet property="_TempoSlider" destination="stI-oD-51s" id="Mt0-7i-R4f"/>
|
||||
<outlet property="_popView" destination="90w-7t-RYP" id="qfi-e0-UZc"/>
|
||||
</connections>
|
||||
</button>
|
||||
</toolbarItem>
|
||||
|
@ -1273,7 +1277,7 @@
|
|||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="C0FF70A3-EE67-43F6-9956-95B89425CF0E" label="Current Time" paletteLabel="Current Time" visibilityPriority="5" sizingBehavior="auto" id="2274">
|
||||
<nil key="toolTip"/>
|
||||
<textField key="view" focusRingType="none" verticalHuggingPriority="750" id="2291" customClass="TimeField">
|
||||
<textField key="view" verticalHuggingPriority="750" id="2291" customClass="TimeField">
|
||||
<rect key="frame" x="15" y="14" width="47" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" borderStyle="bezel" alignment="center" title="0:00" usesSingleLineMode="YES" bezelStyle="round" id="2292">
|
||||
|
@ -2355,10 +2359,12 @@ Gw
|
|||
<connections>
|
||||
<outlet property="appController" destination="226" id="TnP-DA-nJl"/>
|
||||
<outlet property="equalizerWindowController" destination="dJ9-b3-BFu" id="gB5-Bu-vqC"/>
|
||||
<outlet property="lockButton" destination="OQS-2p-1yP" id="RfR-WH-ZPY"/>
|
||||
<outlet property="pitchSlider" destination="6P4-yi-9TK" id="Lnu-kw-iYW"/>
|
||||
<outlet property="playlistController" destination="218" id="706"/>
|
||||
<outlet property="playlistLoader" destination="1319" id="ghZ-65-60L"/>
|
||||
<outlet property="playlistView" destination="207" id="717"/>
|
||||
<outlet property="speedSlider" destination="6P4-yi-9TK" id="Xvq-Vj-A88"/>
|
||||
<outlet property="tempoSlider" destination="stI-oD-51s" id="dDc-lb-crL"/>
|
||||
<outlet property="volumeSlider" destination="1612" id="1615"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
|
@ -2539,19 +2545,69 @@ Gw
|
|||
<point key="canvasLocation" x="615" y="-25"/>
|
||||
</customView>
|
||||
<customView id="90w-7t-RYP" userLabel="Speed View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="32" height="168"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="69" height="216"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<slider horizontalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6P4-yi-9TK" userLabel="Speed Slider" customClass="SpeedSlider">
|
||||
<rect key="frame" x="6" y="2" width="20" height="164"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uVG-0w-rW4">
|
||||
<rect key="frame" x="4" y="199" width="24" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="🎵" id="bQV-ZD-SDv">
|
||||
<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="VUX-JL-rjr">
|
||||
<rect key="frame" x="41" y="199" width="24" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="⏰" id="4R4-ba-Ndx">
|
||||
<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>
|
||||
<slider horizontalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6P4-yi-9TK" userLabel="Pitch Slider" customClass="PitchSlider">
|
||||
<rect key="frame" x="6" y="34" width="20" height="164"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<sliderCell key="cell" controlSize="small" continuous="YES" alignment="left" minValue="0.20000000000000001" maxValue="5" doubleValue="1" tickMarkPosition="left" sliderType="linear" id="vTw-tV-W5R"/>
|
||||
<sliderCell key="cell" controlSize="small" continuous="YES" state="on" alignment="left" maxValue="100" doubleValue="40.824829049999998" tickMarkPosition="left" sliderType="linear" id="vTw-tV-W5R"/>
|
||||
<connections>
|
||||
<action selector="changeSpeed:" target="705" id="FcA-37-2J5"/>
|
||||
<action selector="changePitch:" target="705" id="bZt-zY-tjg"/>
|
||||
<outlet property="_TempoSlider" destination="stI-oD-51s" id="HMq-pE-Ssc"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OQS-2p-1yP" userLabel="Lock Button">
|
||||
<rect key="frame" x="17" y="101" width="36" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="🔒" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="M0v-A9-meu">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="pressLock:" target="Ta5-Ik-jh9" id="HnF-AC-arz"/>
|
||||
</connections>
|
||||
</button>
|
||||
<slider horizontalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="stI-oD-51s" userLabel="Tempo Slider" customClass="TempoSlider">
|
||||
<rect key="frame" x="42" y="34" width="20" height="164"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<sliderCell key="cell" controlSize="small" continuous="YES" alignment="left" maxValue="100" doubleValue="40.824829049999998" tickMarkPosition="left" sliderType="linear" id="94j-7B-a8j"/>
|
||||
<connections>
|
||||
<action selector="changeTempo:" target="705" id="8xu-Dm-ceG"/>
|
||||
<outlet property="_PitchSlider" destination="6P4-yi-9TK" id="QaV-cx-2wf"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3Zc-Xv-g24" userLabel="Reset Button">
|
||||
<rect key="frame" x="2" y="2" width="64" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="1.0×" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ijs-k0-EIP">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="pressReset:" target="Ta5-Ik-jh9" id="zoi-N3-teA"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="694" y="-25"/>
|
||||
<point key="canvasLocation" x="866.5" y="-9"/>
|
||||
</customView>
|
||||
<customObject id="1675" customClass="SpotlightWindowController">
|
||||
<connections>
|
||||
|
|
|
@ -98,13 +98,11 @@
|
|||
830C37A527B95EB300E02BB0 /* EqualizerWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 830C37A427B95EB300E02BB0 /* EqualizerWindowController.m */; };
|
||||
830C37FC27B9956C00E02BB0 /* analyzer.c in Sources */ = {isa = PBXBuildFile; fileRef = 830C37F227B9956C00E02BB0 /* analyzer.c */; };
|
||||
831B99BF27C23E88005A969B /* Cog.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 831B99BE27C23E88005A969B /* Cog.sdef */; };
|
||||
83229C9F283B0095004626A8 /* SpectrumWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83229C9D283B0095004626A8 /* SpectrumWindowController.m */; };
|
||||
83256B68286661FC0036D9C0 /* libmpg123.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83256B672866617F0036D9C0 /* libmpg123.0.dylib */; };
|
||||
83256B69286661FC0036D9C0 /* libmpg123.0.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83256B672866617F0036D9C0 /* libmpg123.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
8327DBA9293CAD2400CD0580 /* Organya.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8327DB94293C923500CD0580 /* Organya.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
832923AF279FAC400048201E /* Cog.q1.json in Resources */ = {isa = PBXBuildFile; fileRef = 832923AE279FAC400048201E /* Cog.q1.json */; };
|
||||
832CFC4F2851AA1A002AC26F /* NSView+Visibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 832CFC4E2851AA1A002AC26F /* NSView+Visibility.m */; };
|
||||
832CFC562851AA8B002AC26F /* SpectrumViewCG.m in Sources */ = {isa = PBXBuildFile; fileRef = 832CFC552851AA8B002AC26F /* SpectrumViewCG.m */; };
|
||||
833D0C2527C4ABB80060E16A /* ScriptAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 833D0C2427C4ABB80060E16A /* ScriptAdditions.m */; };
|
||||
83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83489C542782F2DF00BDCEA2 /* libvgmPlayer.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
834B05EA2859C006000B7DC0 /* TotalTimeTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 834B05E92859C006000B7DC0 /* TotalTimeTransformer.m */; };
|
||||
|
@ -145,6 +143,13 @@
|
|||
837DC931285B3F790005C58A /* DataModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 837DC92F285B3F790005C58A /* DataModel.xcdatamodeld */; };
|
||||
8381A09227C5F72F00A1C530 /* SHA256Digest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8381A09127C5F72F00A1C530 /* SHA256Digest.m */; };
|
||||
8384914018083E4E00E7332D /* filetype.icns in Resources */ = {isa = PBXBuildFile; fileRef = 8384913D18083E4E00E7332D /* filetype.icns */; };
|
||||
838A33742D06A9B100D0D770 /* librubberband.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 838A33732D06A9B100D0D770 /* librubberband.3.dylib */; };
|
||||
838A33752D06A9CE00D0D770 /* librubberband.3.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 838A33732D06A9B100D0D770 /* librubberband.3.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
838A337D2D06C14200D0D770 /* TempoSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 838A337C2D06C14200D0D770 /* TempoSlider.m */; };
|
||||
838A337E2D06C14200D0D770 /* PitchSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 838A337A2D06C14200D0D770 /* PitchSlider.m */; };
|
||||
838A33832D06CF4100D0D770 /* SpectrumViewCG.m in Sources */ = {isa = PBXBuildFile; fileRef = 838A33802D06CF4100D0D770 /* SpectrumViewCG.m */; };
|
||||
838A33842D06CF4100D0D770 /* SpectrumWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 838A33822D06CF4100D0D770 /* SpectrumWindowController.m */; };
|
||||
838A33872D06CFCA00D0D770 /* SpeedButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 838A33862D06CFCA00D0D770 /* SpeedButton.m */; };
|
||||
83922FBA286B1AA900A0B039 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83922FB6286B1AA900A0B039 /* WebKit.framework */; };
|
||||
839614A2286ED97200D3EEDB /* AboutWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 839614A0286ED97200D3EEDB /* AboutWindowController.xib */; };
|
||||
839614AD286EDA5C00D3EEDB /* SpectrumWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 839614AB286EDA5C00D3EEDB /* SpectrumWindow.xib */; };
|
||||
|
@ -154,8 +159,6 @@
|
|||
83988F0E27BE0A5900A0E89A /* RedundantPlaylistDataStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 83988F0D27BE0A5900A0E89A /* RedundantPlaylistDataStore.m */; };
|
||||
8399D4E21805A55000B503B1 /* XmlContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8399D4E01805A55000B503B1 /* XmlContainer.m */; };
|
||||
839B837F286D7F8D00F529EE /* NumberHertzToStringTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839B837E286D7F8D00F529EE /* NumberHertzToStringTransformer.swift */; };
|
||||
839D48AA2C9E73AA00D03298 /* SpeedButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D48A72C9E73AA00D03298 /* SpeedButton.m */; };
|
||||
839D48AB2C9E73AA00D03298 /* SpeedSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 839D48A92C9E73AA00D03298 /* SpeedSlider.m */; };
|
||||
839DA7CF274A2D4C001B18E5 /* NSDictionary+Merge.m in Sources */ = {isa = PBXBuildFile; fileRef = 839DA7CE274A2D4C001B18E5 /* NSDictionary+Merge.m */; };
|
||||
839E56F52879625100DFB5F4 /* SADIE_D02-96000.mhr in Resources */ = {isa = PBXBuildFile; fileRef = 839E56F12879625100DFB5F4 /* SADIE_D02-96000.mhr */; };
|
||||
83A360B220E4E81D00192DAB /* Flac.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8303A30C20E4E3D000951EF8 /* Flac.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
|
@ -721,6 +724,7 @@
|
|||
836EF0C827BB91E600BF35B2 /* libogg.0.dylib in CopyFiles */,
|
||||
83AA7D07279EBCAF00087AA4 /* libswresample.5.dylib in CopyFiles */,
|
||||
83AA7D06279EBCAD00087AA4 /* libavutil.59.dylib in CopyFiles */,
|
||||
838A33752D06A9CE00D0D770 /* librubberband.3.dylib in CopyFiles */,
|
||||
83AA7D05279EBCAB00087AA4 /* libavformat.61.dylib in CopyFiles */,
|
||||
83AA7D04279EBCA900087AA4 /* libavcodec.61.dylib in CopyFiles */,
|
||||
83B72E3B279045B7006007A3 /* libfdk-aac.2.dylib in CopyFiles */,
|
||||
|
@ -770,7 +774,7 @@
|
|||
177042970B8BC53600B86321 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = "<group>"; };
|
||||
177042980B8BC53600B86321 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = "<group>"; };
|
||||
177042990B8BC53600B86321 /* PlaybackController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PlaybackController.h; sourceTree = "<group>"; };
|
||||
1770429A0B8BC53600B86321 /* PlaybackController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PlaybackController.m; sourceTree = "<group>"; };
|
||||
1770429A0B8BC53600B86321 /* PlaybackController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlaybackController.m; sourceTree = "<group>"; };
|
||||
1778D3C80F645BF00037E7A0 /* MissingAlbumArtTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MissingAlbumArtTransformer.h; path = InfoInspector/MissingAlbumArtTransformer.h; sourceTree = "<group>"; };
|
||||
1778D3C90F645BF00037E7A0 /* MissingAlbumArtTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MissingAlbumArtTransformer.m; path = InfoInspector/MissingAlbumArtTransformer.m; sourceTree = "<group>"; };
|
||||
177EBF860B8BC2A70000BC8C /* ImageTextCell.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ImageTextCell.h; sourceTree = "<group>"; };
|
||||
|
@ -907,15 +911,11 @@
|
|||
830C37F227B9956C00E02BB0 /* analyzer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = analyzer.c; sourceTree = "<group>"; };
|
||||
8314D63B1A354DFE00EEE8E6 /* sidplay.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = sidplay.xcodeproj; path = Plugins/sidplay/sidplay.xcodeproj; sourceTree = "<group>"; };
|
||||
831B99BE27C23E88005A969B /* Cog.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Cog.sdef; sourceTree = "<group>"; };
|
||||
83229C9C283B0095004626A8 /* SpectrumWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpectrumWindowController.h; sourceTree = "<group>"; };
|
||||
83229C9D283B0095004626A8 /* SpectrumWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SpectrumWindowController.m; sourceTree = "<group>"; };
|
||||
83256B672866617F0036D9C0 /* libmpg123.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpg123.0.dylib; path = ThirdParty/mpg123/lib/libmpg123.0.dylib; sourceTree = "<group>"; };
|
||||
8327DB8F293C923500CD0580 /* Organya.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Organya.xcodeproj; path = Plugins/Organya/Organya.xcodeproj; sourceTree = "<group>"; };
|
||||
832923AE279FAC400048201E /* Cog.q1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Cog.q1.json; sourceTree = "<group>"; };
|
||||
832CFC4E2851AA1A002AC26F /* NSView+Visibility.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSView+Visibility.m"; sourceTree = "<group>"; };
|
||||
832CFC532851AA37002AC26F /* NSView+Visibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSView+Visibility.h"; sourceTree = "<group>"; };
|
||||
832CFC542851AA8B002AC26F /* SpectrumViewCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpectrumViewCG.h; sourceTree = SOURCE_ROOT; };
|
||||
832CFC552851AA8B002AC26F /* SpectrumViewCG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpectrumViewCG.m; sourceTree = SOURCE_ROOT; };
|
||||
833D0C2027C4ABA00060E16A /* ScriptAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScriptAdditions.h; sourceTree = "<group>"; };
|
||||
833D0C2427C4ABB80060E16A /* ScriptAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScriptAdditions.m; sourceTree = "<group>"; };
|
||||
833F681E1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
|
@ -981,6 +981,17 @@
|
|||
8384912518080F2D00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logging.h; sourceTree = "<group>"; };
|
||||
8384913D18083E4E00E7332D /* filetype.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = filetype.icns; sourceTree = "<group>"; };
|
||||
83859520234FEB35004E9946 /* Cog.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Cog.entitlements; sourceTree = "<group>"; };
|
||||
838A33732D06A9B100D0D770 /* librubberband.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = librubberband.3.dylib; path = ThirdParty/rubberband/lib/librubberband.3.dylib; sourceTree = "<group>"; };
|
||||
838A33792D06C14200D0D770 /* PitchSlider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PitchSlider.h; path = Window/PitchSlider.h; sourceTree = "<group>"; };
|
||||
838A337A2D06C14200D0D770 /* PitchSlider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PitchSlider.m; path = Window/PitchSlider.m; sourceTree = "<group>"; };
|
||||
838A337B2D06C14200D0D770 /* TempoSlider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TempoSlider.h; path = Window/TempoSlider.h; sourceTree = "<group>"; };
|
||||
838A337C2D06C14200D0D770 /* TempoSlider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TempoSlider.m; path = Window/TempoSlider.m; sourceTree = "<group>"; };
|
||||
838A337F2D06CF4100D0D770 /* SpectrumViewCG.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpectrumViewCG.h; path = Visualization/SpectrumViewCG.h; sourceTree = "<group>"; };
|
||||
838A33802D06CF4100D0D770 /* SpectrumViewCG.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SpectrumViewCG.m; path = Visualization/SpectrumViewCG.m; sourceTree = "<group>"; };
|
||||
838A33812D06CF4100D0D770 /* SpectrumWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpectrumWindowController.h; path = Visualization/SpectrumWindowController.h; sourceTree = "<group>"; };
|
||||
838A33822D06CF4100D0D770 /* SpectrumWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SpectrumWindowController.m; path = Visualization/SpectrumWindowController.m; sourceTree = "<group>"; };
|
||||
838A33852D06CFCA00D0D770 /* SpeedButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SpeedButton.h; path = Window/SpeedButton.h; sourceTree = "<group>"; };
|
||||
838A33862D06CFCA00D0D770 /* SpeedButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SpeedButton.m; path = Window/SpeedButton.m; sourceTree = "<group>"; };
|
||||
838EE79E29A8556000CD0580 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/LyricsWindow.strings; sourceTree = "<group>"; };
|
||||
838EE7A029A8556500CD0580 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/LyricsWindow.strings; sourceTree = "<group>"; };
|
||||
838EE7A229A8557000CD0580 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/LyricsWindow.strings; sourceTree = "<group>"; };
|
||||
|
@ -1015,10 +1026,6 @@
|
|||
8399D4E01805A55000B503B1 /* XmlContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XmlContainer.m; sourceTree = "<group>"; };
|
||||
8399D4E11805A55000B503B1 /* XmlContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XmlContainer.h; sourceTree = "<group>"; };
|
||||
839B837E286D7F8D00F529EE /* NumberHertzToStringTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NumberHertzToStringTransformer.swift; path = Transformers/NumberHertzToStringTransformer.swift; sourceTree = "<group>"; };
|
||||
839D48A62C9E73AA00D03298 /* SpeedButton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpeedButton.h; sourceTree = "<group>"; };
|
||||
839D48A72C9E73AA00D03298 /* SpeedButton.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SpeedButton.m; sourceTree = "<group>"; };
|
||||
839D48A82C9E73AA00D03298 /* SpeedSlider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpeedSlider.h; sourceTree = "<group>"; };
|
||||
839D48A92C9E73AA00D03298 /* SpeedSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SpeedSlider.m; sourceTree = "<group>"; };
|
||||
839DA7CB274A2D4C001B18E5 /* NSDictionary+Merge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Merge.h"; sourceTree = "<group>"; };
|
||||
839DA7CE274A2D4C001B18E5 /* NSDictionary+Merge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Merge.m"; sourceTree = "<group>"; };
|
||||
839E3B53286595D700880EA2 /* GeneralPane.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GeneralPane.h; path = Preferences/Preferences/GeneralPane.h; sourceTree = "<group>"; };
|
||||
|
@ -1112,6 +1119,7 @@
|
|||
83922FBA286B1AA900A0B039 /* WebKit.framework in Frameworks */,
|
||||
835FAC7E27BCDF5B00BA8562 /* libaom.a in Frameworks */,
|
||||
837DC92B285B05710005C58A /* CoreData.framework in Frameworks */,
|
||||
838A33742D06A9B100D0D770 /* librubberband.3.dylib in Frameworks */,
|
||||
83978E26285C596F0076ED21 /* FirebaseAnalytics in Frameworks */,
|
||||
17BB5CF90B8A86350009ACB1 /* AudioUnit.framework in Frameworks */,
|
||||
17BB5CFA0B8A86350009ACB1 /* CoreAudio.framework in Frameworks */,
|
||||
|
@ -1168,6 +1176,7 @@
|
|||
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
838A33732D06A9B100D0D770 /* librubberband.3.dylib */,
|
||||
836DF616298F6EC400CD0580 /* libsoxr.0.dylib */,
|
||||
83256B672866617F0036D9C0 /* libmpg123.0.dylib */,
|
||||
835FAC7C27BCDF5B00BA8562 /* libaom.a */,
|
||||
|
@ -1412,6 +1421,8 @@
|
|||
836D28A718086386005B7299 /* MiniModeMenuTitleTransformer.m */,
|
||||
17E0D5E30F520F02005B6FED /* MiniWindow.h */,
|
||||
17E0D5E40F520F02005B6FED /* MiniWindow.m */,
|
||||
838A33792D06C14200D0D770 /* PitchSlider.h */,
|
||||
838A337A2D06C14200D0D770 /* PitchSlider.m */,
|
||||
1752C36A0F59E00100F85F28 /* PlaybackButtons.h */,
|
||||
1752C36B0F59E00100F85F28 /* PlaybackButtons.m */,
|
||||
17E0D5E50F520F02005B6FED /* PositionSlider.h */,
|
||||
|
@ -1421,10 +1432,10 @@
|
|||
172A12320F5911D20078EF0C /* RepeatTransformers.m */,
|
||||
172A123A0F5912AE0078EF0C /* ShuffleTransformers.h */,
|
||||
172A123B0F5912AE0078EF0C /* ShuffleTransformers.m */,
|
||||
839D48A62C9E73AA00D03298 /* SpeedButton.h */,
|
||||
839D48A72C9E73AA00D03298 /* SpeedButton.m */,
|
||||
839D48A82C9E73AA00D03298 /* SpeedSlider.h */,
|
||||
839D48A92C9E73AA00D03298 /* SpeedSlider.m */,
|
||||
838A33852D06CFCA00D0D770 /* SpeedButton.h */,
|
||||
838A33862D06CFCA00D0D770 /* SpeedButton.m */,
|
||||
838A337B2D06C14200D0D770 /* TempoSlider.h */,
|
||||
838A337C2D06C14200D0D770 /* TempoSlider.m */,
|
||||
17E0D5E70F520F02005B6FED /* TimeField.h */,
|
||||
17E0D5E80F520F02005B6FED /* TimeField.m */,
|
||||
17E0D6180F520F9F005B6FED /* VolumeButton.h */,
|
||||
|
@ -1811,15 +1822,15 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
830C37EF27B9956C00E02BB0 /* ThirdParty */,
|
||||
8377C66427B8CF7A00E8BC0F /* VisualizationController.h */,
|
||||
8377C66227B8CF6300E8BC0F /* SpectrumViewSK.h */,
|
||||
8377C66127B8CF6300E8BC0F /* SpectrumViewSK.m */,
|
||||
832CFC542851AA8B002AC26F /* SpectrumViewCG.h */,
|
||||
832CFC552851AA8B002AC26F /* SpectrumViewCG.m */,
|
||||
8377C6B727B900F000E8BC0F /* SpectrumItem.h */,
|
||||
8377C6B827B900F000E8BC0F /* SpectrumItem.m */,
|
||||
83229C9C283B0095004626A8 /* SpectrumWindowController.h */,
|
||||
83229C9D283B0095004626A8 /* SpectrumWindowController.m */,
|
||||
838A337F2D06CF4100D0D770 /* SpectrumViewCG.h */,
|
||||
838A33802D06CF4100D0D770 /* SpectrumViewCG.m */,
|
||||
8377C66227B8CF6300E8BC0F /* SpectrumViewSK.h */,
|
||||
8377C66127B8CF6300E8BC0F /* SpectrumViewSK.m */,
|
||||
838A33812D06CF4100D0D770 /* SpectrumWindowController.h */,
|
||||
838A33822D06CF4100D0D770 /* SpectrumWindowController.m */,
|
||||
8377C66427B8CF7A00E8BC0F /* VisualizationController.h */,
|
||||
);
|
||||
name = Visualization;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2561,8 +2572,6 @@
|
|||
83A3B734283AE89000CC6593 /* ColorToValueTransformer.m in Sources */,
|
||||
8D11072D0486CEB800E47090 /* main.m in Sources */,
|
||||
8E75757109F31D5A0080F1EE /* DNDArrayController.m in Sources */,
|
||||
839D48AA2C9E73AA00D03298 /* SpeedButton.m in Sources */,
|
||||
839D48AB2C9E73AA00D03298 /* SpeedSlider.m in Sources */,
|
||||
8E75757209F31D5A0080F1EE /* PlaylistController.m in Sources */,
|
||||
8E75757309F31D5A0080F1EE /* PlaylistEntry.m in Sources */,
|
||||
8E75757409F31D5A0080F1EE /* PlaylistView.m in Sources */,
|
||||
|
@ -2572,6 +2581,7 @@
|
|||
177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */,
|
||||
177EC0270B8BC2CF0000BC8C /* TrackingCell.m in Sources */,
|
||||
177EC0290B8BC2CF0000BC8C /* TrackingSlider.m in Sources */,
|
||||
838A33872D06CFCA00D0D770 /* SpeedButton.m in Sources */,
|
||||
1770429C0B8BC53600B86321 /* AppController.m in Sources */,
|
||||
1770429E0B8BC53600B86321 /* PlaybackController.m in Sources */,
|
||||
8355D6B6180612F300D05687 /* NSData+MD5.m in Sources */,
|
||||
|
@ -2588,7 +2598,10 @@
|
|||
5604D4F60D60726E004F5C5D /* SpotlightPlaylistEntry.m in Sources */,
|
||||
56462EAF0D6341F6000AB68C /* SpotlightTransformers.m in Sources */,
|
||||
830C37A527B95EB300E02BB0 /* EqualizerWindowController.m in Sources */,
|
||||
832CFC562851AA8B002AC26F /* SpectrumViewCG.m in Sources */,
|
||||
838A337D2D06C14200D0D770 /* TempoSlider.m in Sources */,
|
||||
838A337E2D06C14200D0D770 /* PitchSlider.m in Sources */,
|
||||
838A33832D06CF4100D0D770 /* SpectrumViewCG.m in Sources */,
|
||||
838A33842D06CF4100D0D770 /* SpectrumWindowController.m in Sources */,
|
||||
83B61E2829A82A0200CD0580 /* LyricsWindowController.m in Sources */,
|
||||
56462EB20D634206000AB68C /* SpotlightPlaylistController.m in Sources */,
|
||||
07E18DF30D62B38400BB0E11 /* NSArray+ShuffleUtils.m in Sources */,
|
||||
|
@ -2635,7 +2648,6 @@
|
|||
17F6C8070F603701000D9DA9 /* PlaybackEventController.m in Sources */,
|
||||
83BC5AB220E4C87100631CD4 /* DualWindow.m in Sources */,
|
||||
8307D30E28606148000FF8EB /* SandboxBroker.m in Sources */,
|
||||
83229C9F283B0095004626A8 /* SpectrumWindowController.m in Sources */,
|
||||
835F00BB279BD1CD00055FCF /* SecondsFormatter.m in Sources */,
|
||||
1784560F0F631E24007E8021 /* FileTreeViewController.m in Sources */,
|
||||
178456120F631E31007E8021 /* SideViewController.m in Sources */,
|
||||
|
@ -3025,6 +3037,8 @@
|
|||
"$(PROJECT_DIR)/ThirdParty/avif/lib",
|
||||
"$(PROJECT_DIR)/ThirdParty/mpg123/lib",
|
||||
"$(PROJECT_DIR)/ThirdParty/soxr/lib",
|
||||
"$(PROJECT_DIR)",
|
||||
"$(PROJECT_DIR)/ThirdParty/rubberband/lib",
|
||||
);
|
||||
OTHER_CFLAGS = (
|
||||
"-D__MACOSX__",
|
||||
|
@ -3082,6 +3096,8 @@
|
|||
"$(PROJECT_DIR)/ThirdParty/avif/lib",
|
||||
"$(PROJECT_DIR)/ThirdParty/mpg123/lib",
|
||||
"$(PROJECT_DIR)/ThirdParty/soxr/lib",
|
||||
"$(PROJECT_DIR)",
|
||||
"$(PROJECT_DIR)/ThirdParty/rubberband/lib",
|
||||
);
|
||||
OTHER_CFLAGS = (
|
||||
"-D__MACOSX__",
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
//
|
||||
// SpeedButton.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SpeedSlider.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface SpeedButton : NSButton {
|
||||
IBOutlet SpeedSlider *_popView;
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,51 +0,0 @@
|
|||
//
|
||||
// SpeedButton.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SpeedButton.h"
|
||||
#import "PlaybackController.h"
|
||||
|
||||
@implementation SpeedButton {
|
||||
NSPopover *popover;
|
||||
NSViewController *viewController;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
popover = [[NSPopover alloc] init];
|
||||
popover.behavior = NSPopoverBehaviorTransient;
|
||||
[popover setContentSize:_popView.bounds.size];
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)theEvent {
|
||||
if([popover isShown]) {
|
||||
[_popView scrollWheel:theEvent];
|
||||
return;
|
||||
}
|
||||
|
||||
double change = [theEvent deltaY];
|
||||
|
||||
[_popView setDoubleValue:[_popView doubleValue] + change];
|
||||
|
||||
[[_popView target] changeSpeed:_popView];
|
||||
|
||||
[_popView showToolTipForView:self closeAfter:1.0];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent {
|
||||
[popover close];
|
||||
|
||||
popover.contentViewController = nil;
|
||||
viewController = [[NSViewController alloc] init];
|
||||
viewController.view = _popView;
|
||||
popover.contentViewController = viewController;
|
||||
|
||||
[popover showRelativeToRect:self.bounds ofView:self preferredEdge:NSRectEdgeMaxY];
|
||||
|
||||
[super mouseDown:theEvent];
|
||||
}
|
||||
|
||||
@end
|
BIN
ThirdParty/libraries.tar.xz
vendored
BIN
ThirdParty/libraries.tar.xz
vendored
Binary file not shown.
7
ThirdParty/rubberband/README.md
vendored
Normal file
7
ThirdParty/rubberband/README.md
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
Build the stock release of librubberband with meson and ninja, using the stock
|
||||
cross build option files to build each architecture, then combine them with lipo.
|
||||
|
||||
No changes were made to the upstream library, these binaries are only packaged to
|
||||
simplify building and packaging the project.
|
||||
|
||||
Version 4.0 was used.
|
353
ThirdParty/rubberband/include/rubberband/RubberBandLiveShifter.h
vendored
Normal file
353
ThirdParty/rubberband/include/rubberband/RubberBandLiveShifter.h
vendored
Normal file
|
@ -0,0 +1,353 @@
|
|||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2024 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Live Pitch Shifter obtained by agreement with the
|
||||
copyright holders, you may redistribute and/or modify it under the
|
||||
terms described in that licence.
|
||||
|
||||
If you wish to distribute code using Rubber Band Live under terms
|
||||
other than those of the GNU General Public License, you must
|
||||
obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#ifndef RUBBERBAND_LIVE_SHIFTER_H
|
||||
#define RUBBERBAND_LIVE_SHIFTER_H
|
||||
|
||||
#define RUBBERBAND_VERSION "4.0.0"
|
||||
#define RUBBERBAND_API_MAJOR_VERSION 3
|
||||
#define RUBBERBAND_API_MINOR_VERSION 0
|
||||
|
||||
#undef RUBBERBAND_LIVE_DLLEXPORT
|
||||
#ifdef _MSC_VER
|
||||
#define RUBBERBAND_LIVE_DLLEXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define RUBBERBAND_LIVE_DLLEXPORT
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
/**
|
||||
* ### Summary
|
||||
*
|
||||
* RubberBand::RubberBandLiveShifter is an interface to the Rubber
|
||||
* Band Library designed for applications that need to perform
|
||||
* pitch-shifting only, without time-stretching, and to do so in a
|
||||
* straightforward block-by-block process with the shortest available
|
||||
* processing delay. For the more general interface, see
|
||||
* RubberBand::RubberBandStretcher.
|
||||
*
|
||||
* RubberBandLiveShifter has a much simpler API than
|
||||
* RubberBandStretcher. Its process function, called
|
||||
* RubberBandLiveShifter::shift(), accepts a fixed number of sample
|
||||
* frames on each call and always returns exactly the same number of
|
||||
* sample frames. This is in contrast to the
|
||||
* process/available/retrieve call sequence that RubberBandStretcher
|
||||
* requires as a result of its variable output rate.
|
||||
*
|
||||
* The number of frames accepted by and returned from
|
||||
* RubberBandLiveShifter::shift() are not under the caller's control:
|
||||
* they must always be exactly the number given by
|
||||
* RubberBandLiveShifter::getBlockSize(). But this number is fixed for
|
||||
* the lifetime of the shifter, so it only needs to be queried once
|
||||
* after construction and then fixed-size buffers may be used.
|
||||
*
|
||||
* Using RubberBandLiveShifter also gives a shorter processing delay
|
||||
* than a typical buffering setup using RubberBandStretcher, making it
|
||||
* a useful choice for some streamed or live situations. However, it
|
||||
* is still not a low-latency effect, with a delay of 50ms or more
|
||||
* between input and output signals depending on configuration. (The
|
||||
* actual value may be queried via
|
||||
* RubberBandLiveShifter::getStartDelay().) The shifter is real-time
|
||||
* safe in the sense of avoiding allocation, locking, or blocking
|
||||
* operations in the processing path.
|
||||
*
|
||||
* ### Thread safety
|
||||
*
|
||||
* Multiple instances of RubberBandLiveShifter may be created and used
|
||||
* in separate threads concurrently. However, for any single instance
|
||||
* of RubberBandLiveShifter, you may not call
|
||||
* RubberBandLiveShifter::shift() more than once concurrently, and you
|
||||
* may not change the pitch scaling ratio using
|
||||
* RubberBandLiveShifter::setPitchScale() while a
|
||||
* RubberBandLiveShifter::shift() call is being executed. Changing the
|
||||
* ratio is real-time safe, so when the pitch ratio is time-varying,
|
||||
* it is normal to update the ratio before each shift call.
|
||||
*/
|
||||
class RUBBERBAND_LIVE_DLLEXPORT
|
||||
RubberBandLiveShifter
|
||||
{
|
||||
public:
|
||||
enum Option {
|
||||
OptionWindowShort = 0x00000000,
|
||||
OptionWindowMedium = 0x00100000,
|
||||
|
||||
OptionFormantShifted = 0x00000000,
|
||||
OptionFormantPreserved = 0x01000000,
|
||||
|
||||
OptionChannelsApart = 0x00000000,
|
||||
OptionChannelsTogether = 0x10000000
|
||||
|
||||
// n.b. Options is int, so we must stop before 0x80000000
|
||||
};
|
||||
|
||||
/**
|
||||
* A bitwise OR of values from the RubberBandLiveShifter::Option
|
||||
* enum.
|
||||
*/
|
||||
typedef int Options;
|
||||
|
||||
enum PresetOption {
|
||||
DefaultOptions = 0x00000000
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for log callbacks that may optionally be provided to
|
||||
* the shifter on construction.
|
||||
*
|
||||
* If a Logger is provided, the shifter will call one of these
|
||||
* functions instead of sending output to \c cerr when there is
|
||||
* something to report. This allows debug output to be diverted to
|
||||
* an application's logging facilities, and/or handled in an
|
||||
* RT-safe way. See setDebugLevel() for details about how and when
|
||||
* RubberBandLiveShifter reports something in this way.
|
||||
*
|
||||
* The message text passed to each of these log functions is a
|
||||
* C-style string with no particular guaranteed lifespan. If you
|
||||
* need to retain it, copy it before returning. Do not free it.
|
||||
*
|
||||
* @see setDebugLevel
|
||||
* @see setDefaultDebugLevel
|
||||
*/
|
||||
struct Logger {
|
||||
/// Receive a log message with no numeric values.
|
||||
virtual void log(const char *) = 0;
|
||||
|
||||
/// Receive a log message and one accompanying numeric value.
|
||||
virtual void log(const char *, double) = 0;
|
||||
|
||||
/// Receive a log message and two accompanying numeric values.
|
||||
virtual void log(const char *, double, double) = 0;
|
||||
|
||||
virtual ~Logger() { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a pitch shifter object to run at the given sample
|
||||
* rate, with the given number of channels.
|
||||
*/
|
||||
RubberBandLiveShifter(size_t sampleRate, size_t channels,
|
||||
Options options);
|
||||
|
||||
/**
|
||||
* Construct a pitch shifter object with a custom debug
|
||||
* logger. This may be useful for debugging if the default logger
|
||||
* output (which simply goes to \c cerr) is not visible in the
|
||||
* runtime environment, or if the application has a standard or
|
||||
* more realtime-appropriate logging mechanism.
|
||||
*
|
||||
* See the documentation for the other constructor above for
|
||||
* details of the arguments other than the logger.
|
||||
*
|
||||
* Note that although the supplied logger gets to decide what to
|
||||
* do with log messages, the separately-set debug level (see
|
||||
* setDebugLevel() and setDefaultDebugLevel()) still determines
|
||||
* whether any given debug message is sent to the logger in the
|
||||
* first place.
|
||||
*/
|
||||
RubberBandLiveShifter(size_t sampleRate, size_t channels,
|
||||
std::shared_ptr<Logger> logger,
|
||||
Options options);
|
||||
|
||||
~RubberBandLiveShifter();
|
||||
|
||||
/**
|
||||
* Reset the shifter's internal buffers. The shifter should
|
||||
* subsequently behave as if it had just been constructed
|
||||
* (although retaining the current pitch ratio).
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Set the pitch scaling ratio for the shifter. This is the ratio
|
||||
* of target frequency to source frequency. For example, a ratio
|
||||
* of 2.0 would shift up by one octave; 0.5 down by one octave; or
|
||||
* 1.0 leave the pitch unaffected.
|
||||
*
|
||||
* To put this in musical terms, a pitch scaling ratio
|
||||
* corresponding to a shift of S equal-tempered semitones (where S
|
||||
* is positive for an upwards shift and negative for downwards) is
|
||||
* pow(2.0, S / 12.0).
|
||||
*
|
||||
* This function may be called at any time, so long as it is not
|
||||
* called concurrently with shift(). You should either call this
|
||||
* function from the same thread as shift(), or provide your own
|
||||
* mutex or similar mechanism to ensure that setPitchScale and
|
||||
* shift() cannot be run at once (there is no internal mutex for
|
||||
* this purpose).
|
||||
*/
|
||||
void setPitchScale(double scale);
|
||||
|
||||
/**
|
||||
* Set a pitch scale for the vocal formant envelope separately
|
||||
* from the overall pitch scale. This is a ratio of target
|
||||
* frequency to source frequency. For example, a ratio of 2.0
|
||||
* would shift the formant envelope up by one octave; 0.5 down by
|
||||
* one octave; or 1.0 leave the formant unaffected.
|
||||
*
|
||||
* By default this is set to the special value of 0.0, which
|
||||
* causes the scale to be calculated automatically. It will be
|
||||
* treated as 1.0 / the pitch scale if OptionFormantPreserved is
|
||||
* specified, or 1.0 for OptionFormantShifted.
|
||||
*
|
||||
* Conversely, if this is set to a value other than the default
|
||||
* 0.0, formant shifting will happen regardless of the state of
|
||||
* the OptionFormantPreserved/OptionFormantShifted option.
|
||||
*
|
||||
* This function is provided for special effects only. You do not
|
||||
* need to call it for ordinary pitch shifting, with or without
|
||||
* formant preservation - just specify or omit the
|
||||
* OptionFormantPreserved option as appropriate. Use this function
|
||||
* only if you want to shift formants by a distance other than
|
||||
* that of the overall pitch shift.
|
||||
*/
|
||||
void setFormantScale(double scale);
|
||||
|
||||
/**
|
||||
* Return the last pitch scaling ratio value that was set (either
|
||||
* on construction or with setPitchScale()).
|
||||
*/
|
||||
double getPitchScale() const;
|
||||
|
||||
/**
|
||||
* Return the last formant scaling ratio that was set with
|
||||
* setFormantScale, or 0.0 if the default automatic scaling is in
|
||||
* effect.
|
||||
*/
|
||||
double getFormantScale() const;
|
||||
|
||||
/**
|
||||
* Return the output delay of the shifter. This is the number of
|
||||
* audio samples that one should discard at the start of the
|
||||
* output, in order to ensure that the resulting audio has the
|
||||
* expected time alignment with the input.
|
||||
*
|
||||
* Ensure you have set the pitch scale to its proper starting
|
||||
* value before calling getStartDelay().
|
||||
*/
|
||||
size_t getStartDelay() const;
|
||||
|
||||
/**
|
||||
* Return the number of channels this shifter was constructed
|
||||
* with.
|
||||
*/
|
||||
size_t getChannelCount() const;
|
||||
|
||||
/**
|
||||
* Change an OptionFormant configuration setting. This may be
|
||||
* called at any time in any mode.
|
||||
*
|
||||
* Note that if running multi-threaded in Offline mode, the change
|
||||
* may not take effect immediately if processing is already under
|
||||
* way when this function is called.
|
||||
*/
|
||||
void setFormantOption(Options options);
|
||||
|
||||
/**
|
||||
* Query the number of sample frames that must be passed to, and
|
||||
* will be returned by, each shift() call. This value is fixed for
|
||||
* the lifetime of the shifter.
|
||||
*
|
||||
* Note that the blocksize refers to the number of audio sample
|
||||
* frames, which may be multi-channel, not the number of
|
||||
* individual samples.
|
||||
*/
|
||||
size_t getBlockSize() const;
|
||||
|
||||
/**
|
||||
* Pitch-shift a single block of sample frames. The number of
|
||||
* sample frames (samples per channel) processed per call is
|
||||
* constant.
|
||||
*
|
||||
* "input" should point to de-interleaved audio data with one
|
||||
* float array per channel, with each array containing n samples
|
||||
* where n is the value returned by getBlockSize().
|
||||
*
|
||||
* "output" should point to a float array per channel, with each
|
||||
* array having enough room to store n samples where n is the value
|
||||
* returned by getBlockSize().
|
||||
*
|
||||
* The input and output must be separate arrays; they cannot alias
|
||||
* one another or overlap.
|
||||
*
|
||||
* Sample values are conventionally expected to be in the range
|
||||
* -1.0f to +1.0f.
|
||||
*/
|
||||
void shift(const float *const *input, float *const *output);
|
||||
|
||||
/**
|
||||
* Set the level of debug output. The supported values are:
|
||||
*
|
||||
* 0. Report errors only.
|
||||
*
|
||||
* 1. Report some information on construction and ratio
|
||||
* change. Nothing is reported during normal processing unless
|
||||
* something changes.
|
||||
*
|
||||
* 2. Report a significant amount of information about ongoing
|
||||
* calculations during normal processing.
|
||||
*
|
||||
* The default is whatever has been set using
|
||||
* setDefaultDebugLevel(), or 0 if that function has not been
|
||||
* called.
|
||||
*
|
||||
* All output goes to \c cerr unless a custom
|
||||
* RubberBandLiveShifter::Logger has been provided on
|
||||
* construction. Because writing to \c cerr is not RT-safe, only
|
||||
* debug level 0 is RT-safe in normal use by default. Debug levels
|
||||
* 0 and 1 use only C-string constants as debug messages, so they
|
||||
* are RT-safe if your custom logger is RT-safe. Levels 2 and 3
|
||||
* are not guaranteed to be RT-safe in any conditions as they may
|
||||
* construct messages by allocation.
|
||||
*
|
||||
* @see Logger
|
||||
* @see setDefaultDebugLevel
|
||||
*/
|
||||
void setDebugLevel(int level);
|
||||
|
||||
/**
|
||||
* Set the default level of debug output for subsequently
|
||||
* constructed shifters.
|
||||
*
|
||||
* @see setDebugLevel
|
||||
*/
|
||||
static void setDefaultDebugLevel(int level);
|
||||
|
||||
protected:
|
||||
class Impl;
|
||||
Impl *m_d;
|
||||
|
||||
RubberBandLiveShifter(const RubberBandLiveShifter &) =delete;
|
||||
RubberBandLiveShifter &operator=(const RubberBandLiveShifter &) =delete;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
1099
ThirdParty/rubberband/include/rubberband/RubberBandStretcher.h
vendored
Normal file
1099
ThirdParty/rubberband/include/rubberband/RubberBandStretcher.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
216
ThirdParty/rubberband/include/rubberband/rubberband-c.h
vendored
Normal file
216
ThirdParty/rubberband/include/rubberband/rubberband-c.h
vendored
Normal file
|
@ -0,0 +1,216 @@
|
|||
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2024 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Library obtained by agreement with the copyright
|
||||
holders, you may redistribute and/or modify it under the terms
|
||||
described in that licence.
|
||||
|
||||
If you wish to distribute code using the Rubber Band Library
|
||||
under terms other than those of the GNU General Public License,
|
||||
you must obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#ifndef RUBBERBAND_C_API_H
|
||||
#define RUBBERBAND_C_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RUBBERBAND_VERSION "4.0.0"
|
||||
#define RUBBERBAND_API_MAJOR_VERSION 3
|
||||
#define RUBBERBAND_API_MINOR_VERSION 0
|
||||
|
||||
#undef RB_EXTERN
|
||||
#ifdef _MSC_VER
|
||||
#ifndef RUBBERBAND_STATIC
|
||||
#define RB_EXTERN extern __declspec(dllexport)
|
||||
#else
|
||||
#define RB_EXTERN extern
|
||||
#endif
|
||||
#else
|
||||
#define RB_EXTERN extern
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is a C-linkage interface to the Rubber Band time stretcher.
|
||||
*
|
||||
* This is a wrapper interface: the primary interface is in C++ and is
|
||||
* defined and documented in RubberBandStretcher.h and
|
||||
* RubberBandLiveShifter.h. The library itself is implemented in C++,
|
||||
* and requires C++ standard library support even when using the
|
||||
* C-linkage API.
|
||||
*
|
||||
* Please see RubberBandStretcher.h and RubberBandLiveShifter.h for
|
||||
* documentation.
|
||||
*
|
||||
* If you are writing to the C++ API, do not include this header.
|
||||
*/
|
||||
|
||||
enum RubberBandOption {
|
||||
|
||||
RubberBandOptionProcessOffline = 0x00000000,
|
||||
RubberBandOptionProcessRealTime = 0x00000001,
|
||||
|
||||
RubberBandOptionStretchElastic = 0x00000000, // obsolete
|
||||
RubberBandOptionStretchPrecise = 0x00000010, // obsolete
|
||||
|
||||
RubberBandOptionTransientsCrisp = 0x00000000,
|
||||
RubberBandOptionTransientsMixed = 0x00000100,
|
||||
RubberBandOptionTransientsSmooth = 0x00000200,
|
||||
|
||||
RubberBandOptionDetectorCompound = 0x00000000,
|
||||
RubberBandOptionDetectorPercussive = 0x00000400,
|
||||
RubberBandOptionDetectorSoft = 0x00000800,
|
||||
|
||||
RubberBandOptionPhaseLaminar = 0x00000000,
|
||||
RubberBandOptionPhaseIndependent = 0x00002000,
|
||||
|
||||
RubberBandOptionThreadingAuto = 0x00000000,
|
||||
RubberBandOptionThreadingNever = 0x00010000,
|
||||
RubberBandOptionThreadingAlways = 0x00020000,
|
||||
|
||||
RubberBandOptionWindowStandard = 0x00000000,
|
||||
RubberBandOptionWindowShort = 0x00100000,
|
||||
RubberBandOptionWindowLong = 0x00200000,
|
||||
|
||||
RubberBandOptionSmoothingOff = 0x00000000,
|
||||
RubberBandOptionSmoothingOn = 0x00800000,
|
||||
|
||||
RubberBandOptionFormantShifted = 0x00000000,
|
||||
RubberBandOptionFormantPreserved = 0x01000000,
|
||||
|
||||
RubberBandOptionPitchHighSpeed = 0x00000000,
|
||||
RubberBandOptionPitchHighQuality = 0x02000000,
|
||||
RubberBandOptionPitchHighConsistency = 0x04000000,
|
||||
|
||||
RubberBandOptionChannelsApart = 0x00000000,
|
||||
RubberBandOptionChannelsTogether = 0x10000000,
|
||||
|
||||
RubberBandOptionEngineFaster = 0x00000000,
|
||||
RubberBandOptionEngineFiner = 0x20000000
|
||||
};
|
||||
|
||||
typedef int RubberBandOptions;
|
||||
|
||||
struct RubberBandState_;
|
||||
typedef struct RubberBandState_ *RubberBandState;
|
||||
|
||||
RB_EXTERN RubberBandState rubberband_new(unsigned int sampleRate,
|
||||
unsigned int channels,
|
||||
RubberBandOptions options,
|
||||
double initialTimeRatio,
|
||||
double initialPitchScale);
|
||||
|
||||
RB_EXTERN void rubberband_delete(RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_reset(RubberBandState);
|
||||
|
||||
RB_EXTERN int rubberband_get_engine_version(RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_set_time_ratio(RubberBandState, double ratio);
|
||||
RB_EXTERN void rubberband_set_pitch_scale(RubberBandState, double scale);
|
||||
|
||||
RB_EXTERN double rubberband_get_time_ratio(const RubberBandState);
|
||||
RB_EXTERN double rubberband_get_pitch_scale(const RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_set_formant_scale(RubberBandState, double scale);
|
||||
RB_EXTERN double rubberband_get_formant_scale(const RubberBandState);
|
||||
|
||||
RB_EXTERN unsigned int rubberband_get_preferred_start_pad(const RubberBandState);
|
||||
RB_EXTERN unsigned int rubberband_get_start_delay(const RubberBandState);
|
||||
RB_EXTERN unsigned int rubberband_get_latency(const RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_set_transients_option(RubberBandState, RubberBandOptions options);
|
||||
RB_EXTERN void rubberband_set_detector_option(RubberBandState, RubberBandOptions options);
|
||||
RB_EXTERN void rubberband_set_phase_option(RubberBandState, RubberBandOptions options);
|
||||
RB_EXTERN void rubberband_set_formant_option(RubberBandState, RubberBandOptions options);
|
||||
RB_EXTERN void rubberband_set_pitch_option(RubberBandState, RubberBandOptions options);
|
||||
|
||||
RB_EXTERN void rubberband_set_expected_input_duration(RubberBandState, unsigned int samples);
|
||||
|
||||
RB_EXTERN unsigned int rubberband_get_samples_required(const RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_set_max_process_size(RubberBandState, unsigned int samples);
|
||||
RB_EXTERN unsigned int rubberband_get_process_size_limit(RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_set_key_frame_map(RubberBandState, unsigned int keyframecount, unsigned int *from, unsigned int *to);
|
||||
|
||||
RB_EXTERN void rubberband_study(RubberBandState, const float *const *input, unsigned int samples, int final);
|
||||
RB_EXTERN void rubberband_process(RubberBandState, const float *const *input, unsigned int samples, int final);
|
||||
|
||||
RB_EXTERN int rubberband_available(const RubberBandState);
|
||||
RB_EXTERN unsigned int rubberband_retrieve(const RubberBandState, float *const *output, unsigned int samples);
|
||||
|
||||
RB_EXTERN unsigned int rubberband_get_channel_count(const RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_calculate_stretch(RubberBandState);
|
||||
|
||||
RB_EXTERN void rubberband_set_debug_level(RubberBandState, int level);
|
||||
RB_EXTERN void rubberband_set_default_debug_level(int level);
|
||||
|
||||
|
||||
enum RubberBandLiveOption {
|
||||
|
||||
RubberBandLiveOptionWindowShort = 0x00000000,
|
||||
RubberBandLiveOptionWindowMedium = 0x00100000,
|
||||
|
||||
RubberBandLiveOptionFormantShifted = 0x00000000,
|
||||
RubberBandLiveOptionFormantPreserved = 0x01000000,
|
||||
|
||||
RubberBandLiveOptionChannelsApart = 0x00000000,
|
||||
RubberBandLiveOptionChannelsTogether = 0x10000000
|
||||
};
|
||||
|
||||
typedef int RubberBandLiveOptions;
|
||||
|
||||
struct RubberBandLiveState_;
|
||||
typedef struct RubberBandLiveState_ *RubberBandLiveState;
|
||||
|
||||
RB_EXTERN RubberBandLiveState rubberband_live_new(unsigned int sampleRate,
|
||||
unsigned int channels,
|
||||
RubberBandOptions options);
|
||||
|
||||
RB_EXTERN void rubberband_live_delete(RubberBandLiveState);
|
||||
|
||||
RB_EXTERN void rubberband_live_reset(RubberBandLiveState);
|
||||
|
||||
RB_EXTERN void rubberband_live_set_pitch_scale(RubberBandLiveState, double scale);
|
||||
RB_EXTERN double rubberband_live_get_pitch_scale(const RubberBandLiveState);
|
||||
|
||||
RB_EXTERN void rubberband_live_set_formant_scale(RubberBandLiveState, double scale);
|
||||
RB_EXTERN double rubberband_live_get_formant_scale(const RubberBandLiveState);
|
||||
|
||||
RB_EXTERN unsigned int rubberband_live_get_start_delay(const RubberBandLiveState);
|
||||
|
||||
RB_EXTERN void rubberband_live_set_formant_option(RubberBandLiveState, RubberBandOptions options);
|
||||
|
||||
RB_EXTERN unsigned int rubberband_live_get_block_size(RubberBandLiveState);
|
||||
|
||||
RB_EXTERN void rubberband_live_shift(RubberBandLiveState, const float *const *input, float *const *output);
|
||||
|
||||
RB_EXTERN unsigned int rubberband_live_get_channel_count(const RubberBandLiveState);
|
||||
|
||||
RB_EXTERN void rubberband_live_set_debug_level(RubberBandLiveState, int level);
|
||||
RB_EXTERN void rubberband_live_set_default_debug_level(int level);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef RB_EXTERN
|
||||
|
||||
#endif
|
|
@ -1,16 +1,19 @@
|
|||
//
|
||||
// SpeedSlider.h
|
||||
// PitchSlider.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TempoSlider.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface SpeedSlider : NSSlider {
|
||||
@interface PitchSlider : NSSlider {
|
||||
NSPopover *popover;
|
||||
NSText *textView;
|
||||
IBOutlet NSSlider *_TempoSlider;
|
||||
}
|
||||
|
||||
- (void)showToolTip;
|
|
@ -1,18 +1,18 @@
|
|||
//
|
||||
// SpeedSlider.m
|
||||
// PitchSlider.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SpeedSlider.h"
|
||||
#import "PitchSlider.h"
|
||||
#import "CogAudio/Helper.h"
|
||||
#import "PlaybackController.h"
|
||||
|
||||
static void *kSpeedSliderContext = &kSpeedSliderContext;
|
||||
static void *kPitchSliderContext = &kPitchSliderContext;
|
||||
|
||||
@implementation SpeedSlider {
|
||||
@implementation PitchSlider {
|
||||
NSTimer *currentTimer;
|
||||
BOOL wasInsideSnapRange;
|
||||
/*BOOL observersadded;*/
|
||||
|
@ -55,22 +55,24 @@ static void *kSpeedSliderContext = &kSpeedSliderContext;
|
|||
}*/
|
||||
|
||||
- (void)updateToolTip {
|
||||
const double value = [self doubleValue];
|
||||
const double value = ([self doubleValue] - [self minValue]) * 100.0 / ([self maxValue] - [self minValue]);
|
||||
NSString *text;
|
||||
|
||||
double speed;
|
||||
if(value < 0.2) {
|
||||
speed = 0.2;
|
||||
} else if(value > 5.0) {
|
||||
speed = 5.0;
|
||||
const double adjustedValue = ((value * value) * (5.0 - 0.2) / 10000.0) + 0.2;
|
||||
|
||||
double pitch;
|
||||
if(adjustedValue < 0.2) {
|
||||
pitch = 0.2;
|
||||
} else if(adjustedValue > 5.0) {
|
||||
pitch = 5.0;
|
||||
} else {
|
||||
speed = value;
|
||||
pitch = adjustedValue;
|
||||
}
|
||||
|
||||
if(speed < 1)
|
||||
text = [NSString stringWithFormat:@"%0.2lf×", speed];
|
||||
if(pitch < 1)
|
||||
text = [NSString stringWithFormat:@"%0.2lf×", pitch];
|
||||
else
|
||||
text = [NSString stringWithFormat:@"%0.1lf×", speed];
|
||||
text = [NSString stringWithFormat:@"%0.1lf×", pitch];
|
||||
|
||||
[textView setString:text];
|
||||
}
|
||||
|
@ -128,7 +130,7 @@ static void *kSpeedSliderContext = &kSpeedSliderContext;
|
|||
}
|
||||
|
||||
/*- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if(context != kSpeedSliderContext) {
|
||||
if(context != kPitchSliderContext) {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
return;
|
||||
}
|
||||
|
@ -137,10 +139,21 @@ static void *kSpeedSliderContext = &kSpeedSliderContext;
|
|||
- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
|
||||
// Snap to 1.0× if value is close
|
||||
double snapTarget = 1.0;
|
||||
double snapProgress = ([self doubleValue] - snapTarget) / (self.maxValue - self.minValue);
|
||||
const double value = ([self doubleValue] - [self minValue]) * 100.0 / ([self maxValue] - [self minValue]);
|
||||
const double adjustedValue = ((value * value) * (5.0 - 0.2) / 10000.0) + 0.2;
|
||||
double snapProgress = (adjustedValue - snapTarget);
|
||||
|
||||
if(fabs(snapProgress) < 0.005) {
|
||||
[self setDoubleValue:snapTarget];
|
||||
BOOL speedLock = [[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"];
|
||||
if(speedLock) {
|
||||
[_TempoSlider setDoubleValue:[self doubleValue]];
|
||||
}
|
||||
|
||||
if(fabs(snapProgress) < 0.01) {
|
||||
const double inverseValue = sqrtf((snapTarget - 0.2) * 10000.0 / (5.0 - 0.2));
|
||||
[self setDoubleValue:inverseValue];
|
||||
if(speedLock) {
|
||||
[_TempoSlider setDoubleValue:inverseValue];
|
||||
}
|
||||
if(!wasInsideSnapRange) {
|
||||
[[NSHapticFeedbackManager defaultPerformer] performFeedbackPattern:NSHapticFeedbackPatternGeneric performanceTime:NSHapticFeedbackPerformanceTimeDefault];
|
||||
}
|
||||
|
@ -149,7 +162,7 @@ static void *kSpeedSliderContext = &kSpeedSliderContext;
|
|||
wasInsideSnapRange = NO;
|
||||
}
|
||||
|
||||
[self showToolTip];
|
||||
[self showToolTipForDuration:1.0];
|
||||
|
||||
return [super sendAction:theAction to:theTarget];
|
||||
}
|
||||
|
@ -159,7 +172,14 @@ static void *kSpeedSliderContext = &kSpeedSliderContext;
|
|||
|
||||
[self setDoubleValue:[self doubleValue] + change];
|
||||
|
||||
[[self target] changeSpeed:self];
|
||||
[[self target] changePitch:self];
|
||||
|
||||
BOOL speedLock = [[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"];
|
||||
if(speedLock) {
|
||||
[_TempoSlider setDoubleValue:[self doubleValue]];
|
||||
|
||||
[[self target] changeTempo:self];
|
||||
}
|
||||
|
||||
[self showToolTipForDuration:1.0];
|
||||
}
|
|
@ -1,16 +1,24 @@
|
|||
//
|
||||
// VolumeButton.h
|
||||
// SpeedButton.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/8/09.
|
||||
// Copyright 2009 __MyCompanyName__. All rights reserved.
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "VolumeSlider.h"
|
||||
#import "PitchSlider.h"
|
||||
#import "TempoSlider.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface VolumeButton : NSButton {
|
||||
IBOutlet VolumeSlider *_popView;
|
||||
@interface SpeedButton : NSButton {
|
||||
IBOutlet NSView *_popView;
|
||||
IBOutlet PitchSlider *_PitchSlider;
|
||||
IBOutlet TempoSlider *_TempoSlider;
|
||||
IBOutlet NSButton *_LockButton;
|
||||
IBOutlet NSButton *_ResetButton;
|
||||
}
|
||||
|
||||
- (IBAction)pressLock:(id)sender;
|
||||
- (IBAction)pressReset:(id)sender;
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
//
|
||||
// VolumeButton.m
|
||||
// SpeedButton.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/8/09.
|
||||
// Copyright 2009 __MyCompanyName__. All rights reserved.
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "VolumeButton.h"
|
||||
#import "SpeedButton.h"
|
||||
#import "PlaybackController.h"
|
||||
|
||||
@implementation VolumeButton {
|
||||
static double reverseSpeedScale(double input, double min, double max) {
|
||||
input = sqrtf((input - 0.2) * 10000.0 / (5.0 - 0.2));
|
||||
return (input * (max - min) / 100.0) + min;
|
||||
}
|
||||
|
||||
@implementation SpeedButton {
|
||||
NSPopover *popover;
|
||||
NSViewController *viewController;
|
||||
}
|
||||
|
@ -20,21 +25,6 @@
|
|||
[popover setContentSize:_popView.bounds.size];
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)theEvent {
|
||||
if([popover isShown]) {
|
||||
[_popView scrollWheel:theEvent];
|
||||
return;
|
||||
}
|
||||
|
||||
double change = [theEvent deltaY];
|
||||
|
||||
[_popView setDoubleValue:[_popView doubleValue] + change];
|
||||
|
||||
[[_popView target] changeVolume:_popView];
|
||||
|
||||
[_popView showToolTipForView:self closeAfter:1.0];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent {
|
||||
[popover close];
|
||||
|
||||
|
@ -48,4 +38,30 @@
|
|||
[super mouseDown:theEvent];
|
||||
}
|
||||
|
||||
- (IBAction)pressLock:(id)sender {
|
||||
BOOL speedLock = [[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"];
|
||||
speedLock = !speedLock;
|
||||
[_LockButton setTitle:speedLock ? @"🔒" : @"🔓"];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:speedLock forKey:@"speedLock"];
|
||||
|
||||
if(speedLock) {
|
||||
const double pitchValue = ([_PitchSlider doubleValue] - [_PitchSlider minValue]) / ([_PitchSlider maxValue] - [_PitchSlider minValue]);
|
||||
const double tempoValue = ([_TempoSlider doubleValue] - [_TempoSlider minValue]) / ([_TempoSlider maxValue] - [_TempoSlider minValue]);
|
||||
const double averageValue = (pitchValue + tempoValue) * 0.5;
|
||||
[_PitchSlider setDoubleValue:(averageValue * ([_PitchSlider maxValue] - [_PitchSlider minValue])) + [_PitchSlider minValue]];
|
||||
[_TempoSlider setDoubleValue:(averageValue * ([_TempoSlider maxValue] - [_TempoSlider minValue])) + [_TempoSlider minValue]];
|
||||
|
||||
[[_PitchSlider target] changePitch:_PitchSlider];
|
||||
[[_TempoSlider target] changeTempo:_TempoSlider];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)pressReset:(id)sender {
|
||||
[_PitchSlider setDoubleValue:reverseSpeedScale(1.0, [_PitchSlider minValue], [_PitchSlider maxValue])];
|
||||
[_TempoSlider setDoubleValue:reverseSpeedScale(1.0, [_TempoSlider minValue], [_TempoSlider maxValue])];
|
||||
|
||||
[[_PitchSlider target] changePitch:_PitchSlider];
|
||||
[[_TempoSlider target] changeTempo:_TempoSlider];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
//
|
||||
// VolumeSlider.h
|
||||
// TempoSlider.h
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/8/09.
|
||||
// Copyright 2009 __MyCompanyName__. All rights reserved.
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TempoSlider.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface VolumeSlider : NSSlider {
|
||||
@interface TempoSlider : NSSlider {
|
||||
NSPopover *popover;
|
||||
NSText *textView;
|
||||
double MAX_VOLUME;
|
||||
IBOutlet NSSlider *_PitchSlider;
|
||||
}
|
||||
|
||||
- (void)showToolTip;
|
|
@ -1,21 +1,21 @@
|
|||
//
|
||||
// VolumeSlider.m
|
||||
// TempoSlider.m
|
||||
// Cog
|
||||
//
|
||||
// Created by Vincent Spader on 2/8/09.
|
||||
// Copyright 2009 __MyCompanyName__. All rights reserved.
|
||||
// Created by Christopher Snowhill on 9/20/24.
|
||||
// Copyright 2024 __LoSnoCo__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "VolumeSlider.h"
|
||||
#import "TempoSlider.h"
|
||||
#import "CogAudio/Helper.h"
|
||||
#import "PlaybackController.h"
|
||||
|
||||
static void *kVolumeSliderContext = &kVolumeSliderContext;
|
||||
static void *kTempoSliderContext = &kTempoSliderContext;
|
||||
|
||||
@implementation VolumeSlider {
|
||||
@implementation TempoSlider {
|
||||
NSTimer *currentTimer;
|
||||
BOOL wasInsideSnapRange;
|
||||
BOOL observersadded;
|
||||
/*BOOL observersadded;*/
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(NSRect)frame {
|
||||
|
@ -29,9 +29,6 @@ static void *kVolumeSliderContext = &kVolumeSliderContext;
|
|||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
||||
MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
||||
|
||||
wasInsideSnapRange = NO;
|
||||
textView = [[NSText alloc] init];
|
||||
[textView setFrame:NSMakeRect(0, 0, 50, 20)];
|
||||
|
@ -49,31 +46,33 @@ static void *kVolumeSliderContext = &kVolumeSliderContext;
|
|||
popover.animates = NO;
|
||||
[popover setContentSize:textView.bounds.size];
|
||||
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeLimit" options:0 context:kVolumeSliderContext];
|
||||
observersadded = YES;
|
||||
/*observersadded = YES;*/
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
/*- (void)dealloc {
|
||||
if(observersadded) {
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeLimit" context:kVolumeSliderContext];
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
- (void)updateToolTip {
|
||||
const double value = [self doubleValue];
|
||||
// Sets volume to be the slider value if limit is set to 100% or the actual volume otherwise.
|
||||
const double volume = (MAX_VOLUME == 100) ? value : linearToLogarithmic(value, MAX_VOLUME);
|
||||
const double value = ([self doubleValue] - [self minValue]) * 100.0 / ([self maxValue] - [self minValue]);
|
||||
NSString *text;
|
||||
|
||||
// If volume becomes less than 1%, display two decimal digits of precision (e.g. 0.34%).
|
||||
if(volume < 1)
|
||||
text = [NSString stringWithFormat:@"%0.2lf%%", volume];
|
||||
// Else if volume becomes less than 10%, display one decimal digit of precision (e.g. 3.4%).
|
||||
else if(volume < 10)
|
||||
text = [NSString stringWithFormat:@"%0.1lf%%", volume];
|
||||
// Else display no decimal digits.
|
||||
const double adjustedValue = ((value * value) * (5.0 - 0.2) / 10000.0) + 0.2;
|
||||
|
||||
double tempo;
|
||||
if(adjustedValue < 0.2) {
|
||||
tempo = 0.2;
|
||||
} else if(adjustedValue > 5.0) {
|
||||
tempo = 5.0;
|
||||
} else {
|
||||
tempo = adjustedValue;
|
||||
}
|
||||
|
||||
if(tempo < 1)
|
||||
text = [NSString stringWithFormat:@"%0.2lf×", tempo];
|
||||
else
|
||||
text = [NSString stringWithFormat:@"%0.lf%%", volume];
|
||||
text = [NSString stringWithFormat:@"%0.1lf×", tempo];
|
||||
|
||||
[textView setString:text];
|
||||
}
|
||||
|
@ -130,31 +129,31 @@ static void *kVolumeSliderContext = &kVolumeSliderContext;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if(context != kVolumeSliderContext) {
|
||||
/*- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||
if(context != kTempoSliderContext) {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
return;
|
||||
}
|
||||
|
||||
if([keyPath isEqualToString:@"values.volumeLimit"]) {
|
||||
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
||||
const double new_MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
||||
|
||||
if(MAX_VOLUME != new_MAX_VOLUME) {
|
||||
double currentLevel = linearToLogarithmic([self doubleValue], MAX_VOLUME);
|
||||
[self setDoubleValue:logarithmicToLinear(currentLevel, new_MAX_VOLUME)];
|
||||
}
|
||||
MAX_VOLUME = new_MAX_VOLUME;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
- (BOOL)sendAction:(SEL)theAction to:(id)theTarget {
|
||||
// Snap to 100% if value is close
|
||||
double snapTarget = logarithmicToLinear(100.0, MAX_VOLUME);
|
||||
double snapProgress = ([self doubleValue] - snapTarget) / (self.maxValue - self.minValue);
|
||||
// Snap to 1.0× if value is close
|
||||
double snapTarget = 1.0;
|
||||
const double value = ([self doubleValue] - [self minValue]) * 100.0 / ([self maxValue] - [self minValue]);
|
||||
const double adjustedValue = ((value * value) * (5.0 - 0.2) / 10000.0) + 0.2;
|
||||
double snapProgress = (adjustedValue - snapTarget);
|
||||
|
||||
if(fabs(snapProgress) < 0.005) {
|
||||
[self setDoubleValue:snapTarget];
|
||||
BOOL speedLock = [[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"];
|
||||
if(speedLock) {
|
||||
[_PitchSlider setDoubleValue:[self doubleValue]];
|
||||
}
|
||||
|
||||
if(fabs(snapProgress) < 0.01) {
|
||||
const double inverseValue = sqrtf((snapTarget - 0.2) * 10000.0 / (5.0 - 0.2));
|
||||
[self setDoubleValue:inverseValue];
|
||||
if(speedLock) {
|
||||
[_PitchSlider setDoubleValue:inverseValue];
|
||||
}
|
||||
if(!wasInsideSnapRange) {
|
||||
[[NSHapticFeedbackManager defaultPerformer] performFeedbackPattern:NSHapticFeedbackPatternGeneric performanceTime:NSHapticFeedbackPerformanceTimeDefault];
|
||||
}
|
||||
|
@ -163,7 +162,7 @@ static void *kVolumeSliderContext = &kVolumeSliderContext;
|
|||
wasInsideSnapRange = NO;
|
||||
}
|
||||
|
||||
[self showToolTip];
|
||||
[self showToolTipForDuration:1.0];
|
||||
|
||||
return [super sendAction:theAction to:theTarget];
|
||||
}
|
||||
|
@ -173,7 +172,14 @@ static void *kVolumeSliderContext = &kVolumeSliderContext;
|
|||
|
||||
[self setDoubleValue:[self doubleValue] + change];
|
||||
|
||||
[[self target] changeVolume:self];
|
||||
[[self target] changeTempo:self];
|
||||
|
||||
BOOL speedLock = [[NSUserDefaults standardUserDefaults] boolForKey:@"speedLock"];
|
||||
if(speedLock) {
|
||||
[_PitchSlider setDoubleValue:[self doubleValue]];
|
||||
|
||||
[[self target] changePitch:self];
|
||||
}
|
||||
|
||||
[self showToolTipForDuration:1.0];
|
||||
}
|
|
@ -35,6 +35,7 @@
|
|||
<br><br>
|
||||
<em>This program has been made possible through contributions from users like you.</em>
|
||||
<br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses.
|
||||
<br><br> <a href="https://breakfastquay.com/rubberband/">Rubber Band Library</a> was used under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a> to provide pitch and/or time shifting.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<br><br>
|
||||
<em>Este programa ha sido posible gracias a las contribuciones de usuarios y usuarias como tú.</em>
|
||||
<br><br> Todo el código de Cog es de mi propiedad, y está licenciado bajo la <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contiene código de terceros que están bajo sus propias licencias.
|
||||
<br><br> La biblioteca <a href="https://breakfastquay.com/rubberband/">Rubber Band</a> se usa bajo licencia <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a> para transponer tono y/o cambiar velocidad.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<br><br>
|
||||
<em>This program has been made possible through contributions from users like you.</em>
|
||||
<br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses.
|
||||
<br><br> Biblioteka <a href="https://breakfastquay.com/rubberband/">Rubber Band Library</a> była używana zgodnie z zasadami licencji <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>, aby dostarczyć funkcję zmiany tonu i/lub przerwy w czasie.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
<br><br>
|
||||
<em>Создние этой программы стало возможным благодаря вкладу таких пользователей, как вы.</em>
|
||||
<br><br> Весь код Cog защищен моим авторским правом и распространяется под лицензией <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog содержит фрагменты другого кода от третьих сторон, который находятся под их собственными лицензиями.
|
||||
|
||||
<br><br> Библиотека <a href="https://breakfastquay.com/rubberband/">Rubber Band Library</a> использовалась под лицензией <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a> для предоставления функции изменения тона и/или сдвига во времени.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<br><br>
|
||||
<em>This program has been made possible through contributions from users like you.</em>
|
||||
<br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses.
|
||||
<br><br> <a href="https://breakfastquay.com/rubberband/">Rubber Band Kütüphanesi</a>, ton ve/veya zaman kayması sağlamak için <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a> altında kullanıldı.
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
Loading…
Reference in a new issue