diff --git a/src/plugin/ChildProcess.hpp b/src/plugin/ChildProcess.hpp index 4ef01b4..1d298b8 100644 --- a/src/plugin/ChildProcess.hpp +++ b/src/plugin/ChildProcess.hpp @@ -55,36 +55,8 @@ class ChildProcess stop(); } - bool start(const char* const args[]) + bool start(const char* const args[], char* const* const envp = nullptr) { - // FIXME - #ifdef DISTRHO_OS_WINDOWS - const CHAR* const envp = ( - "MOD_DATA_DIR=" P "\\data\0" - "MOD_FACTORY_PEDALBOARDS_DIR=" P "\\pedalboards\0" - "LV2_PATH=" P "\\plugins\0" - "\0"); - #else - const char* const envp[] = { - "MOD_DESKTOP=1", - "LANG=en_US.UTF-8", - #if defined(DISTRHO_OS_MAC) - "DYLD_LIBRARY_PATH=" P "/MacOS", - "JACK_DRIVER_DIR=" P "/MacOS/jack", - "MOD_DATA_DIR=/Users/falktx/Documents/MOD Desktop", - "MOD_FACTORY_PEDALBOARDS_DIR=" P "/Resources/pedalboards", - "LV2_PATH=" P "/LV2", - #else - "LD_LIBRARY_PATH=" P, - "JACK_DRIVER_DIR=" P "/jack", - "MOD_DATA_DIR=" P "/data", - "MOD_FACTORY_PEDALBOARDS_DIR=" P "/pedalboards", - "LV2_PATH=" P "/plugins", - #endif - nullptr - }; - #endif - #ifdef _WIN32 std::string cmd; @@ -93,6 +65,7 @@ class ChildProcess if (i != 0) cmd += " "; + // TODO quoted cmd += args[i]; } @@ -118,7 +91,10 @@ class ChildProcess { // child process case 0: - execve(args[0], const_cast<char* const*>(args), const_cast<char* const*>(envp)); + if (envp != nullptr) + execve(args[0], const_cast<char* const*>(args), envp); + else + execvp(args[0], const_cast<char* const*>(args)); d_stderr2("exec failed: %d:%s", errno, std::strerror(errno)); _exit(1); @@ -134,29 +110,6 @@ class ChildProcess #endif } - bool start2(const char* const args[]) - { - const pid_t ret = pid = vfork(); - - switch (ret) - { - // child process - case 0: - execvp(args[0], const_cast<char* const*>(args)); - - d_stderr2("exec failed: %d:%s", errno, std::strerror(errno)); - _exit(1); - break; - - // error - case -1: - d_stderr2("vfork() failed: %d:%s", errno, std::strerror(errno)); - break; - } - - return ret > 0; - } - void stop(const uint32_t timeoutInMilliseconds = 2000) { const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds; @@ -260,6 +213,57 @@ class ChildProcess #endif } + bool isRunning() + { + #ifdef _WIN32 + if (process.hProcess == INVALID_HANDLE_VALUE) + return false; + + if (WaitForSingleObject(process.hProcess, 0) == WAIT_FAILED) + { + const PROCESS_INFORMATION oprocess = process; + process = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 }; + CloseHandle(oprocess.hThread); + CloseHandle(oprocess.hProcess); + return false; + } + + return true; + #else + if (pid <= 0) + return false; + + const pid_t ret = ::waitpid(pid, nullptr, WNOHANG); + + if (ret == -1 && errno == ECHILD) + { + pid = 0; + return false; + } + + return true; + #endif + } + + #ifndef _WIN32 + void signal(const int sig) + { + if (pid > 0) + kill(pid, sig); + } + #endif + + void terminate() + { + #ifdef _WIN32 + if (process.hProcess != INVALID_HANDLE_VALUE) + TerminateProcess(process.hProcess, 15); + #else + if (pid > 0) + kill(pid, SIGTERM); + #endif + } + DISTRHO_DECLARE_NON_COPYABLE(ChildProcess) }; diff --git a/src/plugin/DesktopAudioDriver.cpp b/src/plugin/DesktopAudioDriver.cpp index 2b3b6d8..247751b 100644 --- a/src/plugin/DesktopAudioDriver.cpp +++ b/src/plugin/DesktopAudioDriver.cpp @@ -133,6 +133,13 @@ class DesktopAudioDriver : public JackAudioDriver if (! wait()) continue; + if (fShmData->magic == 7331) + { + fIsProcessing = false; + post(); + return; + } + CycleTakeBeginTime(); if (Process() != 0) @@ -157,11 +164,13 @@ class DesktopAudioDriver : public JackAudioDriver fIsRunning(false) { printf("%03d:%s\n", __LINE__, __FUNCTION__); + fflush(stdout); } ~DesktopAudioDriver() override { printf("%03d:%s\n", __LINE__, __FUNCTION__); + fflush(stdout); } int Open(jack_nframes_t buffersize, @@ -177,6 +186,7 @@ class DesktopAudioDriver : public JackAudioDriver jack_nframes_t playback_latency) override { printf("%03d:%s\n", __LINE__, __FUNCTION__); + fflush(stdout); if (JackAudioDriver::Open(buffersize, samplerate, capturing, playing, chan_in, chan_out, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) { return -1; @@ -262,38 +272,14 @@ class DesktopAudioDriver : public JackAudioDriver } #endif - jack_port_id_t port_index; - JackPort* port; - if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_capture_1", JACK_DEFAULT_MIDI_TYPE, - CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) - { - Close(); - jack_error("Can't open default MOD Desktop driver 6"); - return -1; - } - fCaptureMidiPort = port_index; - port = fGraphManager->GetPort(port_index); - port->SetAlias("MOD Desktop MIDI Capture"); - - if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_playback_1", JACK_DEFAULT_MIDI_TYPE, - PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) - { - { - Close(); - jack_error("Can't open default MOD Desktop driver 7"); - return -1; - } - } - fPlaybackMidiPort = port_index; - port = fGraphManager->GetPort(port_index); - port->SetAlias("MOD Desktop MIDI Playback"); - return 0; } int Close() override { printf("%03d:%s\n", __LINE__, __FUNCTION__); + fflush(stdout); + JackAudioDriver::Close(); #ifdef __APPLE__ @@ -339,13 +325,60 @@ class DesktopAudioDriver : public JackAudioDriver return 0; } -// int Attach() override -// { -// } + int Attach() override + { + printf("%03d:%s | %u\n", __LINE__, __FUNCTION__, fShmData->magic); + fflush(stdout); + + if (JackAudioDriver::Attach() != 0) + return -1; + + jack_port_id_t port_index; + JackPort* port; + if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_capture_1", JACK_DEFAULT_MIDI_TYPE, + CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) + { + Close(); + jack_error("Can't open default MOD Desktop driver 6"); + return -1; + } + fCaptureMidiPort = port_index; + port = fGraphManager->GetPort(port_index); + port->SetAlias("MOD Desktop MIDI Capture"); + + if (fEngine->PortRegister(fClientControl.fRefNum, "system:midi_playback_1", JACK_DEFAULT_MIDI_TYPE, + PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) + { + { + Close(); + jack_error("Can't open default MOD Desktop driver 7"); + return -1; + } + } + fPlaybackMidiPort = port_index; + port = fGraphManager->GetPort(port_index); + port->SetAlias("MOD Desktop MIDI Playback"); + + return 0; + } + + int Detach() override + { + printf("%03d:%s | %u\n", __LINE__, __FUNCTION__, fShmData->magic); + fflush(stdout); + + if (JackAudioDriver::Detach() != 0) + return -1; + + fEngine->PortUnRegister(fClientControl.fRefNum, fCaptureMidiPort); + fEngine->PortUnRegister(fClientControl.fRefNum, fPlaybackMidiPort); + return 0; + } int Start() override { printf("%03d:%s\n", __LINE__, __FUNCTION__); + fflush(stdout); if (JackAudioDriver::Start() != 0) return -1; @@ -361,7 +394,9 @@ class DesktopAudioDriver : public JackAudioDriver int Stop() override { - printf("%03d:%s\n", __LINE__, __FUNCTION__); + printf("%03d:%s | %u\n", __LINE__, __FUNCTION__, fShmData->magic); + fflush(stdout); + fIsProcessing = false; if (fIsRunning) diff --git a/src/plugin/DesktopPlugin.cpp b/src/plugin/DesktopPlugin.cpp index 5f82c50..bd09373 100644 --- a/src/plugin/DesktopPlugin.cpp +++ b/src/plugin/DesktopPlugin.cpp @@ -24,6 +24,12 @@ class DesktopPlugin : public Plugin uint32_t numFramesInShmBuffer = 0; uint32_t numFramesInTmpBuffer = 0; + #ifdef DISTRHO_OS_WINDOWS + const CHAR* envp; + #else + char** envp; + #endif + public: DesktopPlugin() : Plugin(0, 0, 0) @@ -31,6 +37,42 @@ class DesktopPlugin : public Plugin if (isDummyInstance()) return; + #ifdef DISTRHO_OS_WINDOWS + envp = ( + "MOD_DATA_DIR=" P "\\data\0" + "MOD_FACTORY_PEDALBOARDS_DIR=" P "\\pedalboards\0" + "LV2_PATH=" P "\\plugins\0" + "\0" + ); + #else + uint envsize = 0; + while (environ[envsize] != nullptr) + ++envsize; + + envp = new char*[envsize + 8]; + + for (uint i = 0; i < envsize; ++i) + envp[i] = strdup(environ[i]); + + envp[envsize] = strdup("MOD_DESKTOP=1"); + envp[envsize + 1] = strdup("LANG=en_US.UTF-8"); + #ifdef DISTRHO_OS_MAC + envp[envsize + 2] = strdup("DYLD_LIBRARY_PATH=" P "/MacOS"); + envp[envsize + 3] = strdup("JACK_DRIVER_DIR=" P "/MacOS/jack"); + envp[envsize + 4] = strdup("MOD_DATA_DIR=/Users/falktx/Documents/MOD Desktop"); + envp[envsize + 5] = strdup("MOD_FACTORY_PEDALBOARDS_DIR=" P "/Resources/pedalboards"); + envp[envsize + 6] = strdup("LV2_PATH=" P "/LV2"); + envp[envsize + 7] = nullptr; + #else + envp[envsize + 2] = strdup("LD_LIBRARY_PATH=" P); + envp[envsize + 3] = strdup("JACK_DRIVER_DIR=" P "/jack"); + envp[envsize + 4] = strdup("MOD_DATA_DIR=" P "/data"); + envp[envsize + 5] = strdup("MOD_FACTORY_PEDALBOARDS_DIR=" P "/pedalboards"); + envp[envsize + 6] = strdup("LV2_PATH=" P "/plugins"); + envp[envsize + 7] = nullptr; + #endif + #endif + const String sampleRateStr(static_cast<int>(getSampleRate())); const char* const jackd_args[] = { #if defined(DISTRHO_OS_MAC) @@ -63,24 +105,36 @@ class DesktopPlugin : public Plugin nullptr }; - if (shm.init() && jackd.start(jackd_args)) + if (shm.init() && jackd.start(jackd_args, envp)) { processing = true; bufferSizeChanged(getBufferSize()); d_msleep(500); - mod_ui.start(mod_ui_args); + mod_ui.start(mod_ui_args, envp); } } ~DesktopPlugin() { - mod_ui.stop(); + if (processing && jackd.isRunning()) + shm.stopWait(); + jackd.stop(); + mod_ui.stop(); + shm.deinit(); delete[] tmpBuffers[0]; delete[] tmpBuffers[1]; + + #ifdef DISTRHO_OS_WINDOWS + #else + for (uint i = 0; envp[i] != nullptr; ++i) + std::free(envp[i]); + + delete[] envp; + #endif } protected: diff --git a/src/plugin/SharedMemory.hpp b/src/plugin/SharedMemory.hpp index f3f2475..35da376 100644 --- a/src/plugin/SharedMemory.hpp +++ b/src/plugin/SharedMemory.hpp @@ -204,6 +204,16 @@ class SharedMemory std::memset(data->audio, 0, sizeof(float) * 128 * 2); } + void stopWait() + { + if (data == nullptr) + return; + + data->magic = 7331; + post(); + wait(); + } + bool process(float** output, const uint32_t offset) { // unlock RT waiter diff --git a/src/plugin/WebView.mm b/src/plugin/WebView.mm index 8e82e1e..f1b30be 100644 --- a/src/plugin/WebView.mm +++ b/src/plugin/WebView.mm @@ -19,7 +19,7 @@ DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT - kVerticalOffset); - WKWebView* const webview = [[WKWebView alloc] initWithFrame: rect]; + WKWebView* const webview = [[[WKWebView alloc] initWithFrame: rect] retain]; [[[webview configuration] preferences] setValue: @(true) forKey: @"developerExtrasEnabled"]; @@ -29,6 +29,14 @@ return webview; } +void destroyWebView(void* const webviewptr) +{ + WKWebView* const webview = static_cast<WKWebView*>(webviewptr); + + [webview setHidden:YES]; + [[webview dealloc] release]; +} + void reloadWebView(void* const webviewptr) { WKWebView* const webview = static_cast<WKWebView*>(webviewptr); diff --git a/src/plugin/WebViewX11.cpp b/src/plugin/WebViewX11.cpp index c05fa49..a1e2f9d 100644 --- a/src/plugin/WebViewX11.cpp +++ b/src/plugin/WebViewX11.cpp @@ -26,16 +26,7 @@ struct WebViewIPC { void* addWebView(uintptr_t viewptr) { - ::Display* const display = XOpenDisplay(nullptr); - DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr); - - WebViewIPC* const ipc = new WebViewIPC(); - ipc->display = display; - ipc->childWindow = 0; - ipc->ourWindow = viewptr; - char webviewTool[PATH_MAX] = {}; - { Dl_info info = {}; dladdr((void*)addWebView, &info); @@ -55,16 +46,25 @@ void* addWebView(uintptr_t viewptr) { std::strncpy(webviewTool, info.dli_fname, PATH_MAX - 1); } + + char* const lastsep = std::strrchr(webviewTool, '/'); + DISTRHO_SAFE_ASSERT_RETURN(lastsep != nullptr, nullptr); + + *lastsep = '\0'; + std::strncat(webviewTool, "/MOD-Desktop-WebView", PATH_MAX - 1); } - if (char* const c = std::strrchr(webviewTool, '/')) - *c = 0; + ::Display* const display = XOpenDisplay(nullptr); + DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, nullptr); - std::strncat(webviewTool, "/MOD-Desktop-WebView", PATH_MAX - 1); + WebViewIPC* const ipc = new WebViewIPC(); + ipc->display = display; + ipc->childWindow = 0; + ipc->ourWindow = viewptr; const String viewStr(viewptr); const char* const args[] = { webviewTool, "-platform", "xcb", "-xembed", viewStr.buffer(), nullptr }; - ipc->p.start2(args); + ipc->p.start(args); return ipc; } @@ -79,6 +79,9 @@ void destroyWebView(void* const webviewptr) void reloadWebView(void* const webviewptr) { + WebViewIPC* const ipc = static_cast<WebViewIPC*>(webviewptr); + + ipc->p.signal(SIGUSR1); } void resizeWebView(void* const webviewptr, const uint offset, const uint width, const uint height)