cog/Application/PlaybackController.m

577 lines
12 KiB
Matlab
Raw Normal View History

2006-01-20 15:41:31 +00:00
#import "PlaybackController.h"
#import "PlaylistView.h"
#import <Foundation/NSTimer.h>
#import "CogAudio/Status.h"
#import "CogAudio/Helper.h"
2006-01-20 15:41:31 +00:00
#import "PlaylistController.h"
#import "PlaylistEntry.h"
2006-01-20 15:41:31 +00:00
@implementation PlaybackController
#define DEFAULT_SEEK 5
@synthesize playbackStatus;
2006-01-20 15:41:31 +00:00
- (id)init
{
self = [super init];
if (self)
{
2007-02-26 05:26:48 +00:00
[self initDefaults];
audioPlayer = [[AudioPlayer alloc] init];
[audioPlayer setDelegate:self];
2006-01-20 15:41:31 +00:00
playbackStatus = kCogStatusStopped;
showTimeRemaining = NO;
scrobbler = [[AudioScrobbler alloc] init];
[GrowlApplicationBridge setGrowlDelegate:self];
2006-01-20 15:41:31 +00:00
}
return self;
}
2007-02-26 05:26:48 +00:00
- (void)initDefaults
{
NSDictionary *defaultsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], @"enableAudioScrobbler",
[NSNumber numberWithBool:NO], @"automaticallyLaunchLastFM",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDictionary];
}
- (NSDictionary *) registrationDictionaryForGrowl
{
NSArray *notifications = [NSArray arrayWithObjects:@"Stream Changed", nil];
return [NSDictionary dictionaryWithObjectsAndKeys:
@"Cog", GROWL_APP_NAME,
notifications, GROWL_NOTIFICATIONS_ALL,
notifications, GROWL_NOTIFICATIONS_DEFAULT,
nil];
}
2006-01-20 15:41:31 +00:00
- (void)awakeFromNib
{
[volumeSlider setDoubleValue:logarithmicToLinear(100.0)];
[audioPlayer setVolume: 100];
[positionSlider setEnabled:NO];
2006-01-20 15:41:31 +00:00
}
2006-01-20 15:41:31 +00:00
- (IBAction)playPauseResume:(id)sender
{
if (playbackStatus == kCogStatusStopped)
2008-02-22 03:09:03 +00:00
{
2006-01-20 15:41:31 +00:00
[self play:self];
2008-02-22 03:09:03 +00:00
}
2006-01-20 15:41:31 +00:00
else
2008-02-22 03:09:03 +00:00
{
2006-01-20 15:41:31 +00:00
[self pauseResume:self];
2008-02-22 03:09:03 +00:00
}
2006-01-20 15:41:31 +00:00
}
- (IBAction)pauseResume:(id)sender
{
if (playbackStatus == kCogStatusPaused)
[self resume:self];
else
[self pause:self];
}
- (IBAction)pause:(id)sender
{
[audioPlayer pause];
playbackStatus = kCogStatusPaused;
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler pause];
}
2006-01-20 15:41:31 +00:00
}
- (IBAction)resume:(id)sender
{
[audioPlayer resume];
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler resume];
}
2006-01-20 15:41:31 +00:00
}
- (IBAction)stop:(id)sender
{
[audioPlayer stop];
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler stop];
}
2006-01-20 15:41:31 +00:00
}
//called by double-clicking on table
- (void)playEntryAtIndex:(int)i
{
2008-02-20 13:20:07 +00:00
PlaylistEntry *pe = [playlistController entryAtIndex:i];
2006-01-20 15:41:31 +00:00
[self playEntry:pe];
}
2007-11-01 01:53:52 +00:00
- (IBAction)playbackButtonClick:(id)sender
{
int clickedSegment = [sender selectedSegment];
if (clickedSegment == 0) //Previous
{
[self prev:sender];
}
else if (clickedSegment == 1) //Play
{
[self playPauseResume:sender];
}
else if (clickedSegment == 2) //Next
{
[self next:sender];
}
}
2006-01-20 15:41:31 +00:00
- (IBAction)play:(id)sender
{
if ([playlistView selectedRow] == -1)
[playlistView selectRow:0 byExtendingSelection:NO];
if ([playlistView selectedRow] > -1)
[self playEntryAtIndex:[playlistView selectedRow]];
2006-01-20 15:41:31 +00:00
}
- (void)playEntry:(PlaylistEntry *)pe
2006-01-20 15:41:31 +00:00
{
2006-01-29 14:57:48 +00:00
if (playbackStatus != kCogStatusStopped)
[self stop:self];
2008-02-22 03:09:03 +00:00
NSLog(@"PLAYLIST CONTROLLER: %@", [playlistController class]);
[playlistController setCurrentEntry:pe];
2008-02-22 03:09:03 +00:00
[positionSlider setDoubleValue:0.0];
[self updateTimeField:0.0f];
2008-02-22 03:09:03 +00:00
if (pe == nil)
return;
2008-02-20 00:44:40 +00:00
[audioPlayer play:[pe URL] withUserInfo:pe];
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler start:pe];
}
[GrowlApplicationBridge notifyWithTitle:[pe title]
description:[pe artist]
notificationName:@"Stream Changed"
iconData:nil
priority:0
isSticky:NO
clickContext:nil];
2006-01-20 15:41:31 +00:00
}
- (IBAction)next:(id)sender
{
2006-01-29 14:57:48 +00:00
if ([playlistController next] == NO)
2006-01-20 15:41:31 +00:00
return;
2006-01-29 14:57:48 +00:00
[self playEntry:[playlistController currentEntry]];
2006-01-20 15:41:31 +00:00
}
- (IBAction)prev:(id)sender
{
if ([playlistController prev] == NO)
2006-01-20 15:41:31 +00:00
return;
[self playEntry:[playlistController currentEntry]];
2006-01-20 15:41:31 +00:00
}
- (IBAction)seek:(id)sender
{
double time;
time = [positionSlider doubleValue];
2006-04-18 17:00:29 +00:00
2006-04-04 01:08:21 +00:00
if ([sender tracking] == NO) // check if user stopped sliding before playing audio
[audioPlayer seekToTime:time];
2006-01-20 15:41:31 +00:00
[self updateTimeField:time];
}
- (IBAction)eventSeekForward:(id)sender
{
[self seekForward:DEFAULT_SEEK];
}
- (void)seekForward:(double)amount
{
double seekTo = [audioPlayer amountPlayed] + amount;
if (seekTo > (int)[positionSlider maxValue])
{
[self next:self];
}
else
{
[audioPlayer seekToTime:seekTo];
[self updateTimeField:seekTo];
[positionSlider setDoubleValue:seekTo];
}
}
- (IBAction)eventSeekBackward:(id)sender
{
[self seekBackward:DEFAULT_SEEK];
}
- (void)seekBackward:(double)amount
{
double seekTo = [audioPlayer amountPlayed] - amount;
if (seekTo < 0)
seekTo = 0;
[audioPlayer seekToTime:seekTo];
[self updateTimeField:seekTo];
[positionSlider setDoubleValue:seekTo];
}
2006-01-20 15:41:31 +00:00
- (void)changePlayButtonImage:(NSString *)name
{
2007-11-01 01:53:52 +00:00
NSImage *img = [NSImage imageNamed:name];
// [img retain];
2006-01-20 15:41:31 +00:00
if (img == nil)
{
2007-07-11 01:20:32 +00:00
NSLog(@"Error loading image!");
2006-01-20 15:41:31 +00:00
}
2007-11-01 01:53:52 +00:00
[playbackButtons setImage:img forSegment:1];
2006-01-20 15:41:31 +00:00
}
- (IBAction)changeVolume:(id)sender
{
NSLog(@"VOLUME: %lf, %lf", [sender doubleValue], linearToLogarithmic([sender doubleValue]));
[audioPlayer setVolume:linearToLogarithmic([sender doubleValue])];
2006-01-20 15:41:31 +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. */
- (void)audioFadeDown:(NSTimer *)audioTimer
{
double volume = [audioPlayer volume];
double originalVolume = [[audioTimer userInfo] doubleValue];
double down = originalVolume/10;
NSLog(@"VOLUME IS %lf", volume);
if (volume > 0.0001) //YAY! Roundoff error!
{
[audioPlayer volumeDown:down];
}
else // volume is at 0 or below, we are ready to release the timer and move on
{
[audioPlayer pause];
[audioPlayer setVolume:originalVolume];
[volumeSlider setDoubleValue: logarithmicToLinear(originalVolume)];
[audioTimer invalidate];
playbackStatus = kCogStatusPaused;
}
}
- (void)audioFadeUp:(NSTimer *)audioTimer
{
double volume = [audioPlayer volume];
double originalVolume = [[audioTimer userInfo] doubleValue];
double up = originalVolume/10;
NSLog(@"VOLUME IS %lf", volume);
if (volume < originalVolume)
{
if ((volume + up) > originalVolume)
[audioPlayer volumeUp:(originalVolume - volume)];
else
[audioPlayer volumeUp:up];
}
else // volume is at 0 or below, we are ready to release the timer and move on
{
[volumeSlider setDoubleValue: logarithmicToLinear(originalVolume)];
[audioTimer invalidate];
playbackStatus = kCogStatusPlaying;
}
}
- (IBAction)fade:(id)sender
{
double time = 0.1;
// we can not allow multiple fade timers to be registered
if (playbackStatus == kCogStatusFading)
return;
NSNumber *originalVolume = [NSNumber numberWithDouble: [audioPlayer volume]];
NSTimer *fadeTimer;
if (playbackStatus == kCogStatusPlaying)
fadeTimer = [NSTimer scheduledTimerWithTimeInterval:time
target:self
selector:@selector(audioFadeDown:)
userInfo:originalVolume
repeats:YES];
else
{
[audioPlayer setVolume:0];
fadeTimer = [NSTimer scheduledTimerWithTimeInterval:time
target:self
selector:@selector(audioFadeUp:)
userInfo:originalVolume
repeats:YES];
[self pauseResume:self];
}
playbackStatus = kCogStatusFading;
}
- (IBAction)skipToNextAlbum:(id)sender
{
BOOL found = NO;
int index = [[playlistController currentEntry] index];
2008-02-20 00:12:25 +00:00
NSString *origAlbum = [[playlistController currentEntry] album];
2008-02-20 13:20:07 +00:00
int i;
NSString *curAlbum;
PlaylistEntry *pe;
2008-02-20 13:20:07 +00:00
for (i = 1; i < [[playlistController arrangedObjects] count]; i++)
{
pe = [playlistController entryAtIndex:index + i];
if (pe == nil)
2008-02-20 13:20:07 +00:00
break;
curAlbum = [pe album];
// check for untagged files, and just play the first untagged one
// we come across
if (curAlbum == nil)
{
2008-02-20 13:20:07 +00:00
found = YES;
break;
}
2008-02-20 13:20:07 +00:00
2008-02-20 13:25:24 +00:00
if ([curAlbum caseInsensitiveCompare:origAlbum] != NSOrderedSame)
{
found = YES;
2008-02-20 13:20:07 +00:00
break;
}
}
2008-02-20 13:20:07 +00:00
if (found)
{
[self playEntryAtIndex:i + index];
2008-02-20 13:20:07 +00:00
}
}
- (IBAction)skipToPreviousAlbum:(id)sender
{
2008-02-20 13:20:07 +00:00
BOOL found = NO;
BOOL foundAlbum = NO;
int index = [[playlistController currentEntry] index];
2008-02-20 00:12:25 +00:00
NSString *origAlbum = [[playlistController currentEntry] album];
NSString *curAlbum;
2008-02-20 13:20:07 +00:00
int i;
PlaylistEntry *pe;
2008-02-20 13:20:07 +00:00
for (i = 1; i < [[playlistController arrangedObjects] count]; i++)
{
pe = [playlistController entryAtIndex:index - i];
if (pe == nil)
2008-02-20 13:20:07 +00:00
break;
curAlbum = [pe album];
if (curAlbum == nil)
{
2008-02-20 13:20:07 +00:00
found = YES;
break;
}
2008-02-20 13:20:07 +00:00
2008-02-20 13:25:24 +00:00
if ([curAlbum caseInsensitiveCompare:origAlbum] != NSOrderedSame)
{
if (foundAlbum == NO)
{
foundAlbum = YES;
// 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;
}
else
2008-02-20 13:20:07 +00:00
{
found = YES; // terminate loop
2008-02-20 13:20:07 +00:00
break;
}
}
}
2008-02-20 13:20:07 +00:00
if (found || foundAlbum)
{
if (foundAlbum == YES)
i--;
[self playEntryAtIndex:index - i];
2008-02-20 13:20:07 +00:00
}
}
- (IBAction)volumeDown:(id)sender
{
double newVolume;
newVolume = [audioPlayer volumeDown:DEFAULT_VOLUME_DOWN];
[volumeSlider setDoubleValue:logarithmicToLinear(newVolume)];
}
- (IBAction)volumeUp:(id)sender
{
double newVolume;
newVolume = [audioPlayer volumeUp:DEFAULT_VOLUME_UP];
[volumeSlider setDoubleValue:logarithmicToLinear(newVolume)];
}
2006-01-20 15:41:31 +00:00
- (void)updateTimeField:(double)pos
{
NSString *text;
if (showTimeRemaining == NO)
{
int sec = (int)(pos);
2006-01-20 15:41:31 +00:00
text = [NSString stringWithFormat:NSLocalizedString(@"TimeElapsed", @""), sec/60, sec%60];
}
else
{
int sec = (int)(([positionSlider maxValue] - pos));
2006-05-13 16:50:52 +00:00
if (sec < 0)
sec = 0;
2006-01-20 15:41:31 +00:00
text = [NSString stringWithFormat:NSLocalizedString(@"TimeRemaining", @""), sec/60, sec%60];
}
[timeField setStringValue:text];
}
- (IBAction)toggleShowTimeRemaining:(id)sender
{
showTimeRemaining = !showTimeRemaining;
[self updateTimeField:[positionSlider doubleValue]];
}
- (void)audioPlayer:(AudioPlayer *)player requestNextStream:(id)userInfo
2006-01-20 15:41:31 +00:00
{
PlaylistEntry *curEntry = (PlaylistEntry *)userInfo;
PlaylistEntry *pe;
if (curEntry.stopAfter)
pe = nil;
else
pe = [playlistController getNextEntry:curEntry];
2006-05-12 18:12:31 +00:00
2008-02-20 00:44:40 +00:00
[player setNextStream:[pe URL] withUserInfo:pe];
2006-01-20 15:41:31 +00:00
}
- (void)audioPlayer:(AudioPlayer *)player streamChanged:(id)userInfo
2006-01-20 15:41:31 +00:00
{
PlaylistEntry *pe = (PlaylistEntry *)userInfo;
2006-04-13 02:51:22 +00:00
[playlistController setCurrentEntry:pe];
2006-01-20 15:41:31 +00:00
[positionSlider setDoubleValue:0.0f];
2006-01-20 15:41:31 +00:00
[self updateTimeField:0.0f];
2006-01-20 15:41:31 +00:00
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
[scrobbler start:pe];
}
[GrowlApplicationBridge notifyWithTitle:[pe title]
description:[pe artist]
notificationName:@"Stream Changed"
iconData:nil
priority:0
isSticky:NO
clickContext:nil];
2006-01-20 15:41:31 +00:00
}
- (void)updatePosition:(id)sender
2006-01-20 15:41:31 +00:00
{
double pos = [audioPlayer amountPlayed];
2006-01-20 15:41:31 +00:00
if ([positionSlider tracking] == NO)
{
[positionSlider setDoubleValue:pos];
[self updateTimeField:pos];
}
}
- (void)audioPlayer:(AudioPlayer *)player statusChanged:(id)s
2006-01-20 15:41:31 +00:00
{
2006-01-29 14:57:48 +00:00
int status = [s intValue];
2006-01-20 15:41:31 +00:00
if (status == kCogStatusStopped || status == kCogStatusPaused)
{
if (positionTimer)
{
[positionTimer invalidate];
positionTimer = NULL;
}
if (status == kCogStatusStopped)
{
[positionSlider setDoubleValue:0.0f];
[positionSlider setEnabled:NO]; // the player stopped, disable the slider
[self updateTimeField:0.0f];
}
2006-01-20 15:41:31 +00:00
//Show play image
[self changePlayButtonImage:@"play"];
}
else if (status == kCogStatusPlaying)
{
if (!positionTimer)
positionTimer = [NSTimer scheduledTimerWithTimeInterval:1.00 target:self selector:@selector(updatePosition:) userInfo:nil repeats:YES];
2006-01-20 15:41:31 +00:00
//Show pause
[self changePlayButtonImage:@"pause"];
}
2007-06-03 17:09:07 +00:00
if (status == kCogStatusStopped) {
NSLog(@"DONE!");
2008-02-22 03:09:03 +00:00
[playlistController setCurrentEntry:nil];
[positionSlider setEnabled:NO]; // the player stopped, disable the slider
2007-06-03 17:09:07 +00:00
}
else {
NSLog(@"PLAYING!");
}
2008-02-22 03:09:03 +00:00
2006-01-20 15:41:31 +00:00
playbackStatus = status;
}
2006-01-20 15:41:31 +00:00
@end