diff --git a/src/clap_proxy.h b/src/clap_proxy.h index 71b36c9c..4e51bafd 100644 --- a/src/clap_proxy.h +++ b/src/clap_proxy.h @@ -35,6 +35,8 @@ class Raise; class IHost { public: + virtual ~IHost() = default; + virtual void mark_dirty() = 0; virtual void restartPlugin() = 0; virtual void request_callback() = 0; diff --git a/src/detail/standalone/macos/AppDelegate.h b/src/detail/standalone/macos/AppDelegate.h index 5234658e..62361a91 100644 --- a/src/detail/standalone/macos/AppDelegate.h +++ b/src/detail/standalone/macos/AppDelegate.h @@ -1,5 +1,13 @@ #import -@interface AppDelegate : NSObject +// @class AudioSettingsWindowDelegate; + +@interface AppDelegate : NSObject +{ + // AudioSettingsWindowDelegate *audioSettingsWindowDelegate; +} +@property(assign) IBOutlet NSWindow *window; + +- (IBAction)openAudioSettingsWindow:(id)sender; @end diff --git a/src/detail/standalone/macos/AppDelegate.mm b/src/detail/standalone/macos/AppDelegate.mm index c65f1ac9..4a6ba574 100644 --- a/src/detail/standalone/macos/AppDelegate.mm +++ b/src/detail/standalone/macos/AppDelegate.mm @@ -10,7 +10,6 @@ @interface AppDelegate () -@property(assign) IBOutlet NSWindow *window; @end @implementation AppDelegate @@ -76,6 +75,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification freeaudio::clap_wrapper::standalone::mainCreatePlugin(entry, pid, pindex, 1, (char **)argv); [[self window] orderFrontRegardless]; + [[self window] setDelegate:self]; if (plugin->_ext._gui) { @@ -88,6 +88,10 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification uint32_t w, h; ui->get_size(p, &w, &h); + if (ui->can_resize(p)) + { + ui->adjust_size(p, &w, &h); + } NSView *view = [[self window] contentView]; @@ -130,4 +134,118 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification freeaudio::clap_wrapper::standalone::mainFinish(); } +- (IBAction)openAudioSettingsWindow:(id)sender +{ + NSLog(@"openAudioSettingsWindow: Unimplemented"); +} + +- (void)windowDidResize:(NSNotification *)notification +{ + auto plugin = freeaudio::clap_wrapper::standalone::getMainPlugin(); + + if (plugin && plugin->_ext._gui) + { + auto canRS = plugin->_ext._gui->can_resize(plugin->_plugin); + if (canRS) + { + auto w = [self window]; + auto f = [w frame]; + auto cr = [w contentRectForFrameRect:f]; + plugin->_ext._gui->set_size(plugin->_plugin, cr.size.width, cr.size.height); + } + } +} + +- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize +{ + auto plugin = freeaudio::clap_wrapper::standalone::getMainPlugin(); + + if (plugin && plugin->_ext._gui) + { + auto w = [self window]; + auto f = [w frame]; + f.size = frameSize; + auto cr = [w contentRectForFrameRect:f]; + + auto canRS = plugin->_ext._gui->can_resize(plugin->_plugin); + if (!canRS) + { + uint32_t w, h; + plugin->_ext._gui->get_size(plugin->_plugin, &w, &h); + cr.size.width = w; + cr.size.height = h; + } + else + { + uint32_t w = frameSize.width, h = frameSize.height; + plugin->_ext._gui->adjust_size(plugin->_plugin, &w, &h); + cr.size.width = w; + cr.size.height = h; + } + auto fr = [w frameRectForContentRect:cr]; + frameSize = fr.size; + } + return frameSize; +} + +- (IBAction)saveDocumentAs:(id)sender +{ + NSSavePanel *savePanel = [NSSavePanel savePanel]; + [savePanel setNameFieldStringValue:@"Untitled"]; // + + if ([savePanel runModal] == NSModalResponseOK) + { + NSURL *documentURL = [savePanel URL]; + auto fsp = fs::path{[[documentURL path] UTF8String]}; + auto fn = fsp.replace_extension(".cwstream"); + + auto standaloneHost = freeaudio::clap_wrapper::standalone::getStandaloneHost(); + + try + { + standaloneHost->saveStandaloneAndPluginSettings(fn.parent_path(), fn.filename()); + } + catch (const fs::filesystem_error &e) + { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Unable to save file"]; + [alert setInformativeText:[[NSString alloc] initWithUTF8String:e.what()]]; + [alert addButtonWithTitle:@"OK"]; + [alert runModal]; + + } + } +} + +- (IBAction)openDocument:(id)sender +{ + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + [openPanel setCanChooseFiles:YES]; + [openPanel setCanChooseDirectories:NO]; + [openPanel setAllowedFileTypes:[NSArray arrayWithObject:@"cwstream"]]; + [openPanel setAllowsMultipleSelection:NO]; + + if ([openPanel runModal] == NSModalResponseOK) + { + NSURL *selectedUrl = [[openPanel URLs] objectAtIndex:0]; + + auto fn = fs::path{[[selectedUrl path] UTF8String]}; + + auto standaloneHost = freeaudio::clap_wrapper::standalone::getStandaloneHost(); + + try + { + standaloneHost->tryLoadStandaloneAndPluginSettings(fn.parent_path(), fn.filename()); + } + catch (const fs::filesystem_error &e) + { + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:@"Unable to open file"]; + [alert setInformativeText:[[NSString alloc] initWithUTF8String:e.what()]]; + [alert addButtonWithTitle:@"OK"]; + [alert runModal]; + } + } +} + @end diff --git a/src/detail/standalone/macos/Info.plist.in b/src/detail/standalone/macos/Info.plist.in index dbfa32ea..adb4d6f0 100644 --- a/src/detail/standalone/macos/Info.plist.in +++ b/src/detail/standalone/macos/Info.plist.in @@ -12,7 +12,7 @@ CFBundleIconFile CFBundleIdentifier - org.cmake.CocoaExample + ${MACOSX_BUNDLE_BUNDLE_NAME}.standalone CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/src/detail/standalone/macos/MainMenu.xib b/src/detail/standalone/macos/MainMenu.xib index 52585c31..50a479ea 100644 --- a/src/detail/standalone/macos/MainMenu.xib +++ b/src/detail/standalone/macos/MainMenu.xib @@ -1,7 +1,7 @@ - + - + @@ -31,6 +31,12 @@ + + + + + + @@ -66,25 +72,14 @@ - - - - - - - - - - - - - + @@ -121,7 +116,7 @@ - + diff --git a/src/detail/standalone/standalone_host_audio.cpp b/src/detail/standalone/standalone_host_audio.cpp index 60db873e..85de547c 100644 --- a/src/detail/standalone/standalone_host_audio.cpp +++ b/src/detail/standalone/standalone_host_audio.cpp @@ -42,14 +42,16 @@ void StandaloneHost::startAudioThread() auto dnms = rtaDac->getDeviceNames(); RtAudio::StreamParameters oParams; - oParams.nChannels = 2; - oParams.firstChannel = 0; oParams.deviceId = rtaDac->getDefaultOutputDevice(); + auto outInfo = rtaDac->getDeviceInfo(oParams.deviceId); + oParams.nChannels = std::min(2U, outInfo.outputChannels); + oParams.firstChannel = 0; RtAudio::StreamParameters iParams; - iParams.nChannels = 2; - iParams.firstChannel = 0; iParams.deviceId = rtaDac->getDefaultInputDevice(); + auto inInfo = rtaDac->getDeviceInfo(iParams.deviceId); + iParams.nChannels = std::min(2U, inInfo.inputChannels); + iParams.firstChannel = 0; LOG << "RtAudio Attached Devices" << std::endl; for (auto i = 0U; i < dids.size(); ++i) @@ -89,19 +91,26 @@ void StandaloneHost::startAudioThread() void StandaloneHost::stopAudioThread() { LOG << "Shutting down audio" << std::endl; - running = false; - - // bit of a hack. Wait until we get an ack from audio callback - for (auto i = 0; i < 10000 && !finishedRunning; ++i) + if (!rtaDac->isStreamRunning()) { - using namespace std::chrono_literals; - std::this_thread::sleep_for(1ms); - // todo put a sleep here + LOG << "Stream not running" << std::endl; } - LOG << "Audio Thread acknowledges shutdown" << std::endl; + else + { + running = false; - if (rtaDac && rtaDac->isStreamRunning()) rtaDac->stopStream(); - LOG << "RtAudio stream stopped" << std::endl; + // bit of a hack. Wait until we get an ack from audio callback + for (auto i = 0; i < 10000 && !finishedRunning; ++i) + { + using namespace std::chrono_literals; + std::this_thread::sleep_for(1ms); + // todo put a sleep here + } + LOG << "Audio Thread acknowledges shutdown" << std::endl; + + if (rtaDac && rtaDac->isStreamRunning()) rtaDac->stopStream(); + LOG << "RtAudio stream stopped" << std::endl; + } return; } } // namespace freeaudio::clap_wrapper::standalone \ No newline at end of file