From cdfcc4ca2d5bfe9aab2df10ffc13cc425abf086d Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sat, 21 May 2022 02:17:59 +0300 Subject: [PATCH] Audio recording in the Cocoa frontend --- Cocoa/AudioRecordingAccessoryView.xib | 51 ++++++++++++++++ Cocoa/Document.h | 2 + Cocoa/Document.m | 87 ++++++++++++++++++++++++--- Cocoa/MainMenu.xib | 9 ++- 4 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 Cocoa/AudioRecordingAccessoryView.xib diff --git a/Cocoa/AudioRecordingAccessoryView.xib b/Cocoa/AudioRecordingAccessoryView.xib new file mode 100644 index 0000000..6dda38b --- /dev/null +++ b/Cocoa/AudioRecordingAccessoryView.xib @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Cocoa/Document.h b/Cocoa/Document.h index e92c180..c52a4ed 100644 --- a/Cocoa/Document.h +++ b/Cocoa/Document.h @@ -56,6 +56,8 @@ @property (readonly) GB_oam_info_t *oamInfo; @property uint8_t oamCount; @property uint8_t oamHeight; +@property (strong) IBOutlet NSView *audioRecordingAccessoryView; +@property (strong) IBOutlet NSPopUpButton *audioFormatButton; + (NSImage *) imageFromData:(NSData *)data width:(NSUInteger) width height:(NSUInteger) height scale:(double) scale; -(uint8_t) readMemory:(uint16_t) addr; diff --git a/Cocoa/Document.m b/Cocoa/Document.m index c68d146..453e3c8 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -101,6 +101,9 @@ enum model { Document *slave; signed linkOffset; bool linkCableBit; + + NSSavePanel *_audioSavePanel; + bool _isRecordingAudio; } @property GBAudioClient *audioClient; @@ -1134,7 +1137,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) return !GB_debugger_is_stopped(&gb); } else if ([anItem action] == @selector(reset:) && anItem.tag != MODEL_NONE) { - [(NSMenuItem*)anItem setState:anItem.tag == current_model]; + [(NSMenuItem *)anItem setState:anItem.tag == current_model]; } else if ([anItem action] == @selector(interrupt:)) { if (![[NSUserDefaults standardUserDefaults] boolForKey:@"DeveloperMode"]) { @@ -1142,26 +1145,29 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) } } else if ([anItem action] == @selector(disconnectAllAccessories:)) { - [(NSMenuItem*)anItem setState:accessory == GBAccessoryNone]; + [(NSMenuItem *)anItem setState:accessory == GBAccessoryNone]; } else if ([anItem action] == @selector(connectPrinter:)) { - [(NSMenuItem*)anItem setState:accessory == GBAccessoryPrinter]; + [(NSMenuItem *)anItem setState:accessory == GBAccessoryPrinter]; } else if ([anItem action] == @selector(connectWorkboy:)) { - [(NSMenuItem*)anItem setState:accessory == GBAccessoryWorkboy]; + [(NSMenuItem *)anItem setState:accessory == GBAccessoryWorkboy]; } else if ([anItem action] == @selector(connectLinkCable:)) { - [(NSMenuItem*)anItem setState:[(NSMenuItem *)anItem representedObject] == master || + [(NSMenuItem *)anItem setState:[(NSMenuItem *)anItem representedObject] == master || [(NSMenuItem *)anItem representedObject] == slave]; } else if ([anItem action] == @selector(toggleCheats:)) { - [(NSMenuItem*)anItem setState:GB_cheats_enabled(&gb)]; + [(NSMenuItem *)anItem setState:GB_cheats_enabled(&gb)]; } else if ([anItem action] == @selector(toggleDisplayBackground:)) { - [(NSMenuItem*)anItem setState:!GB_is_background_rendering_disabled(&gb)]; + [(NSMenuItem *)anItem setState:!GB_is_background_rendering_disabled(&gb)]; } else if ([anItem action] == @selector(toggleDisplayObjects:)) { - [(NSMenuItem*)anItem setState:!GB_is_object_rendering_disabled(&gb)]; + [(NSMenuItem *)anItem setState:!GB_is_object_rendering_disabled(&gb)]; + } + else if ([anItem action] == @selector(toggleAudioRecording:)) { + [(NSMenuItem *)anItem setTitle:_isRecordingAudio? @"Stop Audio Recording" : @"Start Audio Recording…"]; } return [super validateUserInterfaceItem:anItem]; @@ -2388,5 +2394,70 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) }]; } +- (IBAction)toggleAudioRecording:(id)sender +{ + + bool shouldResume = running; + [self stop]; + if (_isRecordingAudio) { + _isRecordingAudio = false; + int error = GB_stop_audio_recording(&gb); + if (error) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:[NSString stringWithFormat:@"Could not finalize recording: %s", strerror(error)]]; + [alert setAlertStyle:NSAlertStyleCritical]; + [alert runModal]; + } + else { + [self.osdView displayText:@"Audio recording ended"]; + } + if (shouldResume) { + [self start]; + } + return; + } + _audioSavePanel = [NSSavePanel savePanel]; + if (!self.audioRecordingAccessoryView) { + [[NSBundle mainBundle] loadNibNamed:@"AudioRecordingAccessoryView" owner:self topLevelObjects:nil]; + } + _audioSavePanel.accessoryView = self.audioRecordingAccessoryView; + [self audioFormatChanged:self.audioFormatButton]; + + [_audioSavePanel beginSheetModalForWindow:self.mainWindow completionHandler:^(NSInteger result) { + if (result == NSModalResponseOK) { + [_audioSavePanel orderOut:self]; + int error = GB_start_audio_recording(&gb, _audioSavePanel.URL.fileSystemRepresentation, self.audioFormatButton.selectedTag); + if (error) { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:[NSString stringWithFormat:@"Could not start recording: %s", strerror(error)]]; + [alert setAlertStyle:NSAlertStyleCritical]; + [alert runModal]; + } + else { + [self.osdView displayText:@"Audio recording started"]; + _isRecordingAudio = true; + } + } + if (shouldResume) { + [self start]; + } + _audioSavePanel = nil; + }]; +} + +- (IBAction)audioFormatChanged:(NSPopUpButton *)sender +{ + switch ((GB_audio_format_t)sender.selectedTag) { + case GB_AUDIO_FORMAT_RAW: + _audioSavePanel.allowedFileTypes = @[@"raw", @"pcm"]; + break; + case GB_AUDIO_FORMAT_AIFF: + _audioSavePanel.allowedFileTypes = @[@"aiff", @"aif", @"aifc"]; + break; + case GB_AUDIO_FORMAT_WAV: + _audioSavePanel.allowedFileTypes = @[@"wav"]; + break; + } +} @end diff --git a/Cocoa/MainMenu.xib b/Cocoa/MainMenu.xib index 3a6cff5..55e31cb 100644 --- a/Cocoa/MainMenu.xib +++ b/Cocoa/MainMenu.xib @@ -370,9 +370,14 @@ - + - + + + + + +