From bc4b13814c30abb801dd93cec14f024e8f0d1aac Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 12 Mar 2024 00:01:35 +0100 Subject: [PATCH] Cleanup, split files Signed-off-by: falkTX --- src/plugin/ChildProcess.hpp | 153 ++++++++++++ src/plugin/DesktopAudioDriver.cpp | 375 ++++++++++++++++-------------- src/plugin/DesktopPlugin.cpp | 357 ++++------------------------ src/plugin/SharedMemory.hpp | 187 +++++++++++++++ src/plugin/Time.hpp | 125 ++++++++++ 5 files changed, 707 insertions(+), 490 deletions(-) create mode 100644 src/plugin/ChildProcess.hpp create mode 100644 src/plugin/SharedMemory.hpp create mode 100644 src/plugin/Time.hpp diff --git a/src/plugin/ChildProcess.hpp b/src/plugin/ChildProcess.hpp new file mode 100644 index 0000000..22c7b7f --- /dev/null +++ b/src/plugin/ChildProcess.hpp @@ -0,0 +1,153 @@ +// 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 +#else +# include +# include +# include +# include +#endif + +// #include + +START_NAMESPACE_DISTRHO + +// FIXME +#define P "/home/falktx/Source/MOD/mod-app/build" + +// ----------------------------------------------------------------------------------------------------------- + +class ChildProcess +{ + #ifdef _WIN32 + #else + pid_t pid = 0; + #endif + +public: + ChildProcess() + { + } + + ~ChildProcess() + { + stop(); + } + + bool start(const char* const args[]) + { + // FIXME + const char* const envp[] = { + "LD_LIBRARY_PATH=" P, + "JACK_DRIVER_DIR=" P "/jack", + "MOD_DATA_DIR=" P "/data", + "MOD_FACTORY_PEDALBOARDS_DIR=" P "/pedalboards", + "MOD_DESKTOP=1", + "LANG=en_US.UTF-8", + "LV2_PATH=" P "/plugins", + nullptr + }; + + const pid_t ret = pid = vfork(); + + switch (ret) + { + // child process + case 0: + execve(args[0], const_cast(args), const_cast(envp)); + + 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) + { + if (pid == 0) + return; + + const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds; + const pid_t opid = pid; + pid_t ret; + bool sendTerminate = true; + pid = 0; + + for (;;) + { + 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; + } + } + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChildProcess) +}; + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/src/plugin/DesktopAudioDriver.cpp b/src/plugin/DesktopAudioDriver.cpp index bfdde83..4b59d24 100644 --- a/src/plugin/DesktopAudioDriver.cpp +++ b/src/plugin/DesktopAudioDriver.cpp @@ -6,234 +6,263 @@ #include "JackEngineControl.h" #include "JackTools.h" +#if defined(__APPLE__) +#elif defined(_WIN32) +#else #include -#include - #include -#include #include #include #include -#include #include +#endif namespace Jack { // ----------------------------------------------------------------------------------------------------------- -struct SharedMemoryData { - uint32_t magic; - int32_t sem1; - int32_t sem2; - int32_t padding1; - // uint8_t sem[32]; - uint16_t midiEventCount; - uint16_t midiFrames[511]; - uint8_t midiData[511 * 4]; - uint8_t padding2[4]; - float audio[]; -}; - -const size_t kSharedMemoryDataSize = sizeof(SharedMemoryData) + sizeof(float) * 128 * 2; +class DesktopAudioDriver : public JackAudioDriver +{ + struct Data { + uint32_t magic; + int32_t sem1; + int32_t sem2; + int32_t padding1; + // uint8_t sem[32]; + uint16_t midiEventCount; + uint16_t midiFrames[511]; + uint8_t midiData[511 * 4]; + uint8_t padding2[4]; + float audio[]; + }* data = nullptr; + + static constexpr const size_t kDataSize = sizeof(Data) + sizeof(float) * 128 * 2; + + Data* fShmData; + + #if defined(__APPLE__) + void post() + { + } -// ----------------------------------------------------------------------------------------------------------- + bool wait() + { + return false; + } + #elif defined(_WIN32) + void post() + { + } -static inline -void shm_sem_rt_post(SharedMemoryData* const data) -{ - const bool unlocked = __sync_bool_compare_and_swap(&data->sem2, 0, 1); - if (! unlocked) - return; - ::syscall(__NR_futex, &data->sem2, FUTEX_WAKE, 1, nullptr, nullptr, 0); -} + bool wait() + { + return false; + } + #else + int fShmFd; -static inline -bool shm_sem_rt_wait(SharedMemoryData* const data) -{ - const timespec timeout = { 1, 0 }; + void post() + { + const bool unlocked = __sync_bool_compare_and_swap(&data->sem2, 0, 1); + if (! unlocked) + return; + ::syscall(__NR_futex, &data->sem2, FUTEX_WAKE, 1, nullptr, nullptr, 0); + } - for (;;) + bool wait() { - if (__sync_bool_compare_and_swap(&data->sem1, 1, 0)) - return true; + const timespec timeout = { 1, 0 }; + + for (;;) + { + if (__sync_bool_compare_and_swap(&data->sem1, 1, 0)) + return true; - if (::syscall(__NR_futex, &data->sem1, FUTEX_WAIT, 0, &timeout, nullptr, 0) != 0) - if (errno != EAGAIN && errno != EINTR) - return false; + if (::syscall(__NR_futex, &data->sem1, FUTEX_WAIT, 0, &timeout, nullptr, 0) != 0) + if (errno != EAGAIN && errno != EINTR) + return false; + } } -} + #endif -// ----------------------------------------------------------------------------------------------------------- + jack_native_thread_t fProcessThread; + bool fIsProcessing, fIsRunning; -class DesktopAudioDriver : public JackAudioDriver -{ - private: - SharedMemoryData* fShmData; - int fShmFd; - jack_native_thread_t fProcessThread; - - bool fIsProcessing, fIsRunning; - - static void* on_process(void* const arg) + static void* on_process(void* const arg) + { + static_cast(arg)->_process(); + return nullptr; + } + + void _process() + { + if (set_threaded_log_function()) { - static_cast(arg)->_process(); - return nullptr; } - void _process() + while (fIsProcessing && fIsRunning) { - if (set_threaded_log_function()) - { - } + if (! wait()) + continue; + + CycleTakeBeginTime(); - while (fIsProcessing && fIsRunning) - { - if (! shm_sem_rt_wait(fShmData)) - continue; + if (Process() != 0) + fIsProcessing = false; - CycleTakeBeginTime(); + post(); + } + } + +public: + + DesktopAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) + : JackAudioDriver(name, alias, engine, table), + fShmData(nullptr), + #if defined(__APPLE__) + #elif defined(_WIN32) + #else + fShmFd(-1), + #endif + fIsProcessing(false), + fIsRunning(false) + { + printf("%03d:%s\n", __LINE__, __FUNCTION__); + } - if (Process() != 0) - fIsProcessing = false; + ~DesktopAudioDriver() override + { + printf("%03d:%s\n", __LINE__, __FUNCTION__); + } - shm_sem_rt_post(fShmData); - } + int Open(jack_nframes_t buffer_size, + jack_nframes_t samplerate, + bool capturing, + bool playing, + int chan_in, + int chan_out, + bool monitor, + const char* capture_driver_name, + const char* playback_driver_name, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency) override + { + printf("%03d:%s\n", __LINE__, __FUNCTION__); + if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, chan_in, chan_out, monitor, + capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) { + return -1; } - public: + #if defined(__APPLE__) + #elif defined(_WIN32) + #else + fShmFd = shm_open("/mod-desktop-test1", O_RDWR, 0); + if (fShmFd < 0) + { + Close(); + jack_error("Can't open default MOD Desktop driver 1"); + return -1; + } - DesktopAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) - : JackAudioDriver(name, alias, engine, table), - fShmData(nullptr), - fShmFd(-1), - fIsProcessing(false), - fIsRunning(false) + void* const ptr = ::mmap(nullptr, kDataSize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fShmFd, 0); + if (ptr == nullptr || ptr == MAP_FAILED) { - printf("%03d:%s\n", __LINE__, __FUNCTION__); + Close(); + jack_error("Can't open default MOD Desktop driver 2"); + return -1; } - ~DesktopAudioDriver() override + fShmData = static_cast(ptr); + #endif + + if (fShmData->magic != 1337) { - printf("%03d:%s\n", __LINE__, __FUNCTION__); + Close(); + jack_error("Can't open default MOD Desktop driver 3"); + return -1; } - int Open(jack_nframes_t buffer_size, - jack_nframes_t samplerate, - bool capturing, - bool playing, - int chan_in, - int chan_out, - bool monitor, - const char* capture_driver_name, - const char* playback_driver_name, - jack_nframes_t capture_latency, - jack_nframes_t playback_latency) override + return 0; + } + + int Close() override + { + printf("%03d:%s\n", __LINE__, __FUNCTION__); + JackAudioDriver::Close(); + + #if defined(__APPLE__) + #elif defined(_WIN32) + #else + if (fShmData != nullptr) { - printf("%03d:%s\n", __LINE__, __FUNCTION__); - if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, chan_in, chan_out, monitor, - capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) { - return -1; - } - - fShmFd = shm_open("/mod-desktop-test1", O_RDWR, 0); - if (fShmFd < 0) - { - Close(); - jack_error("Can't open default MOD Desktop driver 1"); - return -1; - } - - void* const ptr = ::mmap(nullptr, kSharedMemoryDataSize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fShmFd, 0); - if (ptr == nullptr || ptr == MAP_FAILED) - { - Close(); - jack_error("Can't open default MOD Desktop driver 2"); - return -1; - } - - fShmData = static_cast(ptr); - if (fShmData->magic != 1337) - { - Close(); - jack_error("Can't open default MOD Desktop driver 3"); - return -1; - } - - return 0; + ::munmap(fShmData, kDataSize); + fShmData = nullptr; } - int Close() override + if (fShmFd >= 0) { - printf("%03d:%s\n", __LINE__, __FUNCTION__); - JackAudioDriver::Close(); - - if (fShmData != nullptr) - { - ::munmap(fShmData, kSharedMemoryDataSize); - fShmData = nullptr; - } - - if (fShmFd >= 0) - { - close(fShmFd); - fShmFd = -1; - } - - return 0; + close(fShmFd); + fShmFd = -1; } + #endif + + return 0; + } // int Attach() override // { // } - int Start() override - { - printf("%03d:%s\n", __LINE__, __FUNCTION__); - if (JackAudioDriver::Start() != 0) - return -1; - - fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000; - fEngineControl->fComputation = JackTools::ComputationMicroSec(fEngineControl->fBufferSize) * 1000; - fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000; + int Start() override + { + printf("%03d:%s\n", __LINE__, __FUNCTION__); + if (JackAudioDriver::Start() != 0) + return -1; + + #ifdef __APPLE__ + fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000; + fEngineControl->fComputation = JackTools::ComputationMicroSec(fEngineControl->fBufferSize) * 1000; + fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000; + #endif + + fIsProcessing = fIsRunning = true; + return JackPosixThread::StartImp(&fProcessThread, 0, 0, on_process, this); + } - fIsProcessing = fIsRunning = true; - return JackPosixThread::StartImp(&fProcessThread, 0, 0, on_process, this); - } + int Stop() override + { + printf("%03d:%s\n", __LINE__, __FUNCTION__); + fIsProcessing = false; - int Stop() override + if (fIsRunning) { - printf("%03d:%s\n", __LINE__, __FUNCTION__); - fIsProcessing = false; - - if (fIsRunning) - { - fIsRunning = false; - JackPosixThread::StopImp(fProcessThread); - } - - return JackAudioDriver::Stop(); + fIsRunning = false; + JackPosixThread::StopImp(fProcessThread); } - int Read() override - { - memcpy(GetInputBuffer(0), fShmData->audio, sizeof(float) * 128); - memcpy(GetInputBuffer(1), fShmData->audio + 128, sizeof(float) * 128); - return 0; - } + return JackAudioDriver::Stop(); + } - int Write() override - { - memcpy(fShmData->audio, GetOutputBuffer(0), sizeof(float) * 128); - memcpy(fShmData->audio + 128, GetOutputBuffer(1), sizeof(float) * 128); - return 0; - } + int Read() override + { + memcpy(GetInputBuffer(0), fShmData->audio, sizeof(float) * 128); + memcpy(GetInputBuffer(1), fShmData->audio + 128, sizeof(float) * 128); + return 0; + } - bool IsFixedBufferSize() override - { - printf("%03d:%s\n", __LINE__, __FUNCTION__); - return true; - } + int Write() override + { + memcpy(fShmData->audio, GetOutputBuffer(0), sizeof(float) * 128); + memcpy(fShmData->audio + 128, GetOutputBuffer(1), sizeof(float) * 128); + return 0; + } + + bool IsFixedBufferSize() override + { + printf("%03d:%s\n", __LINE__, __FUNCTION__); + return true; + } }; } // end of namespace diff --git a/src/plugin/DesktopPlugin.cpp b/src/plugin/DesktopPlugin.cpp index 0cdfb8c..d94b2ae 100644 --- a/src/plugin/DesktopPlugin.cpp +++ b/src/plugin/DesktopPlugin.cpp @@ -3,293 +3,27 @@ #include "DistrhoPlugin.hpp" -#include "extra/Sleep.hpp" +#include "Time.hpp" -#include -#include - -#include -#include -#include -#include -#include -#include -#include +#include "ChildProcess.hpp" +#include "SharedMemory.hpp" START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------------------------------------------- -/* - * Get a monotonically-increasing time in milliseconds. - */ -static inline -uint32_t d_gettime_ms() noexcept -{ - #if defined(DISTRHO_OS_MAC) - static const time_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000; - return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000) - s; - #elif defined(DISTRHO_OS_WINDOWS) - return static_cast(timeGetTime()); - #else - static struct { - timespec ts; - int r; - uint32_t ms; - } s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast(s.ts.tv_sec * 1000 + - s.ts.tv_nsec / 1000000) }; - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000) - s.ms; - #endif -} - -// ----------------------------------------------------------------------------------------------------------- - -struct SharedMemoryData { - uint32_t magic; - int32_t sem1; - int32_t sem2; - int32_t padding1; - // uint8_t sem[32]; - uint16_t midiEventCount; - uint16_t midiFrames[511]; - uint8_t midiData[511 * 4]; - uint8_t padding2[4]; - float audio[]; -}; - -const size_t kSharedMemoryDataSize = sizeof(SharedMemoryData) + sizeof(float) * 128 * 2; - -static inline -void shm_sem_rt_post(SharedMemoryData* const data) -{ - const bool unlocked = __sync_bool_compare_and_swap(&data->sem1, 0, 1); - DISTRHO_SAFE_ASSERT_RETURN(unlocked,); - ::syscall(__NR_futex, &data->sem1, FUTEX_WAKE, 1, nullptr, nullptr, 0); -} - -static inline -bool shm_sem_rt_wait(SharedMemoryData* const data) -{ - const timespec timeout = { 1, 0 }; - - for (;;) - { - if (__sync_bool_compare_and_swap(&data->sem2, 1, 0)) - return true; - - if (::syscall(__NR_futex, &data->sem2, FUTEX_WAIT, 0, &timeout, nullptr, 0) != 0) - if (errno != EAGAIN && errno != EINTR) - return false; - } -} - -class SharedMemory { - SharedMemoryData* data = nullptr; - int fd = -1; - -public: - SharedMemory() - { - } - - ~SharedMemory() - { - deinit(); - } - - bool init() - { - fd = shm_open("/mod-desktop-test1", O_CREAT|O_EXCL|O_RDWR, 0600); - DISTRHO_SAFE_ASSERT_RETURN(fd >= 0, false); - - { - const int ret = ::ftruncate(fd, static_cast(kSharedMemoryDataSize)); - DISTRHO_SAFE_ASSERT_RETURN(ret == 0, false); - } - - { - void* const ptr = ::mmap(nullptr, kSharedMemoryDataSize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fd, 0); - DISTRHO_SAFE_ASSERT_RETURN(ptr != nullptr, false); - DISTRHO_SAFE_ASSERT_RETURN(ptr != MAP_FAILED, false); - - data = static_cast(ptr); - } - - std::memset(data, 0, kSharedMemoryDataSize); - data->magic = 1337; - - return true; - } - - void deinit() - { - if (data != nullptr) - { - ::munmap(data, kSharedMemoryDataSize); - data = nullptr; - } - - if (fd >= 0) - { - close(fd); - shm_unlink("/mod-desktop-test1"); - fd = -1; - } - } - - void getAudioData(float* audio[2]) - { - DISTRHO_SAFE_ASSERT_RETURN(data != nullptr,); - - audio[0] = data->audio; - audio[1] = data->audio + 128; - } - - void reset() - { - if (data == nullptr) - return; - - data->midiEventCount = 0; - std::memset(data->audio, 0, sizeof(float) * 128 * 2); - } - - bool process(float** output, const uint32_t outputOffset) - { - // unlock RT waiter - shm_sem_rt_post(data); - - // wait for processing - if (! shm_sem_rt_wait(data)) - return false; - - // copy processed buffer - std::memcpy(output[0] + outputOffset, data->audio, sizeof(float) * 128); - std::memcpy(output[1] + outputOffset, data->audio + 128, sizeof(float) * 128); - - return true; - } -}; - -// ----------------------------------------------------------------------------------------------------------- - -class ChildProcess -{ - pid_t pid = 0; - -public: - ChildProcess() - { - } - - ~ChildProcess() - { - if (pid != 0) - stop(); - } - - bool start(const char* const args[]) - { - const pid_t ret = pid = vfork(); - - switch (ret) - { - // child process - case 0: - execvp(args[0], const_cast(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() - { - DISTRHO_SAFE_ASSERT_RETURN(pid != 0,); - - const uint32_t timeout = d_gettime_ms() + 2000; - const pid_t opid = pid; - pid_t ret; - bool sendTerminate = true; - pid = 0; - - for (;;) - { - 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; - } - } -}; - class DesktopPlugin : public Plugin { ChildProcess jackd; ChildProcess mod_ui; SharedMemory shm; bool processing = false; - float fParameters[24] = {}; - float* fInBuffers[2] = {}; - float* fOutBuffers[2] = {}; - uint32_t fNumTempInFrames = 0; - uint32_t fNumTempOutFrames = 0; - bool fFirstTimeProcessing = true; + bool firstTimeProcessing = true; + float parameters[24] = {}; + float* shmBuffers[2] = {}; + float* tmpBuffers[2] = {}; + uint32_t numFramesInShmBuffer = 0; + uint32_t numFramesInTmpBuffer = 0; public: DesktopPlugin() @@ -298,17 +32,6 @@ class DesktopPlugin : public Plugin if (isDummyInstance()) return; - #define P "/home/falktx/Source/MOD/mod-app/build" - - // FIXME - setenv("LD_LIBRARY_PATH", P, 1); - setenv("JACK_DRIVER_DIR", P "/jack", 1); - setenv("MOD_DATA_DIR", P "/data", 1); - setenv("MOD_FACTORY_PEDALBOARDS_DIR", P "/pedalboards", 1); - setenv("MOD_DESKTOP", "1", 1); - setenv("LANG", "en_US.UTF-8", 1); - setenv("LV2_PATH", P "/plugins", 1); - const String sampleRateStr(static_cast(getSampleRate())); const char* const jackd_args[] = { P "/jackd", "-R", "-S", "-n", "mod-desktop", "-C", P "/jack/jack-session.conf", "-d", "desktop", "-r", sampleRateStr.buffer(), nullptr @@ -320,7 +43,7 @@ class DesktopPlugin : public Plugin if (shm.init() && jackd.start(jackd_args) && mod_ui.start(mod_ui_args)) { processing = true; - shm.getAudioData(fInBuffers); + shm.getAudioData(shmBuffers); bufferSizeChanged(getBufferSize()); } } @@ -331,8 +54,8 @@ class DesktopPlugin : public Plugin jackd.stop(); shm.deinit(); - delete[] fOutBuffers[0]; - delete[] fOutBuffers[1]; + delete[] tmpBuffers[0]; + delete[] tmpBuffers[1]; } protected: @@ -435,7 +158,7 @@ class DesktopPlugin : public Plugin */ float getParameterValue(const uint32_t index) const override { - return fParameters[index]; + return parameters[index]; } /** @@ -443,7 +166,7 @@ class DesktopPlugin : public Plugin */ void setParameterValue(const uint32_t index, const float value) override { - fParameters[index] = value; + parameters[index] = value; } /** @@ -460,8 +183,8 @@ class DesktopPlugin : public Plugin { shm.reset(); - fFirstTimeProcessing = true; - fNumTempInFrames = fNumTempOutFrames = 0; + firstTimeProcessing = true; + numFramesInShmBuffer = numFramesInTmpBuffer = 0; } void deactivate() @@ -480,20 +203,20 @@ class DesktopPlugin : public Plugin return; } - uint32_t ti = fNumTempInFrames; - uint32_t to = fNumTempOutFrames; + uint32_t ti = numFramesInShmBuffer; + uint32_t to = numFramesInTmpBuffer; uint32_t framesDone = 0; for (uint32_t i = 0; i < frames; ++i) { - fInBuffers[0][ti] = inputs[0][i]; - fInBuffers[1][ti] = inputs[1][i]; + shmBuffers[0][ti] = inputs[0][i]; + shmBuffers[1][ti] = inputs[1][i]; if (++ti == 128) { ti = 0; - if (! shm.process(fOutBuffers, to)) + if (! shm.process(tmpBuffers, to)) { d_stdout("shm processing failed"); processing = false; @@ -504,27 +227,27 @@ class DesktopPlugin : public Plugin to += 128; - if (fFirstTimeProcessing) + if (firstTimeProcessing) { - fFirstTimeProcessing = false; + firstTimeProcessing = false; std::memset(outputs[0], 0, sizeof(float) * i); std::memset(outputs[1], 0, sizeof(float) * i); } else { const uint32_t framesToCopy = std::min(128u, frames - framesDone); - std::memcpy(outputs[0] + framesDone, fOutBuffers[0], sizeof(float) * framesToCopy); - std::memcpy(outputs[1] + framesDone, fOutBuffers[1], sizeof(float) * framesToCopy); + std::memcpy(outputs[0] + framesDone, tmpBuffers[0], sizeof(float) * framesToCopy); + std::memcpy(outputs[1] + framesDone, tmpBuffers[1], sizeof(float) * framesToCopy); to -= framesToCopy; framesDone += framesToCopy; - std::memmove(fOutBuffers[0], fOutBuffers[0] + framesToCopy, sizeof(float) * to); - std::memmove(fOutBuffers[1], fOutBuffers[1] + framesToCopy, sizeof(float) * to); + std::memmove(tmpBuffers[0], tmpBuffers[0] + framesToCopy, sizeof(float) * to); + std::memmove(tmpBuffers[1], tmpBuffers[1] + framesToCopy, sizeof(float) * to); } } } - if (fFirstTimeProcessing) + if (firstTimeProcessing) { std::memset(outputs[0], 0, sizeof(float) * frames); std::memset(outputs[1], 0, sizeof(float) * frames); @@ -532,26 +255,26 @@ class DesktopPlugin : public Plugin else if (framesDone != frames) { const uint32_t framesToCopy = frames - framesDone; - std::memcpy(outputs[0] + framesDone, fOutBuffers[0], sizeof(float) * framesToCopy); - std::memcpy(outputs[1] + framesDone, fOutBuffers[1], sizeof(float) * framesToCopy); + std::memcpy(outputs[0] + framesDone, tmpBuffers[0], sizeof(float) * framesToCopy); + std::memcpy(outputs[1] + framesDone, tmpBuffers[1], sizeof(float) * framesToCopy); to -= framesToCopy; - std::memmove(fOutBuffers[0], fOutBuffers[0] + framesToCopy, sizeof(float) * to); - std::memmove(fOutBuffers[1], fOutBuffers[1] + framesToCopy, sizeof(float) * to); + std::memmove(tmpBuffers[0], tmpBuffers[0] + framesToCopy, sizeof(float) * to); + std::memmove(tmpBuffers[1], tmpBuffers[1] + framesToCopy, sizeof(float) * to); } - fNumTempInFrames = ti; - fNumTempOutFrames = to; + numFramesInShmBuffer = ti; + numFramesInTmpBuffer = to; } void bufferSizeChanged(const uint32_t bufferSize) override { - delete[] fOutBuffers[0]; - delete[] fOutBuffers[1]; - fOutBuffers[0] = new float[bufferSize + 256]; - fOutBuffers[1] = new float[bufferSize + 256]; - std::memset(fOutBuffers[0], 0, sizeof(float) * (bufferSize + 256)); - std::memset(fOutBuffers[1], 0, sizeof(float) * (bufferSize + 256)); + delete[] tmpBuffers[0]; + delete[] tmpBuffers[1]; + tmpBuffers[0] = new float[bufferSize + 256]; + tmpBuffers[1] = new float[bufferSize + 256]; + std::memset(tmpBuffers[0], 0, sizeof(float) * (bufferSize + 256)); + std::memset(tmpBuffers[1], 0, sizeof(float) * (bufferSize + 256)); } void sampleRateChanged(const double sampleRate) override diff --git a/src/plugin/SharedMemory.hpp b/src/plugin/SharedMemory.hpp new file mode 100644 index 0000000..85780bf --- /dev/null +++ b/src/plugin/SharedMemory.hpp @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: 2023-2024 MOD Audio UG +// SPDX-License-Identifier: AGPL-3.0-or-later + +#pragma once + +#include "DistrhoUtils.hpp" + +#if defined(DISTRHO_OS_MAC) +#elif defined(DISTRHO_OS_WINDOWS) +#else +# include +# include +# include +# include +# include +# include +#endif + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- + +class SharedMemory +{ +public: + SharedMemory() + { + } + + ~SharedMemory() + { + deinit(); + } + + bool init() + { + #if defined(DISTRHO_OS_MAC) + #elif defined(DISTRHO_OS_WINDOWS) + #else + fd = shm_open("/mod-desktop-test1", O_CREAT|O_EXCL|O_RDWR, 0600); + DISTRHO_SAFE_ASSERT_RETURN(fd >= 0, false); + + { + const int ret = ::ftruncate(fd, static_cast(kDataSize)); + DISTRHO_SAFE_ASSERT_RETURN(ret == 0, fail_deinit()); + } + + { + void* const ptr = ::mmap(nullptr, kDataSize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fd, 0); + DISTRHO_SAFE_ASSERT_RETURN(ptr != nullptr, fail_deinit()); + DISTRHO_SAFE_ASSERT_RETURN(ptr != MAP_FAILED, fail_deinit()); + + data = static_cast(ptr); + } + #endif + + std::memset(data, 0, kDataSize); + data->magic = 1337; + + return true; + } + + void deinit() + { + #if defined(DISTRHO_OS_MAC) + #elif defined(DISTRHO_OS_WINDOWS) + #else + if (data != nullptr) + { + ::munmap(data, kDataSize); + data = nullptr; + } + + if (fd >= 0) + { + close(fd); + shm_unlink("/mod-desktop-test1"); + fd = -1; + } + #endif + } + + void getAudioData(float* audio[2]) + { + DISTRHO_SAFE_ASSERT_RETURN(data != nullptr,); + + audio[0] = data->audio; + audio[1] = data->audio + 128; + } + + void reset() + { + if (data == nullptr) + return; + + data->midiEventCount = 0; + std::memset(data->audio, 0, sizeof(float) * 128 * 2); + } + + bool process(float** output, const uint32_t offset) + { + // unlock RT waiter + post(); + + // wait for processing + if (! wait()) + return false; + + // copy processed buffer + std::memcpy(output[0] + offset, data->audio, sizeof(float) * 128); + std::memcpy(output[1] + offset, data->audio + 128, sizeof(float) * 128); + + return true; + } + +private: + struct Data { + uint32_t magic; + int32_t sem1; + int32_t sem2; + int32_t padding1; + // uint8_t sem[32]; + uint16_t midiEventCount; + uint16_t midiFrames[511]; + uint8_t midiData[511 * 4]; + uint8_t padding2[4]; + float audio[]; + }* data = nullptr; + + static constexpr const size_t kDataSize = sizeof(Data) + sizeof(float) * 128 * 2; + + #if defined(DISTRHO_OS_MAC) + void post() + { + } + + bool wait() + { + return false; + } + #elif defined(DISTRHO_OS_WINDOWS) + void post() + { + } + + bool wait() + { + return false; + } + #else + int fd = -1; + + void post() + { + const bool unlocked = __sync_bool_compare_and_swap(&data->sem1, 0, 1); + DISTRHO_SAFE_ASSERT_RETURN(unlocked,); + ::syscall(__NR_futex, &data->sem1, FUTEX_WAKE, 1, nullptr, nullptr, 0); + } + + bool wait() + { + const timespec timeout = { 1, 0 }; + + for (;;) + { + if (__sync_bool_compare_and_swap(&data->sem2, 1, 0)) + return true; + + if (::syscall(__NR_futex, &data->sem2, FUTEX_WAIT, 0, &timeout, nullptr, 0) != 0) + if (errno != EAGAIN && errno != EINTR) + return false; + } + } + #endif + + bool fail_deinit() + { + deinit(); + return false; + } + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SharedMemory) +}; + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO diff --git a/src/plugin/Time.hpp b/src/plugin/Time.hpp new file mode 100644 index 0000000..c1485d0 --- /dev/null +++ b/src/plugin/Time.hpp @@ -0,0 +1,125 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2024 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DISTRHO_TIME_HPP_INCLUDED +#define DISTRHO_TIME_HPP_INCLUDED + +#include "DistrhoUtils.hpp" + +#ifdef DISTRHO_OS_WINDOWS +# include +#else +# include +#endif + +START_NAMESPACE_DISTRHO + +// ----------------------------------------------------------------------------------------------------------- +// d_gettime_* + +/* + * Get a monotonically-increasing time in milliseconds. + */ +static inline +uint32_t d_gettime_ms() noexcept +{ + #if defined(DISTRHO_OS_MAC) + static const time_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000; + return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000) - s; + #elif defined(DISTRHO_OS_WINDOWS) + return static_cast(timeGetTime()); + #else + static struct { + timespec ts; + int r; + uint32_t ms; + } s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast(s.ts.tv_sec * 1000 + + s.ts.tv_nsec / 1000000) }; + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000) - s.ms; + #endif +} + +/* + * Get a monotonically-increasing time in microseconds. + */ +static inline +uint64_t d_gettime_us() noexcept +{ + #if defined(DISTRHO_OS_MAC) + static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000; + return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000) - s; + #elif defined(DISTRHO_OS_WINDOWS) + static struct { + LARGE_INTEGER freq; + LARGE_INTEGER counter; + BOOL r1, r2; + } s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) }; + + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return (counter.QuadPart - s.counter.QuadPart) * 1000000 / s.freq.QuadPart; + #else + static struct { + timespec ts; + int r; + uint64_t us; + } s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast(s.ts.tv_sec * 1000000 + + s.ts.tv_nsec / 1000) }; + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * 1000000 + ts.tv_nsec / 1000) - s.us; + #endif +} + +/* + * Get a monotonically-increasing time in nanoseconds. + */ +static inline +uint64_t d_gettime_ns() noexcept +{ + #if defined(DISTRHO_OS_MAC) + static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); + return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) - s; + #elif defined(DISTRHO_OS_WINDOWS) + static struct { + LARGE_INTEGER freq; + LARGE_INTEGER counter; + BOOL r1, r2; + } s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) }; + + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return (counter.QuadPart - s.counter.QuadPart) * 1000000000ULL / s.freq.QuadPart; + #else + static struct { + timespec ts; + int r; + uint64_t ns; + } s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast(s.ts.tv_sec * 1000000000ULL + + s.ts.tv_nsec) }; + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (ts.tv_sec * 1000000000ULL + ts.tv_nsec) - s.ns; + #endif +} + +// ----------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +#endif // DISTRHO_TIME_HPP_INCLUDED