2006-01-20 15:41:31 +00:00
|
|
|
#import "PlaybackController.h"
|
|
|
|
#import "PlaylistView.h"
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
#import "CogAudio/Status.h"
|
2006-01-20 15:41:31 +00:00
|
|
|
|
2007-03-14 02:28:30 +00:00
|
|
|
#import "PlaylistController.h"
|
|
|
|
#import "PlaylistEntry.h"
|
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
@implementation PlaybackController
|
|
|
|
|
|
|
|
- (id)init
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (self)
|
|
|
|
{
|
2007-02-26 05:26:48 +00:00
|
|
|
[self initDefaults];
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
audioPlayer = [[AudioPlayer alloc] init];
|
|
|
|
[audioPlayer setDelegate:self];
|
2006-01-20 15:41:31 +00:00
|
|
|
playbackStatus = kCogStatusStopped;
|
|
|
|
|
|
|
|
showTimeRemaining = NO;
|
2007-02-25 02:43:56 +00:00
|
|
|
|
|
|
|
scrobbler = [[AudioScrobbler alloc] init];
|
2007-02-28 00:35:27 +00:00
|
|
|
[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];
|
|
|
|
}
|
|
|
|
|
2007-02-28 00:35:27 +00:00
|
|
|
- (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
|
|
|
|
{
|
2006-04-04 01:08:21 +00:00
|
|
|
currentVolume = 100.0;
|
2007-11-01 01:53:52 +00:00
|
|
|
[volumeSlider setDoubleValue:pow(10.0, log10(0.5)/4.0)*100];
|
2007-07-05 23:08:10 +00:00
|
|
|
[positionSlider setEnabled:NO];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
2007-02-20 01:02:23 +00:00
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
- (IBAction)playPauseResume:(id)sender
|
|
|
|
{
|
|
|
|
if (playbackStatus == kCogStatusStopped)
|
|
|
|
[self play:self];
|
|
|
|
else
|
|
|
|
[self pauseResume:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)pauseResume:(id)sender
|
|
|
|
{
|
|
|
|
if (playbackStatus == kCogStatusPaused)
|
|
|
|
[self resume:self];
|
|
|
|
else
|
|
|
|
[self pause:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)pause:(id)sender
|
|
|
|
{
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer pause];
|
2007-02-25 02:43:56 +00:00
|
|
|
|
|
|
|
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
|
|
|
|
[scrobbler pause];
|
|
|
|
}
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)resume:(id)sender
|
|
|
|
{
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer resume];
|
2007-02-25 02:43:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
|
|
|
|
[scrobbler resume];
|
|
|
|
}
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)stop:(id)sender
|
|
|
|
{
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer stop];
|
2007-02-25 02:43:56 +00:00
|
|
|
|
|
|
|
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
|
|
|
|
[scrobbler stop];
|
|
|
|
}
|
2007-02-28 00:35:27 +00:00
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//called by double-clicking on table
|
|
|
|
- (void)playEntryAtIndex:(int)i
|
|
|
|
{
|
|
|
|
PlaylistEntry *pe = [[playlistController arrangedObjects] objectAtIndex:i];
|
|
|
|
|
|
|
|
[self playEntry:pe];
|
|
|
|
}
|
|
|
|
|
2007-11-01 01:53:52 +00:00
|
|
|
|
|
|
|
- (IBAction)playbackButtonClick:(id)sender
|
|
|
|
{
|
|
|
|
int clickedSegment = [sender selectedSegment];
|
|
|
|
if (clickedSegment == 0) //Previous
|
|
|
|
{
|
|
|
|
[sender setSelected:YES forSegment:0];
|
|
|
|
[sender setSelected:YES forSegment:1];
|
|
|
|
[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];
|
|
|
|
|
|
|
|
[self playEntryAtIndex:[playlistView selectedRow]];
|
|
|
|
}
|
|
|
|
|
2007-02-25 02:43:56 +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];
|
2006-04-02 15:44:08 +00:00
|
|
|
|
2006-05-13 15:52:52 +00:00
|
|
|
[playlistController setCurrentEntry:pe];
|
|
|
|
|
2007-11-24 20:16:27 +00:00
|
|
|
[positionSlider setDoubleValue:0.0];
|
2006-04-02 15:44:08 +00:00
|
|
|
|
|
|
|
[self updateTimeField:0.0f];
|
|
|
|
|
2007-03-02 01:36:52 +00:00
|
|
|
[audioPlayer play:[pe url] withUserInfo:pe];
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer setVolume:currentVolume];
|
2007-02-25 02:43:56 +00:00
|
|
|
|
|
|
|
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
|
|
|
|
[scrobbler start:pe];
|
|
|
|
}
|
2007-02-28 00:35:27 +00:00
|
|
|
|
2007-02-28 02:03:37 +00:00
|
|
|
[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
|
|
|
|
2007-06-05 03:09:55 +00:00
|
|
|
[self stop:self];
|
|
|
|
[self playEntry:[playlistController currentEntry]];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)prev:(id)sender
|
|
|
|
{
|
|
|
|
if ([playlistController prev] == nil)
|
|
|
|
return;
|
|
|
|
|
2007-06-05 03:09:55 +00:00
|
|
|
[self stop:self];
|
|
|
|
[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
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer seekToTime:time];
|
2006-01-20 15:41:31 +00:00
|
|
|
|
|
|
|
[self updateTimeField:time];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (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
|
|
|
|
{
|
2007-02-18 23:41:44 +00:00
|
|
|
double percent;
|
2006-04-18 17:00:29 +00:00
|
|
|
|
2006-05-13 13:37:32 +00:00
|
|
|
//Approximated log
|
2007-11-01 01:53:52 +00:00
|
|
|
percent = (float)[sender doubleValue]/100.0;
|
2006-05-13 13:37:32 +00:00
|
|
|
percent = percent * percent * percent * percent;
|
|
|
|
|
|
|
|
//gravitates at the 100% mark
|
|
|
|
float v = [sender frame].size.width - ([sender frame].size.width*(percent*[sender maxValue])/100.0);
|
2006-04-18 17:00:29 +00:00
|
|
|
if (fabs(v) < 10.0)
|
|
|
|
{
|
2006-05-13 13:37:32 +00:00
|
|
|
percent = 0.5;
|
|
|
|
v = pow(10.0, log10(percent)/4.0);
|
2007-11-01 01:53:52 +00:00
|
|
|
[sender setDoubleValue:v*100.0];
|
2006-04-18 17:00:29 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 01:53:52 +00:00
|
|
|
currentVolume = percent * 100.0;
|
2006-05-13 13:37:32 +00:00
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer setVolume:currentVolume];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2007-02-18 23:41:44 +00:00
|
|
|
- (IBAction)volumeDown:(id)sender
|
|
|
|
{
|
|
|
|
double percent;
|
|
|
|
|
|
|
|
[volumeSlider setDoubleValue:([volumeSlider doubleValue] - 5)];
|
|
|
|
|
2007-11-01 01:53:52 +00:00
|
|
|
percent = (float)[volumeSlider doubleValue]/100.0;
|
2007-02-18 23:41:44 +00:00
|
|
|
percent = percent * percent * percent * percent;
|
|
|
|
|
2007-11-01 01:53:52 +00:00
|
|
|
currentVolume = percent * 100.0;
|
2007-02-18 23:41:44 +00:00
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer setVolume:currentVolume];
|
2007-02-18 23:41:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)volumeUp:(id)sender
|
|
|
|
{
|
|
|
|
double percent;
|
|
|
|
|
|
|
|
[volumeSlider setDoubleValue:([volumeSlider doubleValue] + 5)];
|
|
|
|
|
|
|
|
percent = (float)[volumeSlider doubleValue]/[volumeSlider maxValue];
|
|
|
|
percent = percent * percent * percent * percent;
|
|
|
|
|
|
|
|
currentVolume = percent * [volumeSlider maxValue];
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
[audioPlayer setVolume:currentVolume];
|
2007-02-18 23:41:44 +00:00
|
|
|
}
|
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
|
|
|
|
- (void)updateTimeField:(double)pos
|
|
|
|
{
|
|
|
|
NSString *text;
|
|
|
|
if (showTimeRemaining == NO)
|
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
int sec = (int)(pos);
|
2006-01-20 15:41:31 +00:00
|
|
|
text = [NSString stringWithFormat:NSLocalizedString(@"TimeElapsed", @""), sec/60, sec%60];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-11-24 20:16:27 +00:00
|
|
|
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]];
|
|
|
|
}
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player requestNextStream:(id)userInfo
|
2006-01-20 15:41:31 +00:00
|
|
|
{
|
2007-02-24 20:36:27 +00:00
|
|
|
PlaylistEntry *curEntry = (PlaylistEntry *)userInfo;
|
2007-10-21 21:01:40 +00:00
|
|
|
PlaylistEntry *pe = [playlistController getNextEntry:curEntry];
|
2006-05-12 18:12:31 +00:00
|
|
|
|
2007-10-21 21:01:40 +00:00
|
|
|
[player setNextStream:[pe url] withUserInfo:pe];
|
2006-01-20 15:41:31 +00:00
|
|
|
}
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
- (void)audioPlayer:(AudioPlayer *)player streamChanged:(id)userInfo
|
2006-01-20 15:41:31 +00:00
|
|
|
{
|
2007-02-24 20:36:27 +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
|
|
|
|
2006-04-02 15:44:08 +00:00
|
|
|
[positionSlider setDoubleValue:0.0f];
|
2006-01-20 15:41:31 +00:00
|
|
|
|
2006-04-02 15:44:08 +00:00
|
|
|
[self updateTimeField:0.0f];
|
2006-01-20 15:41:31 +00:00
|
|
|
|
2007-02-25 02:43:56 +00:00
|
|
|
if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) {
|
|
|
|
[scrobbler start:pe];
|
|
|
|
}
|
2007-02-28 00:35:27 +00:00
|
|
|
|
2007-02-28 02:03:37 +00:00
|
|
|
[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
|
|
|
}
|
|
|
|
|
2006-04-02 15:44:08 +00:00
|
|
|
- (void)updatePosition:(id)sender
|
2006-01-20 15:41:31 +00:00
|
|
|
{
|
2007-02-24 20:36:27 +00:00
|
|
|
double pos = [audioPlayer amountPlayed];
|
2006-04-02 15:44:08 +00:00
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
if ([positionSlider tracking] == NO)
|
|
|
|
{
|
|
|
|
[positionSlider setDoubleValue:pos];
|
|
|
|
[self updateTimeField:pos];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-02-24 20:36:27 +00:00
|
|
|
|
|
|
|
- (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)
|
|
|
|
{
|
2006-04-02 15:44:08 +00:00
|
|
|
if (positionTimer)
|
|
|
|
{
|
|
|
|
[positionTimer invalidate];
|
|
|
|
positionTimer = NULL;
|
|
|
|
}
|
|
|
|
if (status == kCogStatusStopped)
|
|
|
|
{
|
|
|
|
[positionSlider setDoubleValue:0.0f];
|
|
|
|
|
|
|
|
[self updateTimeField:0.0f];
|
|
|
|
}
|
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
//Show play image
|
|
|
|
[self changePlayButtonImage:@"play"];
|
|
|
|
}
|
|
|
|
else if (status == kCogStatusPlaying)
|
|
|
|
{
|
2006-04-02 15:44:08 +00:00
|
|
|
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) {
|
|
|
|
[positionSlider setEnabled:NO];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
[positionSlider setEnabled:[[[playlistController currentEntry] seekable] boolValue]];
|
|
|
|
}
|
|
|
|
|
2006-01-20 15:41:31 +00:00
|
|
|
playbackStatus = status;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|