#import "SoundController.h" #import "Sound.h" #import "PlaylistView.h" #import "DBLog.h" @implementation SoundController //Note: use distributed objects for communication between Sound and SoundController....each should be in their own threads - (id)init { self = [super init]; if (self) { sound = [[Sound alloc] init]; playbackStatus = kCogStatusStopped; showTimeRemaining = NO; } return self; } - (void)awakeFromNib { [timeField setFont:[NSFont systemFontOfSize:18]]; sendPort = [NSPort port]; if (sendPort) { [sendPort setDelegate:self]; NSArray *modes = [NSArray arrayWithObjects:NSDefaultRunLoopMode, NSEventTrackingRunLoopMode, NSModalPanelRunLoopMode, nil]; NSEnumerator *enumerator; NSString *mode; enumerator = [modes objectEnumerator]; while ((mode = [enumerator nextObject])) [[NSRunLoop currentRunLoop] addPort:sendPort forMode:mode]; [NSThread detachNewThreadSelector:@selector(launchThreadWithPort:) toTarget:sound withObject:sendPort]; } } - (IBAction)playPauseResume:(id)sender { if (playbackStatus == kCogStatusStopped) [self play:self]; else [self pauseResume:self]; } - (IBAction)pauseResume:(id)sender { // DBLog(@"Pause/Resume Sent!"); [self sendPortMessage:kCogPauseResumeMessage]; } - (IBAction)pause:(id)sender { // DBLog(@"Pause Sent!"); [self sendPortMessage:kCogPauseMessage]; } - (IBAction)resume:(id)sender { // DBLog(@"Resume Sent!"); [self sendPortMessage:kCogResumeMessage]; } - (IBAction)stop:(id)sender { // DBLog(@"Stop Sent!"); waitingForPlay = NO; [self sendPortMessage:kCogStopMessage]; } //called by double-clicking on table - (void)playEntryAtIndex:(int)i { PlaylistEntry *pe = [[playlistController arrangedObjects] objectAtIndex:i]; [playlistController setCurrentEntry:pe addToHistory:YES]; [playlistController reset]; [self playEntry:pe]; } - (IBAction)play:(id)sender { [self playEntryAtIndex:[playlistView selectedRow]]; } - (void)playEntry:(PlaylistEntry *)pe; { waitingForPlay = NO; // DBLog(@"PlayEntry: %@ Sent!", [pe filename]); [self sendPortMessage:kCogPlayFileMessage withString:[pe filename]]; } - (IBAction)next:(id)sender { waitingForPlay = NO; if ([playlistController nextEntry] == nil) return; [playlistController next]; [self playEntry:[playlistController currentEntry]]; } - (IBAction)prev:(id)sender { waitingForPlay = NO; if ([playlistController prevEntry] == nil) return; [playlistController prev]; [self playEntry:[playlistController currentEntry]]; } - (IBAction)seek:(id)sender { // DBLog(@"SEEKING?"); double time; time = [positionSlider doubleValue]; [self sendPortMessage:kCogSeekMessage withData:&time ofSize:(sizeof(double))]; int sec = (int)(time/1000.0); NSString *text; text = [NSString stringWithFormat:@"%i:%02i", sec/60, sec%60]; [timeField setStringValue:text]; } - (void)sendPortMessage:(int)msgid { NSPortMessage *portMessage = [[NSPortMessage alloc] initWithSendPort:distantPort receivePort:sendPort components:nil]; if (portMessage) { [portMessage setMsgid:msgid]; [portMessage sendBeforeDate:[NSDate date]]; [portMessage release]; } } - (void)sendPortMessage:(int)msgid withData:(void *)data ofSize:(int)size { NSPortMessage *portMessage; NSData *d = [[NSData alloc] initWithBytes:data length:size]; NSArray *a = [[NSArray alloc] initWithObjects:d,nil]; portMessage = [[NSPortMessage alloc] initWithSendPort:distantPort receivePort:sendPort components:a]; [a release]; [d release]; if (portMessage) { NSDate *date = [[NSDate alloc] init]; [portMessage setMsgid:msgid]; [portMessage sendBeforeDate:date]; [date release]; [portMessage release]; } } - (void)sendPortMessage:(int)msgid withString:(NSString *)s { NSData *dataString = [s dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]; NSPortMessage *portMessage = [[NSPortMessage alloc] initWithSendPort:distantPort receivePort:sendPort components:[NSArray arrayWithObject:dataString]]; if (portMessage) { [portMessage setMsgid:msgid]; [portMessage sendBeforeDate:[NSDate date]]; [portMessage release]; } } - (void)changePlayButtonImage:(NSString *)name { NSImage *img = [NSImage imageNamed:[name stringByAppendingString:@"_gray"]]; NSImage *alt = [NSImage imageNamed:[name stringByAppendingString:@"_blue"]]; [img retain]; [alt retain]; if (img == nil) { DBLog(@"NIL IMAGE!!!"); } if (alt == nil) { DBLog(@"NIL ALT"); } DBLog(@"Setting button: %@", name); [playButton setImage:img]; [playButton setAlternateImage:alt]; } - (IBAction)changeVolume:(id)sender { float v = (float)[sender floatValue]; [self sendPortMessage:kCogSetVolumeMessage withData:&v ofSize:sizeof(float)]; } - (IBAction)toggleShowTimeRemaining:(id)sender { NSString *text; showTimeRemaining = !showTimeRemaining; if (showTimeRemaining == NO) { int sec = (int)([positionSlider doubleValue]/1000.0); text = [NSString stringWithFormat:@"%i:%02i", sec/60, sec%60]; } else { int sec = (int)(([positionSlider maxValue] - [positionSlider doubleValue])/1000.0); text = [NSString stringWithFormat:@"%i:%02i", sec/60, sec%60]; } [timeField setStringValue:text]; } - (void)handlePortMessage:(NSPortMessage *)portMessage { unsigned int message = [portMessage msgid]; DBLog(@"GOT SOME KINDA WONDERFUL: %i %i", message, kCogStatusUpdateMessage); if (message == kCogCheckinMessage) { // Get the worker threadÕs communications port. DBLog(@"CHECKIN RECEIVED"); distantPort = [portMessage sendPort]; // Retain and save the worker port for later use. [distantPort retain]; } else if (message == kCogRequestNextFileMessage) { PlaylistEntry *pe; pe = [playlistController nextEntry]; if (pe == nil) { [self sendPortMessage:kCogEndOfPlaylistMessage]; } else { DBLog(@"REQUESTING"); waitingForPlay = YES; [self sendPortMessage:kCogChangeFileMessage withString:[pe filename]]; } } else if (message == kCogFileChangedMessage) { DBLog(@"FILE CHANGED"); if (waitingForPlay == YES) { waitingForPlay = NO; [playlistController next]; [timeField setStringValue:@"0:00"]; } } else if (message == kCogBitrateUpdateMessage) { NSArray* components = [portMessage components]; NSData *data = [components objectAtIndex:0]; int bitrate; bitrate = (*(int *)[data bytes]); // DBLog(@"Received length update: %f", max); // [bitrateField setIntValue:bitrate]; } else if (message == kCogLengthUpdateMessage) { NSArray* components = [portMessage components]; NSData *data = [components objectAtIndex:0]; double max; max = (*(double *)[data bytes]); // DBLog(@"Received length update: %f", max); [positionSlider setMaxValue:max]; [positionSlider setDoubleValue:0]; // DBLog(@"Length changed: %f", max); // [lengthField setDoubleValue:max/1000.0]; } else if (message == kCogPositionUpdateMessage) { NSArray* components = [portMessage components]; NSData *data = [components objectAtIndex:0]; double pos; pos = (*(double *)[data bytes]); if ([positionSlider tracking] == NO) { // DBLog(@"Received pos update: %f", pos); [positionSlider setDoubleValue:pos]; } NSString *text; if (showTimeRemaining == NO) { int sec = (int)(pos/1000.0); text = [NSString stringWithFormat:@"%i:%02i", sec/60, sec%60]; } else { int sec = (int)(([positionSlider maxValue] - pos)/1000.0); text = [NSString stringWithFormat:@"%i:%02i", sec/60, sec%60]; } [timeField setStringValue:text]; } else if (message == kCogStatusUpdateMessage) { DBLog(@"MESSAGE?"); NSArray* components = [portMessage components]; NSData *data = [components objectAtIndex:0]; int s; s = (*(int *)[data bytes]); playbackStatus = s; DBLog(@"STATUS UPDATE: %i", s); if (s == kCogStatusStopped || s == kCogStatusPaused) { //Show play image [self changePlayButtonImage:@"play"]; DBLog(@"PLAY PIC"); } else if (s == kCogStatusPlaying) { //Show pause [self changePlayButtonImage:@"pause"]; DBLog(@"PAUSE PIC"); } } } @end