Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DPF based plugin #57

Merged
merged 24 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: build
on: [push, pull_request]

env:
CACHE_VERSION_LINUX: 24
CACHE_VERSION_MACOS: 20
CACHE_VERSION_WIN64: 19
CACHE_VERSION_LINUX: 25
CACHE_VERSION_MACOS: 25
CACHE_VERSION_WIN64: 25
DEBIAN_FRONTEND: noninteractive
HOMEBREW_NO_AUTO_UPDATE: 1
PAWPAW_FAST_MATH: 1
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
[submodule "src/PawPaw"]
path = src/PawPaw
url = https://github.com/DISTRHO/PawPaw.git
[submodule "src/DPF"]
path = src/DPF
url = https://github.com/DISTRHO/DPF.git
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ PAWPAW_PREFIX = $(PAWPAW_DIR)/targets/$(PAWPAW_TARGET)$(PAWPAW_SUFFIX)
# ---------------------------------------------------------------------------------------------------------------------
# List of files created by PawPaw bootstrap, to ensure we have run it at least once

ifeq ($(MACOS),true)
BOOTSTRAP_FILES = $(PAWPAW_PREFIX)/bin/cxfreeze
else
BOOTSTRAP_FILES = $(PAWPAW_PREFIX)/bin/cxfreeze-quickstart
endif
BOOTSTRAP_FILES += $(PAWPAW_PREFIX)/bin/jackd$(APP_EXT)
BOOTSTRAP_FILES += $(PAWPAW_PREFIX)/include/armadillo

Expand All @@ -102,6 +106,7 @@ TARGETS += build/mod-desktop.app/Contents/MacOS/jack/jack-session.conf
TARGETS += build/mod-desktop.app/Contents/MacOS/jack/jack_coreaudio.so
TARGETS += build/mod-desktop.app/Contents/MacOS/jack/jack_coremidi.so
TARGETS += build/mod-desktop.app/Contents/MacOS/jack/jack_dummy.so
TARGETS += build/mod-desktop.app/Contents/MacOS/jack/jack_mod-desktop.so
TARGETS += build/mod-desktop.app/Contents/MacOS/jack/mod-host.so
TARGETS += build/mod-desktop.app/Contents/MacOS/jack/mod-midi-broadcaster.so
TARGETS += build/mod-desktop.app/Contents/MacOS/jack/mod-midi-merger.so
Expand Down Expand Up @@ -143,6 +148,7 @@ TARGETS += build/pedalboards
TARGETS += build/VERSION
ifeq ($(WINDOWS),true)
TARGETS += build/jack/jack_dummy.dll
TARGETS += build/jack/jack_mod-desktop.dll
TARGETS += build/jack/jack_portaudio.dll
TARGETS += build/jack/jack_winmme.dll
TARGETS += build/libjack64.dll
Expand All @@ -162,6 +168,7 @@ else
TARGETS += build/jack/alsa_midi.so
TARGETS += build/jack/jack_alsa.so
TARGETS += build/jack/jack_dummy.so
TARGETS += build/jack/jack_mod-desktop.so
TARGETS += build/jack/jack_portaudio.so
TARGETS += build/jack/jack-session-alsamidi.conf
TARGETS += build/libjack.so.0
Expand Down Expand Up @@ -274,10 +281,13 @@ TARGETS += $(foreach PLUGIN,$(PLUGINS),$(call PLUGIN_STAMP,$(PLUGIN)))
# ---------------------------------------------------------------------------------------------------------------------

all: $(TARGETS)
./utils/run.sh $(PAWPAW_TARGET) $(MAKE) -C src/plugin

clean:
$(MAKE) clean -C src/DPF
$(MAKE) clean -C src/mod-host
$(MAKE) clean -C src/mod-ui/utils
$(MAKE) clean -C src/plugin
$(MAKE) clean -C src/systray
rm -rf build
rm -rf build-midi-merger
Expand Down Expand Up @@ -318,6 +328,9 @@ win64-app:
win64-bootstrap:
./src/PawPaw/bootstrap-mod.sh win64

win64-plugin:
./utils/run.sh win64 $(MAKE) -C src/plugin

win64-plugins:
$(MAKE) PAWPAW_TARGET=win64 plugins

Expand Down
1 change: 1 addition & 0 deletions src/DPF
Submodule DPF added at ba985c
2 changes: 1 addition & 1 deletion src/mod-host
2 changes: 1 addition & 1 deletion src/mod-ui
279 changes: 279 additions & 0 deletions src/plugin/ChildProcess.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
// SPDX-FileCopyrightText: 2023-2024 MOD Audio UG
// SPDX-License-Identifier: AGPL-3.0-or-later

#pragma once

#include "extra/Sleep.hpp"
#include "Time.hpp"

#if defined(DISTRHO_OS_MAC)
#elif defined(DISTRHO_OS_WINDOWS)
#else
#endif

#ifdef DISTRHO_OS_WINDOWS
# include <string>
# include <winsock2.h>
# include <windows.h>
#else
# include <cerrno>
# include <ctime>
# include <signal.h>
# include <sys/wait.h>
#endif

// #include <sys/time.h>

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------

class ChildProcess
{
#ifdef _WIN32
PROCESS_INFORMATION process = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };
#else
pid_t pid = -1;
#endif

public:
ChildProcess()
{
}

~ChildProcess()
{
stop();
}

#ifdef _WIN32
bool start(const char* const args[], const WCHAR* const envp)
#else
bool start(const char* const args[], char* const* const envp = nullptr)
#endif
{
#ifdef _WIN32
std::string cmd;

for (uint i = 0; args[i] != nullptr; ++i)
{
if (i != 0)
cmd += " ";

if (std::strchr(args[i], ' ') != nullptr)
{
cmd += "\"";
cmd += args[i];
cmd += "\"";
}
else
{
cmd += args[i];
}
}

wchar_t wcmd[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, cmd.data(), -1, wcmd, PATH_MAX) <= 0)
return false;

STARTUPINFOW si = {};
si.cb = sizeof(si);

d_stdout("will start process with args '%s'", cmd.data());

return CreateProcessW(nullptr, // lpApplicationName
wcmd, // lpCommandLine
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
TRUE, // bInheritHandles
/* CREATE_NO_WINDOW | */ CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
const_cast<LPWSTR>(envp), // lpEnvironment
nullptr, // lpCurrentDirectory
&si, // lpStartupInfo
&process) != FALSE;
#else
const pid_t ret = pid = vfork();

switch (ret)
{
// child process
case 0:
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);
break;

// error
case -1:
d_stderr2("vfork() failed: %d:%s", errno, std::strerror(errno));
break;
}

return ret > 0;
#endif
}

void stop(const uint32_t timeoutInMilliseconds = 2000)
{
const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds;
bool sendTerminate = true;

#ifdef _WIN32
if (process.hProcess == INVALID_HANDLE_VALUE)
return;

const PROCESS_INFORMATION oprocess = process;
process = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };

for (;;)
{
switch (WaitForSingleObject(oprocess.hProcess, 0))
{
case WAIT_OBJECT_0:
case WAIT_FAILED:
CloseHandle(oprocess.hThread);
CloseHandle(oprocess.hProcess);
return;
}

if (sendTerminate)
{
sendTerminate = false;
TerminateProcess(oprocess.hProcess, 15);
}
if (d_gettime_ms() < timeout)
{
d_msleep(5);
continue;
}
d_stderr("ChildProcess::stop() - timed out");
TerminateProcess(oprocess.hProcess, 9);
d_msleep(5);
CloseHandle(oprocess.hThread);
CloseHandle(oprocess.hProcess);
break;
}
#else
if (pid <= 0)
return;

const pid_t opid = pid;
pid = -1;

for (pid_t ret;;)
{
try {
ret = ::waitpid(opid, nullptr, WNOHANG);
} DISTRHO_SAFE_EXCEPTION_BREAK("waitpid");

switch (ret)
{
case -1:
if (errno == ECHILD)
{
// success, child doesn't exist
return;
}
else
{
d_stderr("ChildProcess::stop() - waitpid failed: %d:%s", errno, std::strerror(errno));
return;
}
break;

case 0:
if (sendTerminate)
{
sendTerminate = false;
kill(opid, SIGTERM);
}
if (d_gettime_ms() < timeout)
{
d_msleep(5);
continue;
}

d_stderr("ChildProcess::stop() - timed out");
kill(opid, SIGKILL);
waitpid(opid, nullptr, WNOHANG);
break;

default:
if (ret == opid)
{
// success
return;
}
else
{
d_stderr("ChildProcess::stop() - got wrong pid %i (requested was %i)", int(ret), int(opid));
return;
}
}

break;
}
#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 == pid || (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)
};

// -----------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO
Loading
Loading