Skip to content

Commit

Permalink
DPF based plugin (#57)
Browse files Browse the repository at this point in the history
* Start of DPF-based plugin

Signed-off-by: falkTX <falktx@falktx.com>

* Deal with any buffer size

Signed-off-by: falkTX <falktx@falktx.com>

* Pass host sample rate into jack

Signed-off-by: falkTX <falktx@falktx.com>

* Auto-start mod-ui as well

Signed-off-by: falkTX <falktx@falktx.com>

* Cleanup, split files

Signed-off-by: falkTX <falktx@falktx.com>

* macos plugin details

Signed-off-by: falkTX <falktx@falktx.com>

* More mac details

Signed-off-by: falkTX <falktx@falktx.com>

* MIDI stubs

Signed-off-by: falkTX <falktx@falktx.com>

* working MIDI

Signed-off-by: falkTX <falktx@falktx.com>

* Add com.apple.security.device.audio-input to entitlements

Signed-off-by: falkTX <falktx@falktx.com>

* update pawpaw

Signed-off-by: falkTX <falktx@falktx.com>

* Deal with some UI details

Signed-off-by: falkTX <falktx@falktx.com>

* x11 webview

Signed-off-by: falkTX <falktx@falktx.com>

* continue plugin tweaks

Signed-off-by: falkTX <falktx@falktx.com>

* Less hacky approach

Signed-off-by: falkTX <falktx@falktx.com>

* Start of multi-instance details

Signed-off-by: falkTX <falktx@falktx.com>

* Dynamic path handling on Linux too

Signed-off-by: falkTX <falktx@falktx.com>

* Make it versioned

Signed-off-by: falkTX <falktx@falktx.com>

* Use jack2 fork

Signed-off-by: falkTX <falktx@falktx.com>

* force CI rebuild

Signed-off-by: falkTX <falktx@falktx.com>

* win32 details

Signed-off-by: falkTX <falktx@falktx.com>

* more linux details

Signed-off-by: falkTX <falktx@falktx.com>

* even more linux details, qt6 variant, gtk-free usage

Signed-off-by: falkTX <falktx@falktx.com>

* Put the rest of the linux embed webview details in place

Signed-off-by: falkTX <falktx@falktx.com>

---------

Signed-off-by: falkTX <falktx@falktx.com>
  • Loading branch information
falkTX authored Mar 15, 2024
1 parent 86bcaa3 commit 64900a8
Show file tree
Hide file tree
Showing 35 changed files with 3,735 additions and 21 deletions.
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

0 comments on commit 64900a8

Please sign in to comment.