/* vim: set ft=objc ts=4 nowrap: */ /* * Player.m * * Copyright (c) 1999 - 2003 * * Author: ACKyugo * Andreas Heppel * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Player.h" #include "LED.h" #include "TrackList.h" static BOOL mustReadTOC = NO; static Player *sharedPlayer = nil; @implementation Player - init { if (sharedPlayer) { [self dealloc]; } else { self = [super init]; sharedPlayer = self; track = 1; // we must already create the (hidden) track list [TrackList sharedTrackList]; [self buildInterface]; timer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(timer:) userInfo: self repeats: YES]; if (![self loadAudioCDBundle]) { [self release]; return nil; } [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(playTrack:) name: @"PlayTrack" object: nil]; } return sharedPlayer; } - (void) dealloc { [[NSNotificationCenter defaultCenter] removeObserver: self name: @"PlayTrack" object: nil]; [drive release]; [timer invalidate]; [timer release]; [led release]; [window release]; [prev release]; [play release]; [pause release]; [stop release]; [next release]; [super dealloc]; } - (BOOL) loadAudioCDBundle { int i; NSString *path; NSArray *searchPaths; // try to load the AudioCD bundle searchPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask|NSLocalDomainMask|NSSystemDomainMask, YES); for (i = 0; i < [searchPaths count]; i++) { NSBundle *bundle; NSString *bundlePath = [NSString stringWithFormat: @"%@/Bundles/AudioCD.bundle", [searchPaths objectAtIndex: i]]; bundle = [NSBundle bundleWithPath: bundlePath]; if (bundle) { audiocdClass = [bundle principalClass]; if (audiocdClass) { break; } } } // for (i = 0; i < [searchPaths count]; i++) if (!audiocdClass) { NSRunAlertPanel(@"CDPlayer", _(@"Couldn't find AudioCD bundle."), _(@"Exit"), nil, nil); exit(-1); } path = [[NSUserDefaults standardUserDefaults] stringForKey: @"Device"]; drive = [[audiocdClass alloc] initWithPath: path andHandler: self]; return YES; } // // // - (void) timer: (id)timer { NSString *path; path = [[NSUserDefaults standardUserDefaults] stringForKey: @"Device"]; if (drive == nil) { drive = [[audiocdClass alloc] initWithPath: path andHandler: self]; } if(drive == nil) { return; } if (mustReadTOC) { [[TrackList sharedTrackList] setTOC: [drive readTOC]]; mustReadTOC = NO; } // is a disc in the drive? if([drive cdPresent] == NO) { [led setNoCD]; [led display]; return; } state = [drive currentState]; if(state == AUDIOCD_PLAYING) { [led setMin: [drive currentMin]]; [led setSec: [drive currentSec]]; track = [drive currentTrack]; } else if(state == AUDIOCD_NOSTATUS) { [led setMin: 0]; [led setSec: 0]; } [led setTrack: track]; [led display]; [[TrackList sharedTrackList] setPlaysTrack: track]; } // // // - (void) playTrack: (NSNotification *)not { int nextTrack = [[[not userInfo] objectForKey: @"Track"] intValue]; if (nextTrack == track) return; track = nextTrack; [drive playStart: track End: [drive totalTrack]]; [led setTrack: track]; [led display]; [[TrackList sharedTrackList] setPlaysTrack: track]; } - (void) play: (id)sender { if([drive cdPresent] == NO) { return; } if ([drive currentState] == AUDIOCD_PAUSED) { [drive resume]; } else { [drive playStart: track End: [drive totalTrack]]; } } - (void) pause: (id)sender { if ([drive cdPresent] == NO) { return; } if ([drive currentState] == AUDIOCD_PLAYING) { [drive pause]; } else if ([drive currentState] == AUDIOCD_PAUSED) { [drive resume]; } } - (void) stop: (id)sender { // the 'stop' button is also 'eject' if CD is already halted, // but not the Controller, which may also stop the CD on exit if(sender == stop) { if ([drive cdPresent] == NO) { [drive close]; return; } if((sender == stop) && ([drive currentState] == AUDIOCD_NOSTATUS)) { [drive eject]; return; } } [drive stop]; track = 1; [led setTrack: track]; [led setMin: 0]; [led setSec: 0]; [led display]; [[TrackList sharedTrackList] setPlaysTrack: 0]; } - (void) eject: (id)sender { if([drive cdPresent] == NO) { return; } [drive eject]; } - (void) next: (id)sender { if([drive cdPresent] == NO) { return; } track++; if(track > [drive totalTrack]) { track = 1; } if(([drive currentState] == AUDIOCD_PLAYING) || ([drive currentState] == AUDIOCD_PAUSED)) { [drive playStart: track End: [drive totalTrack]]; } [led setTrack: track]; [led display]; [[TrackList sharedTrackList] setPlaysTrack: track]; } - (void) prev: (id)sender { if([drive cdPresent] == NO) { return; } if ((state == AUDIOCD_NOSTATUS) || ([drive currentSec] == 0 && [drive currentMin] == 0)) { track--; if(track < 1) { track = [drive totalTrack]; } } if(([drive currentState] == AUDIOCD_PLAYING) || ([drive currentState] == AUDIOCD_PAUSED)) { [drive playStart: track End: [drive totalTrack]]; } [led setTrack: track]; [led display]; [[TrackList sharedTrackList] setPlaysTrack: track]; } // // // // - (BOOL) audioCD: (id)sender error: (int)no message: (NSString *)msg { // FIXME: Take appropriate action when an error occurs!! // NSRunAlertPanel(@"CDPlayer", // msg, // _(@"OK"), nil, nil); NSLog(@"CDPlayer error: %@", msg); return YES; } - (void) audioCDChanged: (id)sender { mustReadTOC = YES; } - (BOOL) windowShouldClose: (id)sender { [[NSApplication sharedApplication ] terminate: self]; return YES; } // // // - (void) buildInterface { NSRect frame; unsigned int style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; NSBundle *bundle = [NSBundle mainBundle]; NSImage *image; NSString *path; frame = NSMakeRect(100, 100, 160, 73); window = [[NSWindow alloc] initWithContentRect: frame styleMask: style backing: NSBackingStoreRetained defer: NO]; [window setTitle: @"CDPlayer"]; [window setDelegate: self]; frame = NSMakeRect(5, 38, 150, 30); led = [[LED alloc] initWithFrame: frame]; [led setNoCD]; [led display]; [[window contentView] addSubview: led]; path = [bundle pathForResource: @"prev" ofType: @"tiff"]; image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease]; if(image == nil) NSLog(@"cannot load prev.tiff"); frame = NSMakeRect( 5, 5, 30, 30); prev = [[NSButton alloc] initWithFrame: frame]; [prev setButtonType: NSMomentaryPushButton]; [prev setImagePosition: NSImageOnly]; [prev setImage: image]; [prev setTarget: self]; [prev setAction: @selector(prev:)]; [[window contentView] addSubview: prev]; path = [bundle pathForResource: @"play" ofType: @"tiff"]; image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease]; if(image == nil) NSLog(@"cannot load play.tiff"); frame = NSMakeRect( 35, 5, 30, 30); play = [[NSButton alloc] initWithFrame: frame]; [play setButtonType: NSMomentaryPushButton]; [play setImagePosition: NSImageOnly]; [play setImage: image]; [play setTarget: self]; [play setAction: @selector(play:)]; [[window contentView] addSubview: play]; path = [bundle pathForResource: @"pause" ofType: @"tiff"]; image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease]; if(image == nil) NSLog(@"cannot load pause.tiff"); frame = NSMakeRect( 65, 5, 30, 30); pause = [[NSButton alloc] initWithFrame: frame]; [pause setButtonType: NSMomentaryPushButton]; [pause setImagePosition: NSImageOnly]; [pause setImage: image]; [pause setTarget: self]; [pause setAction: @selector(pause:)]; [[window contentView] addSubview: pause]; path = [bundle pathForResource: @"next" ofType: @"tiff"]; image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease]; if(image == nil) NSLog(@"cannot load next.tiff"); frame = NSMakeRect(95, 5, 30, 30); next = [[NSButton alloc] initWithFrame: frame]; [next setButtonType: NSMomentaryPushButton]; [next setImagePosition: NSImageOnly]; [next setImage: image]; [next setTarget: self]; [next setAction: @selector(next:)]; [[window contentView] addSubview: next]; path = [bundle pathForResource: @"stop" ofType: @"tiff"]; image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease]; if(image == nil) NSLog(@"cannot load stop.tiff"); frame = NSMakeRect( 125, 5, 30, 30); stop = [[NSButton alloc] initWithFrame: frame]; [stop setButtonType: NSMomentaryPushButton]; [stop setImagePosition: NSImageOnly]; [stop setImage: image]; [stop setTarget: self]; [stop setAction: @selector(stop:)]; [[window contentView] addSubview: stop]; [window orderFront: self]; } // // services methods // - (void) getTOC: (NSPasteboard *) pboard userData: (NSString *) userData error: (NSString **) error { TrackList *tl = [TrackList sharedTrackList]; int i, rows = [tl numberOfTracksInTOC]; NSMutableArray *array; /* * If we don't have any rows, there is probably no CD. */ if (rows == 0) { *error = _(@"No Audio CD found."); return; } array = [[NSMutableArray alloc] init]; for (i = 0; i < rows; i++) { [array addObject: [NSNumber numberWithInt: i]]; } /* * This is a small hack, but we can clean this up later. */ if (![tl tableView: nil writeRows: array toPasteboard: pboard]) { *error = _(@"Could not write TOC to pasteboard."); } else { } RELEASE(array); } // // class methods // + (Player *) sharedPlayer { if (!sharedPlayer) { sharedPlayer = [[Player alloc] init]; } return sharedPlayer; } @end