2006-01-20 15:41:31 +00:00
|
|
|
#import "PlaybackController.h"
|
2022-02-07 05:49:27 +00:00
|
|
|
#import "CogAudio/Helper.h"
|
|
|
|
#import "CogAudio/Status.h"
|
2006-01-20 15:41:31 +00:00
|
|
|
#import "PlaylistView.h"
|
2008-02-12 22:12:27 +00:00
|
|
|
#import <Foundation/NSTimer.h>
|
2006-01-20 15:41:31 +00:00
|
|
|
|
2007-03-14 02:28:30 +00:00
|
|
|
#import "PlaylistController.h"
|
|
|
|
#import "PlaylistEntry.h"
|
2018-06-28 10:59:59 +00:00
|
|
|
#import "PlaylistLoader.h"
|
2007-03-14 02:28:30 +00:00
|
|
|
|
2022-01-21 07:53:45 +00:00
|
|
|
#import "MainWindow.h"
|
|
|
|
#import "MiniWindow.h"
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
#import <MediaPlayer/MPMediaItem.h>
|
2019-11-14 03:13:59 +00:00
|
|
|
#import <MediaPlayer/MPNowPlayingInfoCenter.h>
|
|
|
|
#import <MediaPlayer/MPRemoteCommand.h>
|
2022-02-07 05:49:27 +00:00
|
|
|
#import <MediaPlayer/MPRemoteCommandCenter.h>
|
2019-11-14 03:13:59 +00:00
|
|
|
#import <MediaPlayer/MPRemoteCommandEvent.h>
|
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
#import "Logging.h"
|
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
@implementation PlaybackController
|
|
|
|
|
2008-02-28 13:11:37 +00:00
|
|
|
#define DEFAULT_SEEK 5
|
2008-02-10 18:34:23 +00:00
|
|
|
|
2009-03-05 17:03:30 +00:00
|
|
|
NSString *CogPlaybackDidBeginNotficiation = @"CogPlaybackDidBeginNotficiation";
|
|
|
|
NSString *CogPlaybackDidPauseNotficiation = @"CogPlaybackDidPauseNotficiation";
|
|
|
|
NSString *CogPlaybackDidResumeNotficiation = @"CogPlaybackDidResumeNotficiation";
|
|
|
|
NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation";
|
|
|
|
|
2008-02-23 22:20:14 +00:00
|
|
|
@synthesize playbackStatus;
|
2008-02-13 01:50:39 +00:00
|
|
|
|
2022-01-09 10:10:08 +00:00
|
|
|
@synthesize progressBarStatus;
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSSet *)keyPathsForValuesAffectingSeekable {
|
|
|
|
return [NSSet setWithObjects:@"playlistController.currentEntry", @"playlistController.currentEntry.seekable", nil];
|
2009-02-22 22:28:09 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (id)init {
|
2006-01-20 15:41:31 +00:00
|
|
|
self = [super init];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(self) {
|
2007-02-26 05:26:48 +00:00
|
|
|
[self initDefaults];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2009-02-28 21:19:26 +00:00
|
|
|
seekable = NO;
|
|
|
|
fading = NO;
|
2022-02-07 05:49:27 +00:00
|
|
|
_eqWasOpen = NO;
|
|
|
|
_equi = nil;
|
|
|
|
|
|
|
|
progressBarStatus = -1;
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
audioPlayer = [[AudioPlayer alloc] init];
|
|
|
|
[audioPlayer setDelegate:self];
|
2022-02-07 05:49:27 +00:00
|
|
|
[self setPlaybackStatus:CogStatusStopped];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)initDefaults {
|
2007-02-26 05:26:48 +00:00
|
|
|
NSDictionary *defaultsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
|
2022-02-07 05:49:27 +00:00
|
|
|
[NSNumber numberWithDouble:100.0], @"volume",
|
|
|
|
[NSNumber numberWithBool:NO], @"GraphicEQenable",
|
|
|
|
[NSNumber numberWithInt:-1], @"GraphicEQpreset",
|
|
|
|
[NSNumber numberWithBool:NO], @"GraphicEQtrackgenre",
|
|
|
|
[NSNumber numberWithBool:YES], @"volumeLimit",
|
|
|
|
[NSNumber numberWithBool:NO], @"headphoneVirtualization",
|
|
|
|
nil];
|
|
|
|
|
2007-02-26 05:26:48 +00:00
|
|
|
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary];
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)awakeFromNib {
|
|
|
|
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
|
|
|
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
2007-02-28 00:35:27 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
double volume = [[NSUserDefaults standardUserDefaults] doubleForKey:@"volume"];
|
2022-01-18 06:41:26 +00:00
|
|
|
|
|
|
|
[volumeSlider setDoubleValue:logarithmicToLinear(volume, MAX_VOLUME)];
|
2009-02-28 18:19:15 +00:00
|
|
|
[audioPlayer setVolume:volume];
|
2009-02-22 22:28:09 +00:00
|
|
|
|
|
|
|
[self setSeekable:NO];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
- (IBAction)playPauseResume:(id)sender {
|
|
|
|
if(playbackStatus == CogStatusStopped || playbackStatus == CogStatusStopping) {
|
2006-01-20 15:41:31 +00:00
|
|
|
[self play:self];
|
2022-02-07 05:49:27 +00:00
|
|
|
} else {
|
2006-01-20 15:41:31 +00:00
|
|
|
[self pauseResume:self];
|
2008-02-22 03:09:03 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
[self sendMetaData];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)pauseResume:(id)sender {
|
|
|
|
if(playbackStatus == CogStatusPaused)
|
2006-01-20 15:41:31 +00:00
|
|
|
[self resume:self];
|
|
|
|
else
|
|
|
|
[self pause:self];
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)pause:(id)sender {
|
|
|
|
[[NSUserDefaults standardUserDefaults] setInteger:CogStatusPaused forKey:@"lastPlaybackStatus"];
|
2022-01-09 10:34:29 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[audioPlayer pause];
|
|
|
|
[self setPlaybackStatus:CogStatusPaused];
|
2006-01-20 15:41:31 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[self sendMetaData];
|
|
|
|
}
|
2022-01-09 10:34:29 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)resume:(id)sender {
|
|
|
|
[[NSUserDefaults standardUserDefaults] setInteger:CogStatusPlaying forKey:@"lastPlaybackStatus"];
|
2007-02-25 02:43:56 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[audioPlayer resume];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)stop:(id)sender {
|
|
|
|
[[NSUserDefaults standardUserDefaults] setInteger:CogStatusStopped forKey:@"lastPlaybackStatus"];
|
|
|
|
|
|
|
|
[self audioPlayer:audioPlayer removeEqualizer:_eq];
|
2022-01-09 10:34:29 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[audioPlayer stop];
|
2019-11-14 03:13:59 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[self sendMetaData];
|
|
|
|
|
|
|
|
[self removeHDCD:nil];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
// called by double-clicking on table
|
|
|
|
- (void)playEntryAtIndex:(NSInteger)i {
|
|
|
|
[self playEntryAtIndex:i startPaused:NO andSeekTo:[NSNumber numberWithDouble:0.0]];
|
2013-10-13 02:16:47 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)playEntryAtIndex:(NSInteger)i startPaused:(BOOL)paused {
|
|
|
|
PlaylistEntry *pe = [playlistController entryAtIndex:i];
|
2021-12-26 12:35:54 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[self playEntry:pe startPaused:paused andSeekTo:[NSNumber numberWithDouble:0.0]];
|
2021-12-26 12:35:54 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)playEntryAtIndex:(NSInteger)i startPaused:(BOOL)paused andSeekTo:(id)offset {
|
2008-02-20 13:20:07 +00:00
|
|
|
PlaylistEntry *pe = [playlistController entryAtIndex:i];
|
2006-01-20 15:41:31 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[self playEntry:pe startPaused:paused andSeekTo:offset];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)play:(id)sender {
|
|
|
|
if([playlistView selectedRow] == -1)
|
2013-10-03 08:00:58 +00:00
|
|
|
[playlistView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
2008-11-21 15:43:34 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if([playlistView selectedRow] > -1)
|
2016-06-30 05:10:29 +00:00
|
|
|
[self playEntryAtIndex:(int)[playlistView selectedRow]];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
NSDictionary *makeRGInfo(PlaylistEntry *pe) {
|
|
|
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
|
|
if([pe replayGainAlbumGain] != 0)
|
|
|
|
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainAlbumGain]] forKey:@"replayGainAlbumGain"];
|
|
|
|
if([pe replayGainAlbumPeak] != 0)
|
|
|
|
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainAlbumPeak]] forKey:@"replayGainAlbumPeak"];
|
|
|
|
if([pe replayGainTrackGain] != 0)
|
|
|
|
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainTrackGain]] forKey:@"replayGainTrackGain"];
|
|
|
|
if([pe replayGainTrackPeak] != 0)
|
|
|
|
[dictionary setObject:[NSNumber numberWithFloat:[pe replayGainTrackPeak]] forKey:@"replayGainTrackPeak"];
|
|
|
|
if([pe volume] != 1)
|
|
|
|
[dictionary setObject:[NSNumber numberWithFloat:[pe volume]] forKey:@"volume"];
|
|
|
|
return dictionary;
|
2013-10-13 02:16:47 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)playEntry:(PlaylistEntry *)pe {
|
|
|
|
[self playEntry:pe startPaused:NO andSeekTo:[NSNumber numberWithDouble:0.0]];
|
2021-12-26 12:35:54 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)playEntry:(PlaylistEntry *)pe startPaused:(BOOL)paused {
|
|
|
|
[self playEntry:pe startPaused:paused andSeekTo:[NSNumber numberWithDouble:0.0]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)playEntry:(PlaylistEntry *)pe startPaused:(BOOL)paused andSeekTo:(id)offset {
|
|
|
|
if(playbackStatus != CogStatusStopped && playbackStatus != CogStatusStopping)
|
2006-01-29 14:57:48 +00:00
|
|
|
[self stop:self];
|
2006-05-13 15:52:52 +00:00
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
DLog(@"PLAYLIST CONTROLLER: %@", [playlistController class]);
|
2008-02-22 03:09:03 +00:00
|
|
|
[playlistController setCurrentEntry:pe];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
lastPosition = -10;
|
|
|
|
|
2021-12-26 12:35:54 +00:00
|
|
|
[self setPosition:[offset doubleValue]];
|
2008-02-22 03:09:03 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if(pe == nil)
|
2008-02-22 03:09:03 +00:00
|
|
|
return;
|
2021-02-28 10:47:00 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
BOOL loadData = YES;
|
|
|
|
NSString *urlScheme = [[pe URL] scheme];
|
|
|
|
if([urlScheme isEqualToString:@"http"] ||
|
|
|
|
[urlScheme isEqualToString:@"https"])
|
|
|
|
loadData = NO;
|
2021-02-28 10:47:00 +00:00
|
|
|
|
2016-05-08 05:41:28 +00:00
|
|
|
#if 0
|
2013-10-07 23:15:15 +00:00
|
|
|
// Race here, but the worst that could happen is we re-read the data
|
2016-05-08 05:41:28 +00:00
|
|
|
if ([pe metadataLoaded] != YES) {
|
2013-10-07 23:15:15 +00:00
|
|
|
[pe performSelectorOnMainThread:@selector(setMetadata:) withObject:[playlistLoader readEntryInfo:pe] waitUntilDone:YES];
|
|
|
|
}
|
2016-09-04 19:49:43 +00:00
|
|
|
#elif 0
|
2022-02-07 05:49:27 +00:00
|
|
|
// Racing with this version is less likely to jam up the main thread
|
|
|
|
if([pe metadataLoaded] != YES) {
|
|
|
|
NSArray *entries = @[pe];
|
|
|
|
[playlistLoader loadInfoForEntries:entries];
|
|
|
|
}
|
2016-09-04 19:49:43 +00:00
|
|
|
#else
|
2022-02-07 05:49:27 +00:00
|
|
|
// Let's do it this way instead
|
|
|
|
if([pe metadataLoaded] != YES && loadData == YES) {
|
|
|
|
NSArray *entries = @[pe];
|
|
|
|
[playlistLoader performSelectorInBackground:@selector(loadInfoForEntries:) withObject:entries];
|
|
|
|
}
|
2016-05-08 05:41:28 +00:00
|
|
|
#endif
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
[self sendMetaData];
|
|
|
|
|
|
|
|
[audioPlayer play:[pe URL] withUserInfo:pe withRGInfo:makeRGInfo(pe) startPaused:paused andSeekTo:[offset doubleValue]];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)next:(id)sender {
|
|
|
|
if([playlistController next] == NO)
|
2006-01-20 15:41:31 +00:00
|
|
|
return;
|
2006-01-29 14:57:48 +00:00
|
|
|
|
2007-06-05 03:09:55 +00:00
|
|
|
[self playEntry:[playlistController currentEntry]];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)prev:(id)sender {
|
|
|
|
if([playlistController prev] == NO)
|
2006-01-20 15:41:31 +00:00
|
|
|
return;
|
|
|
|
|
2007-06-05 03:09:55 +00:00
|
|
|
[self playEntry:[playlistController currentEntry]];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)updatePosition:(id)sender {
|
2009-02-22 22:28:09 +00:00
|
|
|
double pos = [audioPlayer amountPlayed];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2009-02-22 22:28:09 +00:00
|
|
|
[self setPosition:pos];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
[[playlistController currentEntry] setCurrentPosition:pos];
|
2009-02-22 22:28:09 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)seek:(id)sender {
|
2009-02-22 22:28:09 +00:00
|
|
|
double time = [sender doubleValue];
|
2006-04-18 17:00:29 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[audioPlayer seekToTime:time];
|
|
|
|
|
|
|
|
lastPosition = -10;
|
|
|
|
|
|
|
|
[self setPosition:time];
|
2013-10-04 11:16:09 +00:00
|
|
|
|
|
|
|
[[playlistController currentEntry] setCurrentPosition:time];
|
2019-11-14 03:13:59 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)seek:(id)sender toTime:(NSTimeInterval)position {
|
|
|
|
double time = (double)(position);
|
|
|
|
|
|
|
|
lastPosition = -10;
|
|
|
|
|
|
|
|
[audioPlayer seekToTime:time];
|
2013-10-04 11:16:09 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[self setPosition:time];
|
|
|
|
|
|
|
|
[[playlistController currentEntry] setCurrentPosition:time];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)spam:(id)sender {
|
|
|
|
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
|
|
|
|
|
|
|
|
[pboard clearContents];
|
|
|
|
|
|
|
|
[pboard writeObjects:@[[[playlistController currentEntry] spam]]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)eventSeekForward:(id)sender {
|
2008-02-13 18:03:06 +00:00
|
|
|
[self seekForward:DEFAULT_SEEK];
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)seekForward:(double)amount {
|
2008-02-13 18:03:06 +00:00
|
|
|
double seekTo = [audioPlayer amountPlayed] + amount;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(seekTo > [[[playlistController currentEntry] length] doubleValue]) {
|
2008-02-07 23:57:21 +00:00
|
|
|
[self next:self];
|
2022-02-07 05:49:27 +00:00
|
|
|
} else {
|
|
|
|
lastPosition = -10;
|
2008-02-10 18:34:23 +00:00
|
|
|
[audioPlayer seekToTime:seekTo];
|
2009-02-22 22:28:09 +00:00
|
|
|
[self setPosition:seekTo];
|
2008-02-07 23:57:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)eventSeekBackward:(id)sender {
|
2008-02-13 18:03:06 +00:00
|
|
|
[self seekBackward:DEFAULT_SEEK];
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)seekBackward:(double)amount {
|
2008-02-13 18:03:06 +00:00
|
|
|
double seekTo = [audioPlayer amountPlayed] - amount;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(seekTo < 0)
|
2008-02-17 18:44:11 +00:00
|
|
|
seekTo = 0;
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
lastPosition = -10;
|
|
|
|
|
2008-02-17 18:44:11 +00:00
|
|
|
[audioPlayer seekToTime:seekTo];
|
2009-02-22 22:28:09 +00:00
|
|
|
[self setPosition:seekTo];
|
2008-02-07 23:57:21 +00:00
|
|
|
}
|
|
|
|
|
2009-02-28 21:13:06 +00:00
|
|
|
/*
|
|
|
|
- (void)changePlayButtonImage:(NSString *)name
|
2006-01-20 15:41:31 +00:00
|
|
|
{
|
2022-02-07 05:49:27 +00:00
|
|
|
NSImage *img = [NSImage imageNamed:name];
|
2007-11-01 01:53:52 +00:00
|
|
|
// [img retain];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if (img == nil)
|
|
|
|
{
|
|
|
|
DLog(@"Error loading image!");
|
|
|
|
}
|
|
|
|
|
|
|
|
[playbackButtons setImage:img forSegment:1];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
2009-02-28 21:13:06 +00:00
|
|
|
*/
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)changeVolume:(id)sender {
|
|
|
|
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
|
|
|
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
2022-01-18 06:41:26 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
DLog(@"VOLUME: %lf, %lf", [sender doubleValue], linearToLogarithmic([sender doubleValue], MAX_VOLUME));
|
2008-02-13 01:50:39 +00:00
|
|
|
|
2022-01-18 06:41:26 +00:00
|
|
|
[audioPlayer setVolume:linearToLogarithmic([sender doubleValue], MAX_VOLUME)];
|
2009-02-28 18:19:15 +00:00
|
|
|
|
|
|
|
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer volume] forKey:@"volume"];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2008-02-12 22:12:27 +00:00
|
|
|
/* selector for NSTimer - gets passed the Timer object itself
|
|
|
|
and the appropriate userInfo, which in this case is an NSNumber
|
|
|
|
containing the current volume before we start fading. */
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioFadeDown:(NSTimer *)audioTimer {
|
2008-02-13 01:50:39 +00:00
|
|
|
double volume = [audioPlayer volume];
|
|
|
|
double originalVolume = [[audioTimer userInfo] doubleValue];
|
2022-02-07 05:49:27 +00:00
|
|
|
double down = originalVolume / 10;
|
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
DLog(@"VOLUME IS %lf", volume);
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(volume > 0.0001) // YAY! Roundoff error!
|
2008-02-12 22:12:27 +00:00
|
|
|
{
|
2008-02-17 18:44:11 +00:00
|
|
|
[audioPlayer volumeDown:down];
|
2022-02-07 05:49:27 +00:00
|
|
|
} else // volume is at 0 or below, we are ready to release the timer and move on
|
2008-02-12 22:12:27 +00:00
|
|
|
{
|
2022-02-07 05:49:27 +00:00
|
|
|
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
|
|
|
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
2022-01-18 06:41:26 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[audioPlayer pause];
|
2008-02-13 01:50:39 +00:00
|
|
|
[audioPlayer setVolume:originalVolume];
|
2022-02-07 05:49:27 +00:00
|
|
|
[volumeSlider setDoubleValue:logarithmicToLinear(originalVolume, MAX_VOLUME)];
|
2008-02-12 22:12:27 +00:00
|
|
|
[audioTimer invalidate];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2009-02-28 21:19:26 +00:00
|
|
|
fading = NO;
|
2008-02-12 22:12:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioFadeUp:(NSTimer *)audioTimer {
|
2008-02-16 16:30:18 +00:00
|
|
|
double volume = [audioPlayer volume];
|
|
|
|
double originalVolume = [[audioTimer userInfo] doubleValue];
|
2022-02-07 05:49:27 +00:00
|
|
|
double up = originalVolume / 10;
|
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
DLog(@"VOLUME IS %lf", volume);
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(originalVolume - volume > 0.0001) {
|
|
|
|
if((volume + up) > originalVolume)
|
2008-02-17 18:44:11 +00:00
|
|
|
[audioPlayer volumeUp:(originalVolume - volume)];
|
2008-02-16 16:30:18 +00:00
|
|
|
else
|
2008-02-17 18:44:11 +00:00
|
|
|
[audioPlayer volumeUp:up];
|
2022-02-07 05:49:27 +00:00
|
|
|
} else // volume is at or near original level, we are ready to release the timer and move on
|
2008-02-16 16:30:18 +00:00
|
|
|
{
|
2022-02-07 05:49:27 +00:00
|
|
|
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
|
|
|
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
2022-01-18 06:41:26 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[audioPlayer setVolume:originalVolume];
|
|
|
|
[volumeSlider setDoubleValue:logarithmicToLinear(originalVolume, MAX_VOLUME)];
|
2008-02-16 16:30:18 +00:00
|
|
|
[audioTimer invalidate];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2009-02-28 21:19:26 +00:00
|
|
|
fading = NO;
|
2008-02-16 16:30:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)fade:(id)sender {
|
2008-02-23 22:20:14 +00:00
|
|
|
double time = 0.1;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2008-02-13 18:03:06 +00:00
|
|
|
// we can not allow multiple fade timers to be registered
|
2022-02-07 05:49:27 +00:00
|
|
|
if(YES == fading)
|
2008-02-13 18:03:06 +00:00
|
|
|
return;
|
2009-02-28 21:19:26 +00:00
|
|
|
fading = YES;
|
2008-02-16 16:30:18 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
NSNumber *originalVolume = [NSNumber numberWithDouble:[audioPlayer volume]];
|
|
|
|
NSTimer *fadeTimer;
|
|
|
|
|
|
|
|
if(playbackStatus == CogStatusPlaying) {
|
2009-02-09 06:16:16 +00:00
|
|
|
fadeTimer = [NSTimer timerWithTimeInterval:time
|
2022-02-07 05:49:27 +00:00
|
|
|
target:self
|
|
|
|
selector:@selector(audioFadeDown:)
|
|
|
|
userInfo:originalVolume
|
|
|
|
repeats:YES];
|
2009-02-09 06:16:16 +00:00
|
|
|
[[NSRunLoop currentRunLoop] addTimer:fadeTimer forMode:NSRunLoopCommonModes];
|
2022-02-07 05:49:27 +00:00
|
|
|
} else {
|
2008-02-16 16:30:18 +00:00
|
|
|
[audioPlayer setVolume:0];
|
2009-02-09 06:16:16 +00:00
|
|
|
fadeTimer = [NSTimer timerWithTimeInterval:time
|
2022-02-07 05:49:27 +00:00
|
|
|
target:self
|
|
|
|
selector:@selector(audioFadeUp:)
|
|
|
|
userInfo:originalVolume
|
|
|
|
repeats:YES];
|
2009-02-09 06:16:16 +00:00
|
|
|
[[NSRunLoop currentRunLoop] addTimer:fadeTimer forMode:NSRunLoopCommonModes];
|
2008-02-16 16:30:18 +00:00
|
|
|
[self pauseResume:self];
|
|
|
|
}
|
2008-02-12 22:12:27 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)skipToNextAlbum:(id)sender {
|
|
|
|
BOOL found = NO;
|
|
|
|
|
2021-04-30 01:16:24 +00:00
|
|
|
NSInteger index = [[playlistController currentEntry] index];
|
2008-02-20 00:12:25 +00:00
|
|
|
NSString *origAlbum = [[playlistController currentEntry] album];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2021-04-30 01:16:24 +00:00
|
|
|
NSInteger i;
|
2008-02-14 19:25:01 +00:00
|
|
|
NSString *curAlbum;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2008-02-14 19:25:01 +00:00
|
|
|
PlaylistEntry *pe;
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
for(i = 1; i < [[playlistController arrangedObjects] count]; i++) {
|
2008-02-23 22:20:14 +00:00
|
|
|
pe = [playlistController entryAtIndex:index + i];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(pe == nil)
|
2008-02-20 13:20:07 +00:00
|
|
|
break;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2008-02-14 19:25:01 +00:00
|
|
|
curAlbum = [pe album];
|
|
|
|
|
|
|
|
// check for untagged files, and just play the first untagged one
|
|
|
|
// we come across
|
2022-02-07 05:49:27 +00:00
|
|
|
if(curAlbum == nil) {
|
2008-02-20 13:20:07 +00:00
|
|
|
found = YES;
|
|
|
|
break;
|
2008-02-14 19:25:01 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if([curAlbum caseInsensitiveCompare:origAlbum] != NSOrderedSame) {
|
2008-02-14 19:25:01 +00:00
|
|
|
found = YES;
|
2008-02-20 13:20:07 +00:00
|
|
|
break;
|
2008-02-14 19:25:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if(found) {
|
2008-02-23 22:20:14 +00:00
|
|
|
[self playEntryAtIndex:i + index];
|
2008-02-20 13:20:07 +00:00
|
|
|
}
|
2008-02-14 19:25:01 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)skipToPreviousAlbum:(id)sender {
|
2008-02-20 13:20:07 +00:00
|
|
|
BOOL found = NO;
|
2008-02-14 19:25:01 +00:00
|
|
|
BOOL foundAlbum = NO;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2021-04-30 01:16:24 +00:00
|
|
|
NSInteger index = [[playlistController currentEntry] index];
|
2008-02-20 00:12:25 +00:00
|
|
|
NSString *origAlbum = [[playlistController currentEntry] album];
|
2008-02-14 19:25:01 +00:00
|
|
|
NSString *curAlbum;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2021-04-30 01:16:24 +00:00
|
|
|
NSInteger i;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2008-02-14 19:25:01 +00:00
|
|
|
PlaylistEntry *pe;
|
2008-02-20 13:20:07 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
for(i = 1; i < [[playlistController arrangedObjects] count]; i++) {
|
2008-02-23 22:20:14 +00:00
|
|
|
pe = [playlistController entryAtIndex:index - i];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(pe == nil)
|
2008-02-20 13:20:07 +00:00
|
|
|
break;
|
2008-02-23 22:20:14 +00:00
|
|
|
|
2008-02-14 19:25:01 +00:00
|
|
|
curAlbum = [pe album];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(curAlbum == nil) {
|
2008-02-20 13:20:07 +00:00
|
|
|
found = YES;
|
|
|
|
break;
|
2008-02-14 19:25:01 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if([curAlbum caseInsensitiveCompare:origAlbum] != NSOrderedSame) {
|
|
|
|
if(foundAlbum == NO) {
|
2008-02-14 19:25:01 +00:00
|
|
|
foundAlbum = YES;
|
2008-02-15 15:27:34 +00:00
|
|
|
// now we need to move up to the first song in the album, so we'll
|
|
|
|
// go till we either find index 0, or the first song in the album
|
2008-02-20 13:20:07 +00:00
|
|
|
origAlbum = curAlbum;
|
|
|
|
continue;
|
2022-02-07 05:49:27 +00:00
|
|
|
} else {
|
2008-02-14 19:25:01 +00:00
|
|
|
found = YES; // terminate loop
|
2008-02-20 13:20:07 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-02-14 19:25:01 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(found || foundAlbum) {
|
|
|
|
if(foundAlbum == YES)
|
2008-02-20 13:20:07 +00:00
|
|
|
i--;
|
2008-02-23 22:20:14 +00:00
|
|
|
[self playEntryAtIndex:index - i];
|
2008-02-20 13:20:07 +00:00
|
|
|
}
|
2008-02-14 19:25:01 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)volumeDown:(id)sender {
|
|
|
|
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
|
|
|
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
2008-02-14 19:25:01 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
double newVolume = [audioPlayer volumeDown:DEFAULT_VOLUME_DOWN];
|
2022-01-18 06:41:26 +00:00
|
|
|
[volumeSlider setDoubleValue:logarithmicToLinear(newVolume, MAX_VOLUME)];
|
2007-02-18 23:41:44 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer volume] forKey:@"volume"];
|
2008-02-13 18:03:06 +00:00
|
|
|
}
|
2008-02-12 22:12:27 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)volumeUp:(id)sender {
|
|
|
|
BOOL volumeLimit = [[[NSUserDefaultsController sharedUserDefaultsController] defaults] boolForKey:@"volumeLimit"];
|
|
|
|
const double MAX_VOLUME = (volumeLimit) ? 100.0 : 800.0;
|
2022-01-18 06:41:26 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
double newVolume;
|
2008-02-17 18:44:11 +00:00
|
|
|
newVolume = [audioPlayer volumeUp:DEFAULT_VOLUME_UP];
|
2022-01-18 06:41:26 +00:00
|
|
|
[volumeSlider setDoubleValue:logarithmicToLinear(newVolume, MAX_VOLUME)];
|
2008-02-17 18:44:11 +00:00
|
|
|
|
2009-02-28 18:19:15 +00:00
|
|
|
[[NSUserDefaults standardUserDefaults] setDouble:[audioPlayer volume] forKey:@"volume"];
|
2007-02-18 23:41:44 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)eqAlloc {
|
|
|
|
// Show a stopped equalizer as a stub
|
|
|
|
OSStatus err;
|
|
|
|
AudioComponentDescription desc;
|
|
|
|
|
|
|
|
desc.componentType = kAudioUnitType_Effect;
|
|
|
|
desc.componentSubType = kAudioUnitSubType_GraphicEQ;
|
|
|
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
|
|
|
desc.componentFlags = 0;
|
|
|
|
desc.componentFlagsMask = 0;
|
|
|
|
|
|
|
|
AudioComponent comp = NULL;
|
|
|
|
|
|
|
|
desc.componentType = kAudioUnitType_Effect;
|
|
|
|
desc.componentSubType = kAudioUnitSubType_GraphicEQ;
|
|
|
|
|
|
|
|
comp = AudioComponentFindNext(comp, &desc);
|
|
|
|
if(!comp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
err = AudioComponentInstanceNew(comp, &_eq);
|
|
|
|
if(err)
|
|
|
|
return;
|
|
|
|
|
|
|
|
AudioUnitInitialize(_eq);
|
2022-01-16 15:32:47 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)eqDealloc {
|
|
|
|
AudioUnitUninitialize(_eq);
|
|
|
|
AudioComponentInstanceDispose(_eq);
|
|
|
|
_eq = nil;
|
|
|
|
_eqStubbed = NO;
|
2022-01-16 15:32:47 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (IBAction)showEq:(id)sender {
|
|
|
|
if(_eq) {
|
|
|
|
if(_equi && [_equi isOpen])
|
|
|
|
[_equi bringToFront];
|
|
|
|
else
|
|
|
|
_equi = [[AUPluginUI alloc] initWithSampler:_eq bringToFront:YES orWindowNumber:0];
|
|
|
|
} else {
|
|
|
|
[self eqAlloc];
|
|
|
|
_eqWasOpen = YES;
|
|
|
|
[self audioPlayer:nil displayEqualizer:_eq];
|
|
|
|
[_equi bringToFront];
|
|
|
|
}
|
|
|
|
}
|
2022-01-16 15:32:47 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player displayEqualizer:(AudioUnit)eq {
|
|
|
|
if(_equi) {
|
|
|
|
_eqWasOpen = [_equi isOpen];
|
|
|
|
_equi = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_eq && _eq != eq) {
|
|
|
|
OSStatus err;
|
|
|
|
CFPropertyListRef classData;
|
|
|
|
UInt32 size;
|
|
|
|
|
|
|
|
size = sizeof(classData);
|
|
|
|
err = AudioUnitGetProperty(_eq, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, &size);
|
|
|
|
if(err == noErr) {
|
|
|
|
CFPreferencesSetAppValue(CFSTR("GraphEQ_Preset"), classData, kCFPreferencesCurrentApplication);
|
|
|
|
CFRelease(classData);
|
|
|
|
}
|
|
|
|
|
|
|
|
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
|
|
|
|
|
|
|
|
// Caller relinquishes EQ to us
|
|
|
|
[self eqDealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
_eq = eq;
|
|
|
|
|
|
|
|
{
|
|
|
|
OSStatus err;
|
|
|
|
ComponentDescription cd;
|
|
|
|
CFPropertyListRef classData;
|
|
|
|
CFDictionaryRef dict;
|
|
|
|
CFNumberRef cfnum;
|
|
|
|
|
|
|
|
classData = CFPreferencesCopyAppValue(CFSTR("GraphEQ_Preset"), kCFPreferencesCurrentApplication);
|
|
|
|
if(classData) {
|
|
|
|
dict = (CFDictionaryRef)classData;
|
|
|
|
|
|
|
|
cfnum = (CFNumberRef)(CFDictionaryGetValue(dict, CFSTR("type")));
|
|
|
|
CFNumberGetValue(cfnum, kCFNumberSInt32Type, &cd.componentType);
|
|
|
|
cfnum = (CFNumberRef)(CFDictionaryGetValue(dict, CFSTR("subtype")));
|
|
|
|
CFNumberGetValue(cfnum, kCFNumberSInt32Type, &cd.componentSubType);
|
|
|
|
cfnum = (CFNumberRef)(CFDictionaryGetValue(dict, CFSTR("manufacturer")));
|
|
|
|
CFNumberGetValue(cfnum, kCFNumberSInt32Type, &cd.componentManufacturer);
|
|
|
|
|
|
|
|
if((cd.componentType == kAudioUnitType_Effect) &&
|
|
|
|
(cd.componentSubType == kAudioUnitSubType_GraphicEQ) &&
|
|
|
|
(cd.componentManufacturer == kAudioUnitManufacturer_Apple))
|
|
|
|
err = AudioUnitSetProperty(eq, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, sizeof(classData));
|
|
|
|
|
|
|
|
CFRelease(classData);
|
|
|
|
}
|
|
|
|
|
|
|
|
equalizerLoadPreset(eq);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_eqWasOpen) {
|
|
|
|
NSWindow *window = appController.miniMode ? appController.miniWindow : appController.mainWindow;
|
|
|
|
_equi = [[AUPluginUI alloc] initWithSampler:_eq bringToFront:NO orWindowNumber:window.windowNumber];
|
|
|
|
_eqWasOpen = NO;
|
|
|
|
}
|
2022-01-16 15:32:47 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player refreshEqualizer:(AudioUnit)eq {
|
|
|
|
equalizerLoadPreset(eq);
|
2022-01-18 04:43:08 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player removeEqualizer:(AudioUnit)eq {
|
|
|
|
if(eq == _eq) {
|
|
|
|
OSStatus err;
|
|
|
|
CFPropertyListRef classData;
|
|
|
|
UInt32 size;
|
|
|
|
|
|
|
|
size = sizeof(classData);
|
|
|
|
err = AudioUnitGetProperty(eq, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0, &classData, &size);
|
|
|
|
if(err == noErr) {
|
|
|
|
CFPreferencesSetAppValue(CFSTR("GraphEQ_Preset"), classData, kCFPreferencesCurrentApplication);
|
|
|
|
CFRelease(classData);
|
|
|
|
}
|
|
|
|
|
|
|
|
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
|
|
|
|
|
|
|
|
if(_equi) {
|
|
|
|
_eqWasOpen = [_equi isOpen];
|
|
|
|
}
|
|
|
|
|
|
|
|
_equi = nil;
|
|
|
|
[self eqDealloc];
|
|
|
|
|
|
|
|
if(_eqWasOpen) {
|
|
|
|
[self showEq:nil];
|
|
|
|
}
|
|
|
|
}
|
2022-01-16 15:32:47 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player willEndStream:(id)userInfo {
|
2007-02-24 20:36:27 +00:00
|
|
|
PlaylistEntry *curEntry = (PlaylistEntry *)userInfo;
|
2008-02-25 17:02:06 +00:00
|
|
|
PlaylistEntry *pe;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(curEntry.stopAfter)
|
2008-02-26 11:59:47 +00:00
|
|
|
pe = nil;
|
2022-02-07 05:49:27 +00:00
|
|
|
else {
|
2008-02-25 17:02:06 +00:00
|
|
|
pe = [playlistController getNextEntry:curEntry];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(pe && [pe metadataLoaded] != YES) {
|
|
|
|
NSArray *entries = @[pe];
|
|
|
|
[playlistLoader performSelectorInBackground:@selector(loadInfoForEntries:) withObject:entries];
|
|
|
|
}
|
|
|
|
}
|
2006-05-12 18:12:31 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if(pe)
|
|
|
|
[player setNextStream:[pe URL] withUserInfo:pe withRGInfo:makeRGInfo(pe)];
|
|
|
|
else
|
|
|
|
[player setNextStream:nil];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player didBeginStream:(id)userInfo {
|
2007-02-24 20:36:27 +00:00
|
|
|
PlaylistEntry *pe = (PlaylistEntry *)userInfo;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2006-04-13 02:51:22 +00:00
|
|
|
[playlistController setCurrentEntry:pe];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(_eq)
|
|
|
|
equalizerApplyGenre(_eq, [pe genre]);
|
|
|
|
|
|
|
|
lastPosition = -10;
|
|
|
|
|
2009-02-22 22:28:09 +00:00
|
|
|
[self setPosition:0];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
[self removeHDCD:nil];
|
|
|
|
|
2009-03-05 17:03:30 +00:00
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidBeginNotficiation object:pe];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player didChangeStatus:(NSNumber *)s userInfo:(id)userInfo {
|
2006-01-29 14:57:48 +00:00
|
|
|
int status = [s intValue];
|
2022-02-07 05:49:27 +00:00
|
|
|
if(status == CogStatusStopped || status == CogStatusPaused) {
|
|
|
|
[self removeHDCD:nil];
|
|
|
|
if(positionTimer) {
|
2006-04-02 15:44:08 +00:00
|
|
|
[positionTimer invalidate];
|
|
|
|
positionTimer = NULL;
|
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(status == CogStatusStopped) {
|
2009-02-22 22:28:09 +00:00
|
|
|
[self setPosition:0];
|
|
|
|
[self setSeekable:NO]; // the player stopped, disable the slider
|
2009-03-05 17:03:30 +00:00
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidStopNotficiation object:nil];
|
2022-02-07 05:49:27 +00:00
|
|
|
} else // paused
|
2009-03-05 17:03:30 +00:00
|
|
|
{
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidPauseNotficiation object:nil];
|
2006-04-02 15:44:08 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
} else if(status == CogStatusPlaying) {
|
|
|
|
if(!positionTimer) {
|
2021-04-20 06:51:31 +00:00
|
|
|
positionTimer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(updatePosition:) userInfo:nil repeats:YES];
|
2009-02-09 06:16:16 +00:00
|
|
|
[[NSRunLoop currentRunLoop] addTimer:positionTimer forMode:NSRunLoopCommonModes];
|
|
|
|
}
|
2009-03-05 17:03:30 +00:00
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:CogPlaybackDidResumeNotficiation object:nil];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(status == CogStatusStopped) {
|
2008-02-22 03:09:03 +00:00
|
|
|
[playlistController setCurrentEntry:nil];
|
2009-02-22 22:28:09 +00:00
|
|
|
[self setSeekable:NO]; // the player stopped, disable the slider
|
2022-02-07 05:49:27 +00:00
|
|
|
} else {
|
2009-02-22 22:28:09 +00:00
|
|
|
[self setSeekable:YES];
|
2008-02-22 03:46:04 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
switch(status) {
|
|
|
|
case CogStatusPlaying:
|
|
|
|
DLog(@"PLAYING!");
|
|
|
|
break;
|
|
|
|
case CogStatusPaused:
|
|
|
|
DLog(@"PAUSED!");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DLog(@"STOPED!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(status == CogStatusStopped) {
|
|
|
|
status = CogStatusStopping;
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
|
|
|
if([self playbackStatus] == CogStatusStopping)
|
|
|
|
[self setPlaybackStatus:CogStatusStopped];
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2009-02-28 21:13:06 +00:00
|
|
|
[self setPlaybackStatus:status];
|
2022-02-07 05:49:27 +00:00
|
|
|
// If we don't send it here, if we've stopped, then the NPIC will be stuck at the last file we played.
|
|
|
|
[self sendMetaData];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player sustainHDCD:(id)userInfo {
|
|
|
|
MainWindow *mainWindow = (MainWindow *)appController.mainWindow;
|
|
|
|
[mainWindow showHDCDLogo:YES];
|
|
|
|
MiniWindow *miniWindow = (MiniWindow *)appController.miniWindow;
|
|
|
|
[miniWindow showHDCDLogo:YES];
|
2022-01-21 07:53:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)removeHDCD:(id)sender {
|
|
|
|
MainWindow *mainWindow = (MainWindow *)appController.mainWindow;
|
|
|
|
[mainWindow showHDCDLogo:NO];
|
|
|
|
MiniWindow *miniWindow = (MiniWindow *)appController.miniWindow;
|
|
|
|
[miniWindow showHDCDLogo:NO];
|
2022-01-21 07:53:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)playlistDidChange:(PlaylistController *)p {
|
2009-02-28 18:57:21 +00:00
|
|
|
[audioPlayer resetNextStreams];
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)setPosition:(double)p {
|
|
|
|
if(p > lastPosition && (p - lastPosition) >= 10.0) {
|
|
|
|
PlaylistEntry *pe = [playlistController currentEntry];
|
|
|
|
NSInteger lastTrackPlaying = [pe index];
|
2022-01-09 10:34:29 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[[NSUserDefaults standardUserDefaults] setInteger:CogStatusPlaying forKey:@"lastPlaybackStatus"];
|
|
|
|
[[NSUserDefaults standardUserDefaults] setInteger:lastTrackPlaying forKey:@"lastTrackPlaying"];
|
|
|
|
[[NSUserDefaults standardUserDefaults] setDouble:p forKey:@"lastTrackPosition"];
|
|
|
|
|
|
|
|
// If we handle this here, then it will send on all seek operations, which also reset lastPosition
|
|
|
|
[self sendMetaData];
|
|
|
|
|
|
|
|
lastPosition = p;
|
|
|
|
}
|
2022-01-09 10:34:29 +00:00
|
|
|
|
2009-02-22 22:28:09 +00:00
|
|
|
position = p;
|
2013-10-04 11:16:09 +00:00
|
|
|
|
|
|
|
[[playlistController currentEntry] setCurrentPosition:p];
|
2009-02-22 22:28:09 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (double)position {
|
2009-02-22 22:28:09 +00:00
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (void)setSeekable:(BOOL)s {
|
2009-02-22 22:28:09 +00:00
|
|
|
seekable = s;
|
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (BOOL)seekable {
|
2009-02-22 22:28:09 +00:00
|
|
|
return seekable && [[playlistController currentEntry] seekable];
|
|
|
|
}
|
2008-02-10 18:34:23 +00:00
|
|
|
|
2019-11-14 03:13:59 +00:00
|
|
|
- (void)sendMetaData {
|
2022-02-07 05:49:27 +00:00
|
|
|
MPNowPlayingInfoCenter *defaultCenter = [MPNowPlayingInfoCenter defaultCenter];
|
|
|
|
|
|
|
|
PlaylistEntry *entry = [playlistController currentEntry];
|
|
|
|
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
|
|
|
|
|
|
|
|
if(entry) {
|
|
|
|
if([entry title])
|
|
|
|
[songInfo setObject:[entry title] forKey:MPMediaItemPropertyTitle];
|
|
|
|
if([entry artist])
|
|
|
|
[songInfo setObject:[entry artist] forKey:MPMediaItemPropertyArtist];
|
|
|
|
if([entry album])
|
|
|
|
[songInfo setObject:[entry album] forKey:MPMediaItemPropertyAlbumTitle];
|
|
|
|
if([entry albumArt]) {
|
|
|
|
// can't do && with @available
|
|
|
|
if(@available(macOS 10.13.2, *)) {
|
|
|
|
CGSize artworkSize = CGSizeMake(500, 500);
|
|
|
|
MPMediaItemArtwork *mpArtwork = [[MPMediaItemArtwork alloc] initWithBoundsSize:artworkSize
|
|
|
|
requestHandler:^NSImage *_Nonnull(CGSize size) {
|
|
|
|
return [entry albumArt];
|
|
|
|
}];
|
|
|
|
[songInfo setObject:mpArtwork forKey:MPMediaItemPropertyArtwork];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// I don't know what NPIC does with these since they aren't exposed in UI, but if we have them, use it.
|
|
|
|
// There's a bunch of other metadata, but PlaylistEntry can't represent a lot of it.
|
|
|
|
if([entry genre])
|
|
|
|
[songInfo setObject:[entry genre] forKey:MPMediaItemPropertyGenre];
|
|
|
|
if([entry year]) {
|
|
|
|
// If PlaylistEntry can represent a full date like some tag formats can do, change it
|
|
|
|
NSCalendar *calendar = [NSCalendar currentCalendar];
|
|
|
|
NSDate *releaseYear = [calendar dateWithEra:1 year:[[entry year] intValue] month:0 day:0 hour:0 minute:0 second:0 nanosecond:0];
|
|
|
|
[songInfo setObject:releaseYear forKey:MPMediaItemPropertyReleaseDate];
|
|
|
|
}
|
|
|
|
[songInfo setObject:[NSNumber numberWithFloat:[entry currentPosition]] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
|
|
|
|
[songInfo setObject:[entry length] forKey:MPMediaItemPropertyPlaybackDuration];
|
|
|
|
[songInfo setObject:[NSNumber numberWithFloat:[entry index]] forKey:MPMediaItemPropertyPersistentID];
|
|
|
|
}
|
2019-11-14 03:13:59 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
switch(playbackStatus) {
|
|
|
|
case CogStatusPlaying:
|
|
|
|
defaultCenter.playbackState = MPNowPlayingPlaybackStatePlaying;
|
|
|
|
break;
|
|
|
|
case CogStatusPaused:
|
|
|
|
defaultCenter.playbackState = MPNowPlayingPlaybackStatePaused;
|
|
|
|
break;
|
2019-11-14 03:13:59 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
default:
|
|
|
|
defaultCenter.playbackState = MPNowPlayingPlaybackStateStopped;
|
|
|
|
break;
|
|
|
|
}
|
2019-11-14 03:13:59 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
[defaultCenter setNowPlayingInfo:songInfo];
|
|
|
|
}
|
2008-02-10 18:34:23 +00:00
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
@end
|