diff --git a/CMakeLists.txt b/CMakeLists.txt index 9864b62..3bd8712 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 3.16.0) project(pipedal - VERSION 1.4.79 + VERSION 1.4.83 DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" HOMEPAGE_URL "https://rerdavies.github.io/pipedal" ) EXECUTE_PROCESS( COMMAND dpkg --print-architecture COMMAND tr -d '\n' OUTPUT_VARIABLE DEBIAN_ARCHITECTURE ) -set (DISPLAY_VERSION "PiPedal v1.4.79-Beta") +set (DISPLAY_VERSION "PiPedal v1.4.83-Experimental") set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE}) set (CMAKE_INSTALL_PREFIX "/usr/") diff --git a/PiPedalCommon/src/AlsaSequencer.cpp b/PiPedalCommon/src/AlsaSequencer.cpp index 7506e02..4e21ee4 100644 --- a/PiPedalCommon/src/AlsaSequencer.cpp +++ b/PiPedalCommon/src/AlsaSequencer.cpp @@ -259,6 +259,8 @@ namespace pipedal // Open sequencer in input mode int rc; + Lv2Log::debug("Opening ALSA Sequencer"); + rc = snd_seq_open(&seqHandle, "default", SND_SEQ_OPEN_DUPLEX, 0); if (rc < 0) { diff --git a/PiPedalCommon/src/include/restrict.hpp b/PiPedalCommon/src/include/restrict.hpp new file mode 100644 index 0000000..3cf0756 --- /dev/null +++ b/PiPedalCommon/src/include/restrict.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2022 Robin E. R. Davies + * All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#pragma once + + +// define restrict keyword for C++ compilers (which don't yet support it) +#ifndef restrict +#if defined(__GNUC__) || defined(__clang__) +#define restrict __restrict__ +#elif defined(_MSC_VER) +#define restrict __restrict +#endif +#endif \ No newline at end of file diff --git a/README.md b/README.md index 4645e27..a332ae7 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ -Download: v1.4.79 +Download: v1.4.83 Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html). -#### NEW version 1.4.79 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. New Phaser and Graphic Equalizer plugins. +#### NEW version 1.4.83 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. New Phaser and Graphic Equalizer plugins.   diff --git a/docs/Installing.md b/docs/Installing.md index f8935b8..6a66c15 100644 --- a/docs/Installing.md +++ b/docs/Installing.md @@ -13,18 +13,18 @@ page_icon: img/Install4.jpg Download the most recent Debian (.deb) package for your platform: -- [Raspberry Pi OS bookworm (aarch64) v1.4.79](https://github.com/rerdavies/pipedal/releases/download/v1.4.79/pipedal_1.4.79_arm64.deb) -- [Ubuntu 24.x (aarch64) v1.4.79](https://github.com/rerdavies/pipedal/releases/download/v1.4.79/pipedal_1.4.79_arm64.deb) -- [Ubuntu 24.x (amd64) v1.4.79](https://github.com/rerdavies/pipedal/releases/download/v1.4.79/pipedal_1.4.79_amd64.deb) +- [Raspberry Pi OS bookworm (aarch64) v1.4.83](https://github.com/rerdavies/pipedal/releases/download/v1.4.83/pipedal_1.4.83_arm64.deb) +- [Ubuntu 24.x (aarch64) v1.4.83](https://github.com/rerdavies/pipedal/releases/download/v1.4.83/pipedal_1.4.83_arm64.deb) +- [Ubuntu 24.x (amd64) v1.4.83](https://github.com/rerdavies/pipedal/releases/download/v1.4.83/pipedal_1.4.83_amd64.deb) -Version 1.4.79 has been tested on Raspberry Pi OS bookworm, Ubuntu 24.04 (amd64), and Ubuntu 24.10 (aarch64). Download the appropriate package for your platform, and install using the following procedure: +Version 1.4.83 has been tested on Raspberry Pi OS bookworm, Ubuntu 24.04 (amd64), and Ubuntu 24.10 (aarch64). Download the appropriate package for your platform, and install using the following procedure: ``` sudo apt update sudo apt upgrade cd ~/Downloads - sudo apt-get install ./pipedal_1.4.79_arm64.deb + sudo apt-get install ./pipedal_1.4.83_arm64.deb ``` You MUST use `apt-get`. `apt` will not install downloaded packages; and `dpkg -i` will not install dependencies. diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 3d45137..791e5b0 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -1,4 +1,9 @@ # Release Notes +## Pipedal 1.4.79 Experimental +Bug fixes: +- Thread-per-plugin-instance for LV2_WORKER threads (see issue #339) +- Fixes for selection issues when modifying pedalboard structure. + ## Pipedal 1.4.79 Beta The Big Feature: diff --git a/docs/download.md b/docs/download.md index 8e8b412..7cd8397 100644 --- a/docs/download.md +++ b/docs/download.md @@ -4,9 +4,9 @@ Download the most recent Debian (.deb) package for your platform: -- [Raspberry Pi OS bookworm (aarch64) v1.4.79 Beta](https://github.com/rerdavies/pipedal/releases/download/v1.4.79/pipedal_1.4.79_arm64.deb) -- [Ubuntu 24.x (aarch64) v1.4.79 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.4.79/pipedal_1.4.79_arm64.deb) -- [Ubuntu 24.x (amd64) v1.4.79 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.4.79/pipedal_1.4.79_amd64.deb) +- [Raspberry Pi OS bookworm (aarch64) v1.4.83 Beta](https://github.com/rerdavies/pipedal/releases/download/v1.4.83/pipedal_1.4.83_arm64.deb) +- [Ubuntu 24.x (aarch64) v1.4.83 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.4.83/pipedal_1.4.83_arm64.deb) +- [Ubuntu 24.x (amd64) v1.4.83 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.4.83/pipedal_1.4.83_amd64.deb) Install the package by running @@ -14,7 +14,7 @@ Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install ./pipedal_1.4.79_arm64.deb + sudo apt-get install ./pipedal_1.4.83_arm64.deb ``` You MUST use `apt-get` to install the package. `apt install` will NOT install the package correctly. The message about missing permissions given by `apt-get` is expected, and can be safely ignored. diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index 195cec6..1f833be 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -245,6 +245,8 @@ namespace pipedal class AlsaDriverImpl : public AudioDriver { private: + std::recursive_mutex restartMutex; + pipedal::CpuUse cpuUse; #ifdef ALSADRIVER_CONFIG_DBG @@ -378,16 +380,21 @@ namespace pipedal } private: - void AlsaCleanup() + void AlsaCloseAudio() { + std::lock_guard lock{restartMutex}; if (captureHandle) { + Lv2Log::debug("ALSA capture handle closed."); + snd_pcm_drain(captureHandle); snd_pcm_close(captureHandle); captureHandle = nullptr; } if (playbackHandle) { + Lv2Log::debug("ALSA playback handle closed."); + snd_pcm_drain(playbackHandle); snd_pcm_close(playbackHandle); playbackHandle = nullptr; } @@ -411,7 +418,11 @@ namespace pipedal snd_pcm_sw_params_free(playbackSwParams); playbackSwParams = nullptr; } - this->alsaSequencer = nullptr; + + } + void AlsaCleanup() + { + AlsaCloseAudio(); } std::string discover_alsa_using_apps() @@ -1085,6 +1096,34 @@ namespace pipedal } } + void RestartAlsa() + { + std::lock_guard lock{restartMutex}; + Lv2Log::info("Restarting ALSA devices."); + + try { + AlsaCloseAudio(); + } catch (const std::exception &e) { + Lv2Log::error(SS("Error cleaning up ALSA: " << e.what())); + throw std::runtime_error("Unable to restart the audio stream."); + } + try { + OpenAudio(this->jackServerSettings, this->channelSelection); + validate_capture_handle(); + FillOutputBuffer(); + audioRunning = true; + } catch (const std::exception &e) { + Lv2Log::error(SS("Error opening ALSA: " << e.what())); + throw std::runtime_error("Unable to restart the audio stream."); + } + int err; + if ((err = snd_pcm_start(captureHandle)) < 0) + { + throw PiPedalStateException("Unable to restart ALSA capture."); + } + + } + void PrepareCaptureFunctions(snd_pcm_format_t captureFormat) { this->captureFormat = captureFormat; @@ -1221,6 +1260,8 @@ namespace pipedal void OpenAudio(const JackServerSettings &jackServerSettings, const JackChannelSelection &channelSelection) { + std::lock_guard lock{ restartMutex }; + int err; alsa_device_name = jackServerSettings.GetAlsaInputDevice(); @@ -1389,18 +1430,25 @@ namespace pipedal void recover_from_output_underrun(snd_pcm_t *capture_handle, snd_pcm_t *playback_handle, int err) { validate_capture_handle(); - if (err == -EPIPE) - { - err = snd_pcm_prepare(playback_handle); - if (err < 0) + try { + + if (err == -EPIPE) { - throw PiPedalStateException(SS("Can't recover from ALSA output underrun. (" << snd_strerror(err) << ")")); + err = snd_pcm_prepare(playback_handle); + if (err < 0) + { + throw PiPedalStateException(SS("Can't recover from ALSA output underrun. (" << snd_strerror(err) << ")")); + } + FillOutputBuffer(); } - FillOutputBuffer(); - } - else - { - throw PiPedalStateException(SS("Can't recover from ALSA output error. (" << snd_strerror(err) << ")")); + else + { + throw PiPedalStateException(SS("Can't recover from ALSA output error. (" << snd_strerror(err) << ")")); + } + } catch (const std::exception &e) { + Lv2Log::info(SS("Soft audio restart failed. " << e.what())); + RestartAlsa(); + audioRunning = true; } validate_capture_handle(); } @@ -1408,72 +1456,79 @@ namespace pipedal { validate_capture_handle(); - if (err == -EPIPE) - { + try { + if (err == -EPIPE) + { - // Unlink the streams before recovery - snd_pcm_unlink(capture_handle); + // Unlink the streams before recovery + snd_pcm_unlink(capture_handle); - err = snd_pcm_drop(capture_handle); - if (err < 0) - { - throw PiPedalStateException(SS("Can't recover from ALSA underrun. (" << snd_strerror(err) << ")")); - } - err = snd_pcm_drop(playback_handle); - if (err < 0) - { - throw PiPedalStateException(SS("Can't recover from ALSA underrun. (" << snd_strerror(err) << ")")); - } - - // Prepare both streams - if ((err = snd_pcm_prepare(playback_handle)) < 0) - { - throw std::runtime_error(SS("Cannot prepare playback stream: " << snd_strerror(err))); - } - if ((err = snd_pcm_prepare(capture_handle)) < 0) - { - throw std::runtime_error(SS("Cannot prepare capture stream: " << snd_strerror(err))); - } - - // Fill the playback buffer with silence - FillOutputBuffer(); - - // Resynchronize the streams - if ((err = snd_pcm_link(capture_handle, playback_handle)) < 0) - { - throw std::runtime_error(SS("Cannot relink streams: " << snd_strerror(err))); - } - - // Start the streams - if ((err = snd_pcm_start(capture_handle)) < 0) - { - throw std::runtime_error(SS("Cannot restart capture stream: " << snd_strerror(err))); - } - validate_capture_handle(); - } - else if (err == ESTRPIPE) - { - audioRunning = false; - validate_capture_handle(); - - while ((err = snd_pcm_resume(capture_handle)) == -EAGAIN) - { - sleep(1); - } - if (err < 0) - { - err = snd_pcm_prepare(capture_handle); + err = snd_pcm_drop(capture_handle); if (err < 0) { - throw PiPedalStateException(SS("Can't recover from ALSA suspend. (" << snd_strerror(err) << ")")); + throw PiPedalStateException(SS("Can't recover from ALSA underrun. (" << snd_strerror(err) << ")")); } + err = snd_pcm_drop(playback_handle); + if (err < 0) + { + throw PiPedalStateException(SS("Can't recover from ALSA underrun. (" << snd_strerror(err) << ")")); + } + + // Prepare both streams + if ((err = snd_pcm_prepare(playback_handle)) < 0) + { + throw std::runtime_error(SS("Cannot prepare playback stream: " << snd_strerror(err))); + } + if ((err = snd_pcm_prepare(capture_handle)) < 0) + { + throw std::runtime_error(SS("Cannot prepare capture stream: " << snd_strerror(err))); + } + + // Fill the playback buffer with silence + FillOutputBuffer(); + + // Resynchronize the streams + if ((err = snd_pcm_link(capture_handle, playback_handle)) < 0) + { + throw std::runtime_error(SS("Cannot relink streams: " << snd_strerror(err))); + } + + // Start the streams + if ((err = snd_pcm_start(capture_handle)) < 0) + { + throw std::runtime_error(SS("Cannot restart capture stream: " << snd_strerror(err))); + } + validate_capture_handle(); } + else if (err == ESTRPIPE) + { + audioRunning = false; + validate_capture_handle(); + + while ((err = snd_pcm_resume(capture_handle)) == -EAGAIN) + { + sleep(1); + } + if (err < 0) + { + err = snd_pcm_prepare(capture_handle); + if (err < 0) + { + throw PiPedalStateException(SS("Can't recover from ALSA suspend. (" << snd_strerror(err) << ")")); + } + } + audioRunning = true; + validate_capture_handle(); + } + else + { + throw PiPedalStateException(SS("Can't recover from ALSA input error. (" << snd_strerror(err) << ")")); + } + } catch (const std::exception &e) { + Lv2Log::info(SS("Soft audio restart failed. " << e.what())); + RestartAlsa(); audioRunning = true; - validate_capture_handle(); - } - else - { - throw std::runtime_error(SS("Can't restart audio: " << snd_strerror(err))); + } } @@ -1526,6 +1581,11 @@ namespace pipedal AlsaMidiMessage message; midiEventCount = 0; + auto alsaSequener = this->alsaSequencer; // take an addref + if (!alsaSequener) + { + return; + } while (alsaSequencer->ReadMessage(message, 0)) { size_t messageSize = message.size; @@ -1675,11 +1735,11 @@ namespace pipedal Lv2Log::error(e.what()); Lv2Log::error("ALSA audio thread terminated abnormally."); } - this->driverHost->OnAlsaDriverStopped(); // if we terminated abnormally, pump messages until we have been terminated. if (!terminateAudio()) { + this->driverHost->OnAlsaDriverStopped(); // zero out input buffers. for (size_t i = 0; i < this->captureBuffers.size(); ++i) { @@ -1848,6 +1908,8 @@ namespace pipedal Deactivate(); AlsaCleanup(); DeleteBuffers(); + this->alsaSequencer = nullptr; + std::atomic_thread_fence(std::memory_order::release); } @@ -1940,7 +2002,7 @@ namespace pipedal try { int err; - for (int retry = 0; retry < 2; ++retry) + for (int retry = 0; retry < 4; ++retry) { err = snd_pcm_open(&playbackHandle, alsaDeviceName.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (err < 0) // field report of a device that is present, but won't immediately open. @@ -2202,6 +2264,7 @@ namespace pipedal #endif } + void FreeAlsaGlobals() { snd_config_update_free_global(); // to get a clean Valgrind report. diff --git a/src/AudioHost.cpp b/src/AudioHost.cpp index 3cdb7cc..79afb3c 100644 --- a/src/AudioHost.cpp +++ b/src/AudioHost.cpp @@ -34,6 +34,7 @@ #include "PluginHost.hpp" #include "PatchPropertyWriter.hpp" #include "CpuTemperatureMonitor.hpp" +#include "restrict.hpp" using namespace pipedal; @@ -618,7 +619,7 @@ private: { for (size_t i = 0; i < audioDriver->OutputBufferCount(); ++i) { - float *out = (float *)audioDriver->GetOutputBuffer(i); + float * out = (float *)audioDriver->GetOutputBuffer(i); if (out) { ZeroBuffer(out, nframes); @@ -1141,7 +1142,7 @@ private: { try { - float *in, *out; + float * restrict in , * restrict out; Lv2Pedalboard *pedalboard = nullptr; pedalboard = this->realtimeActivePedalboard; @@ -1724,6 +1725,7 @@ public: { Close(); active = false; + isOpen = false; throw; } } diff --git a/src/AvahiService.cpp b/src/AvahiService.cpp index a3feb36..c88487d 100644 --- a/src/AvahiService.cpp +++ b/src/AvahiService.cpp @@ -40,6 +40,40 @@ using namespace pipedal; +int avahiPollLockCount = 0; +static std::mutex avahiLockMutex; +class AvahiPollLock { +public: + AvahiPollLock() = delete; + AvahiPollLock(AvahiThreadedPoll*threadedPoll) + : threadedPoll(threadedPoll) { + std::lock_guard lock(avahiLockMutex); + if (!threadedPoll) { + throw std::runtime_error("AvahiPollLock: threadedPoll is null."); + } + if (++avahiPollLockCount > 1) { + throw std::runtime_error("AvahiPollLock: nested locks are not allowed."); + } + avahi_threaded_poll_lock(threadedPoll); + } + void release() { + std::lock_guard lock(avahiLockMutex); + if (threadedPoll) + { + if (avahiPollLockCount <= 0) { + throw std::runtime_error("AvahiPollLock: release called without a lock."); + } + --avahiPollLockCount; + avahi_threaded_poll_unlock(threadedPoll); + threadedPoll = nullptr; + } + } + ~AvahiPollLock() { + release(); + } +private: + AvahiThreadedPoll *threadedPoll; +}; void AvahiService::Announce( int portNumber, const std::string &name, @@ -75,7 +109,7 @@ void AvahiService::Announce( else { // already started, so we have to use poll_lock instead. - avahi_threaded_poll_lock(threadedPoll); + AvahiPollLock lock(threadedPoll); // all state that we have to protect with the lock now that the avahi serv3ce is running. this->portNumber = portNumber; @@ -104,7 +138,7 @@ void AvahiService::Announce( Lv2Log::error("Failed to update mDNS service because of a synch problem."); } } - avahi_threaded_poll_unlock(threadedPoll); + lock.release(); if (wait) { Wait(); @@ -118,30 +152,31 @@ void AvahiService::Unannounce(bool wait) return; if (this->threadedPoll) { - avahi_threaded_poll_lock(threadedPoll); - if (started) { - if (this->createPending) + AvahiPollLock lock(threadedPoll); + if (started) { - // if service is starting up, and we haven't yet made our first announcement, - // just signal that we don't want to announc. - this->makeAnnouncement = false; - } - else - { - this->makeAnnouncement = false; - // we have previously made a successful announcement. Retract it. - if (group) + if (this->createPending) { - int rc = avahi_entry_group_reset(group); - if (rc < 0) + // if service is starting up, and we haven't yet made our first announcement, + // just signal that we don't want to announc. + this->makeAnnouncement = false; + } + else + { + this->makeAnnouncement = false; + // we have previously made a successful announcement. Retract it. + if (group) { - Lv2Log::error("Avahi: failed to un-announce."); + int rc = avahi_entry_group_reset(group); + if (rc < 0) + { + Lv2Log::error("Avahi: failed to un-announce."); + } } } } } - avahi_threaded_poll_unlock(threadedPoll); if (wait) { WaitForUnannounce(); @@ -411,6 +446,7 @@ void AvahiService::Start() if (!client) { + AvahiPollLock lock(threadedPoll); /* Allocate a new client */ client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), AvahiClientFlags::AVAHI_CLIENT_NO_FAIL, client_callback, (void *)this, &error); /* Check wether creating the client object succeeded */ @@ -442,20 +478,22 @@ void AvahiService::Stop() if (threadedPoll) { - avahi_threaded_poll_lock(threadedPoll); - if (group) { - avahi_entry_group_free(group); - group = nullptr; + AvahiPollLock lock(threadedPoll); + if (group) + { + avahi_entry_group_free(group); + group = nullptr; + } } - avahi_threaded_poll_unlock(threadedPoll); - avahi_threaded_poll_lock(threadedPoll); - if (client) { - avahi_client_free(client); - client = nullptr; + AvahiPollLock lock(threadedPoll); + if (client) + { + avahi_client_free(client); + client = nullptr; + } } - avahi_threaded_poll_unlock(threadedPoll); avahi_threaded_poll_stop(threadedPoll); avahi_threaded_poll_free(threadedPoll); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 95faca4..ec8462f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -59,8 +59,8 @@ find_package(sdbus-c++ REQUIRED) -find_package(ICU REQUIRED COMPONENTS uc i18n ) -message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}") +find_package(ICU REQUIRED COMPONENTS uc i18n) +message(STATUS "ICU_LIBRARIES: ${ICU_LIBRARIES}") if(DEFINED ENV{GITHUB_ACTIONS}) @@ -72,19 +72,19 @@ endif() ################################################################# # ENABLE/DISABLE VST3 Support. # Disabled, pending approval of Steinberg VST3 License. -# Do not enable unless you have non-GPL3 access to the Steinberg +# Do not enable unless you have non-GPL3 access to the Steinberg # SDK. # -# Plus, there don't seem to be any VST3 plugins for linux, as it -# turns out. :-/ Status: not completely implemented due to lack +# Plus, there don't seem to be any VST3 plugins for linux, as it +# turns out. :-/ Status: not completely implemented due to lack # of test targets. Deprecated, and non-functional. ################################################################# set (ENABLE_VST3 0) -if (ENABLE_VST3) - set (VST3PATH "../../vst3sdk") +if (ENABLE_VST3) + set (VST3PATH "../../vst3sdk") message(STATUS " VST3 Support Enabled") set (VST3_INCLUDES "${VST3PATH}") set (VST3_LIBRARIES vst3_lib dl) @@ -129,11 +129,11 @@ pkg_check_modules(ZIP "lilv-0") set (LV2DEV_INCLUDE_DIRS ) # use lvt headers fro /usr/include -# Use submodules/websocketpp heders taken from websocketpp/develop branch, because debian-provided +# Use submodules/websocketpp heders taken from websocketpp/develop branch, because debian-provided # version of websocketpp cannot compile under GCC 12.x. -set (WEBSOCKETPP_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/modules/websocketpp) -message(STATUS "WEBSOCKETPP_INCLUDE_DIRS ${WEBSOCKETPP_INCLUDE_DIRS}" ) +set (WEBSOCKETPP_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/modules/websocketpp) +message(STATUS "WEBSOCKETPP_INCLUDE_DIRS ${WEBSOCKETPP_INCLUDE_DIRS}") # pkg_check_modules(JACK "jack") # if(!JACK_FOUND) @@ -151,7 +151,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) if (!ENABLE_VST3) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wno-psabi -DARCHITECTURE=${CPACK_SYSTEM_NAME}") else() - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar -Wno-psabi") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar -Wno-psabi") endif() EXECUTE_PROCESS( COMMAND dpkg --print-architecture COMMAND tr -d '\n' OUTPUT_VARIABLE DEBIAN_ARCHITECTURE ) @@ -163,22 +163,22 @@ if (CMAKE_BUILD_TYPE MATCHES Debug) message(STATUS "Debug build") # Must not -D_GLIBCXX_DEBUG, since it conflict with SQLiteCpp.lol - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -DDEBUG " ) - if (USE_SANITIZE) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -static-libasan " ) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -DDEBUG " ) + if (USE_SANITIZE) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -static-libasan " ) endif() elseif(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) message(STATUS "RelWithgDebInfo build") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -DNDEBUG" ) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -ffast-math -DNDEBUG" ) else() message(STATUS "Release build") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG" ) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -ffast-math -DNDEBUG" ) endif() if (ENABLE_BACKTRACE) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") if (${DEBIAN_ARCHITECTURE} MATCHES arm64) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -funwind-tables") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -funwind-tables") endif() endif() @@ -189,11 +189,11 @@ endif() # message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") # set(CMAKE_ENABLE_EXPORTS 1) -message (STATUS "Cxx flags: ${CMAKE_CXX_FLAGS}" ) +message (STATUS "Cxx flags: ${CMAKE_CXX_FLAGS}") add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY -DBOOST_BIND_GLOBAL_PLACEHOLDERS -DONBOARDING) - + if (VST3PATH) set (VST3_SOURCES vst3/Vst3Effect.hpp Vst3Effect.cpp @@ -233,8 +233,8 @@ set (PIPEDAL_SOURCES WebServerConfig.cpp WebServerConfig.hpp Locale.hpp Locale.cpp ZipFile.cpp ZipFile.hpp - TemporaryFile.cpp TemporaryFile.hpp - FilePropertyDirectoryTree.cpp FilePropertyDirectoryTree.hpp + TemporaryFile.cpp TemporaryFile.hpp + FilePropertyDirectoryTree.cpp FilePropertyDirectoryTree.hpp FileEntry.cpp FileEntry.hpp atom_object.hpp atom_object.cpp lv2ext/pipedal.lv2/ext/fileBrowser.h @@ -243,7 +243,7 @@ set (PIPEDAL_SOURCES DbDezipper.hpp DbDezipper.cpp WebServerLog.hpp WifiChannelSelectors.cpp WifiChannelSelectors.hpp - + PiPedalUI.hpp PiPedalUI.cpp MapPathFeature.hpp @@ -319,15 +319,15 @@ set (PIPEDAL_SOURCES configure_file(config.hpp.in config.hpp) include_directories( - ${pipedald_SOURCE_DIR}/. + ${pipedald_SOURCE_DIR}/. ../build/src - ) + ) -set (PIPEDAL_INCLUDES +set (PIPEDAL_INCLUDES ${LV2DEV_INCLUDE_DIRS} - ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} + ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${VST3_INCLUDES} - ${WEBSOCKETPP_INCLUDE_DIRS} + ${WEBSOCKETPP_INCLUDE_DIRS} ${PipeWire_INCLUDE_DIRS} . ) @@ -337,7 +337,7 @@ set(PIPEDAL_LIBS libpipedald zip PiPedalCommon pthread atomic stdc++fs asound avahi-common avahi-client systemd ${VST3_LIBRARIES} - ${LILV_0_LIBRARIES} + ${LILV_0_LIBRARIES} asound # ${JACK_LIBRARIES} - pending delete for JACK support. ) @@ -345,16 +345,15 @@ set(PIPEDAL_LIBS libpipedald zip ########################## - + add_library(libpipedald STATIC ${PIPEDAL_SOURCES}) target_compile_definitions(libpipedald PUBLIC "_REENTRANT") -target_include_directories(libpipedald PUBLIC ${PIPEDAL_INCLUDES} - ) +target_include_directories(libpipedald PUBLIC ${PIPEDAL_INCLUDES}) -target_link_libraries(libpipedald - PUBLIC +target_link_libraries(libpipedald + PUBLIC PiPedalCommon SQLiteCpp ${PipeWire_LIBRARIES} @@ -382,26 +381,23 @@ target_link_libraries(pipedal_kconfig PRIVATE PiPedalCommon asound systemd -) +) ################################# -add_executable(pipedald +add_executable(pipedald asan_options.cpp # disable leak checking for sanitize=address. - main.cpp + main.cpp ) target_include_directories(pipedald PRIVATE ${PIPEDAL_INCLUDES}) target_compile_definitions(pipedald PRIVATE "ENABLE_BACKTRACE=${ENABLE_BACKTRACE}") -target_link_libraries(pipedald PRIVATE PiPedalCommon - - ${PIPEDAL_LIBS} - ) +target_link_libraries(pipedald PRIVATE PiPedalCommon ${PIPEDAL_LIBS}) ################################# -add_executable(hotspotManagerTest +add_executable(hotspotManagerTest hotspotManagerTestMain.cpp HotspotManager.cpp HotspotManager.hpp) @@ -416,7 +412,7 @@ add_executable(AuxInTest AuxInTest.cpp ) -add_executable(pipedaltest +add_executable(pipedaltest testMain.cpp ModGuiTest.cpp @@ -427,9 +423,9 @@ add_executable(pipedaltest ModFileTypesTest.cpp jsonTest.cpp UpdaterTest.cpp - + utilTest.cpp - + AlsaDriverTest.cpp AvahiServiceTest.cpp WifiChannelsTest.cpp @@ -448,29 +444,23 @@ add_executable(pipedaltest MemDebug.hpp ) target_link_libraries(pipedaltest PRIVATE ${PIPEDAL_LIBS} ${ICU_LIBRARIES}) -target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES} -) +target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES}) set_target_properties(pipedaltest PROPERTIES EXCLUDE_FROM_ALL ${PIPEDAL_EXCLUDE_TESTS}) if (NOT GITHUB_ACTIONS) # Google perftools are not available on Github action servers. - - - add_executable(pipedalProfilePlugin profilePluginMain.cpp ArmPerformanceCounters.hpp ) - target_link_libraries(pipedalProfilePlugin PRIVATE profiler ${PIPEDAL_LIBS}) + target_link_libraries(pipedalProfilePlugin PRIVATE profiler ${PIPEDAL_LIBS}) target_include_directories(pipedalProfilePlugin PRIVATE ${PIPEDAL_INCLUDES} ) if (${DEBIAN_ARCHITECTURE} MATCHES arm64) target_compile_definitions(pipedalProfilePlugin PRIVATE "PIPEDAL_AARCH64") - endif() - - - + endif() endif() + add_executable(jsonTest testMain.cpp jsonTest.cpp @@ -484,8 +474,7 @@ add_executable(jsonTest PromiseTest.cpp ) target_link_libraries(jsonTest PRIVATE PiPedalCommon) -target_include_directories(jsonTest PRIVATE ${PIPEDAL_INCLUDES} - ) +target_include_directories(jsonTest PRIVATE ${PIPEDAL_INCLUDES}) set_target_properties(jsonTest PROPERTIES EXCLUDE_FROM_ALL ${PIPEDAL_EXCLUDE_TESTS}) @@ -498,7 +487,7 @@ add_test(NAME jsonTest COMMAND jsonTest) -include_directories( ${pipedald_SOURCE_DIR}/. ../build/src) +include_directories( ${pipedald_SOURCE_DIR}/. ../build/src) if(${USE_PCH}) target_precompile_headers(pipedaltest PRIVATE pch.h) @@ -508,25 +497,25 @@ endif() target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES} ) -target_link_libraries(pipedaltest PRIVATE ${PIPEDAL_LIBS} +target_link_libraries(pipedaltest PRIVATE ${PIPEDAL_LIBS} ) ######################################################### # VST3 Source. # -# VST3 support is optional, because it poses unfortunate +# VST3 support is optional, because it poses unfortunate # licensing problems. # There's no easy way to get the VST SDK to build without -# GCC c++11 linkage, which is not compatible with pipedal's +# GCC c++11 linkage, which is not compatible with pipedal's # use of C++20 features (strictly a link time breakage). # # So pipedal rebuilds the VST3 SDK using pipedal-compatible # compile flags. # -# The current build supports only Linux builds. Refer to the -# original VST3 SDK build for details on how to build +# The current build supports only Linux builds. Refer to the +# original VST3 SDK build for details on how to build # for other platforms. # ######################################################### @@ -566,12 +555,12 @@ if(ENABLE_VST3) ${VST3_BASEPATH}/source/timer.h ${VST3_BASEPATH}/source/updatehandler.cpp ${VST3_BASEPATH}/source/updatehandler.h - + ${VST3_BASEPATH}/thread/include/fcondition.h ${VST3_BASEPATH}/thread/include/flock.h ${VST3_BASEPATH}/thread/source/fcondition.cpp ${VST3_BASEPATH}/thread/source/flock.cpp - + # sdk_common files. @@ -615,7 +604,7 @@ if(ENABLE_VST3) ${VST3_PLUGININTERFACES_BASE_PATH}/ucolorspec.h ${VST3_PLUGININTERFACES_BASE_PATH}/ustring.cpp ${VST3_PLUGININTERFACES_BASE_PATH}/ustring.h - + # sdk files. # ${VST3_SRCPATH}/main/moduleinit.cpp @@ -664,7 +653,7 @@ if(ENABLE_VST3) ${VST3_SRCPATH}/vst/hosting/module.cpp ${VST3_SRCPATH}/vst/hosting/module.h ${VST3_SRCPATH}/vst/hosting/parameterchanges.cpp - ${VST3_SRCPATH}/vst/hosting/parameterchanges.h + ${VST3_SRCPATH}/vst/hosting/parameterchanges.h ${VST3_SRCPATH}/vst/hosting/pluginterfacesupport.cpp ${VST3_SRCPATH}/vst/hosting/pluginterfacesupport.h ${VST3_SRCPATH}/vst/hosting/plugprovider.cpp @@ -693,10 +682,10 @@ if(ENABLE_VST3) add_library(vst3_lib STATIC ${vst3_sources}) - target_include_directories(vst3_lib PRIVATE ${VST3_INCLUDES} + target_include_directories(vst3_lib PRIVATE ${VST3_INCLUDES} ) - + # add_executable(vst3test Vst3test.cpp # MemDebug.cpp @@ -705,16 +694,15 @@ if(ENABLE_VST3) # Vst3SdkRepro.cpp # ${VST3_FILES} - + # #vst3/Vst3PresetFile.hpp Vst3PresetFile.cpp # asan_options.cpp # ) - target_include_directories(vst3test PRIVATE ${PIPEDAL_INCLUDES} - ) + target_include_directories(vst3test PRIVATE ${PIPEDAL_INCLUDES}) - - target_link_libraries(vst3test PRIVATE ${PIPEDAL_LIBS} + + target_link_libraries(vst3test PRIVATE ${PIPEDAL_LIBS} vst3_lib dl pthread ) @@ -733,11 +721,11 @@ add_test(NAME DevTest COMMAND pipedaltest "[Dev]") -add_executable(pipedalconfig +add_executable(pipedalconfig PrettyPrinter.hpp SetWifiConfig.cpp SetWifiConfig.hpp CommandLineParser.hpp - PiPedalException.hpp + PiPedalException.hpp ConfigMain.cpp alsaCheck.cpp alsaCheck.hpp @@ -773,13 +761,12 @@ add_executable(pipedal_latency_test CpuUse.cpp ) -target_link_libraries(pipedal_latency_test PRIVATE pthread asound PiPedalCommon - ) - +target_link_libraries(pipedal_latency_test PRIVATE pthread asound PiPedalCommon) + add_executable(pipedal_alsa_info alsaCheck.cpp alsaCheck.hpp - alsaCheckMain.cpp + alsaCheckMain.cpp ) target_link_libraries(pipedal_alsa_info PRIVATE asound) @@ -788,7 +775,7 @@ add_executable(capturepresets Storage.cpp Storage.hpp CommandLineParser.hpp -) +) target_include_directories(capturepresets PRIVATE ${PIPEDAL_INCLUDES}) @@ -797,7 +784,7 @@ target_link_libraries(capturepresets ${PIPEDAL_LIBS}) add_executable(makeRelease makeReleaseMain.cpp CommandLineParser.hpp -) +) target_include_directories(makeRelease PRIVATE ${PIPEDAL_INCLUDES}) target_link_libraries(makeRelease ${PIPEDAL_LIBS}) @@ -807,14 +794,14 @@ target_link_libraries(makeRelease ${PIPEDAL_LIBS}) add_executable(pipedal_update - UpdateMain.cpp + UpdateMain.cpp UpdateResults.cpp UpdateResults.hpp Lv2SystemdLogger.cpp Lv2SystemdLogger.hpp TemporaryFile.cpp TemporaryFile.hpp AdminInstallUpdate.cpp AdminInstallUpdate.hpp ) -target_link_libraries(pipedal_update PRIVATE stdc++fs systemd PiPedalCommon ) +target_link_libraries(pipedal_update PRIVATE stdc++fs systemd PiPedalCommon ) add_executable(pipedaladmind AdminMain.cpp CommandLineParser.hpp @@ -824,7 +811,7 @@ add_executable(pipedaladmind AdminMain.cpp CommandLineParser.hpp JackServerSettings.hpp JackServerSettings.cpp Lv2SystemdLogger.hpp Lv2SystemdLogger.cpp - SystemConfigFile.hpp SystemConfigFile.cpp + SystemConfigFile.hpp SystemConfigFile.cpp CpuGovernor.cpp CpuGovernor.hpp asan_options.cpp @@ -832,9 +819,9 @@ add_executable(pipedaladmind AdminMain.cpp CommandLineParser.hpp target_link_libraries(pipedaladmind PRIVATE PiPedalCommon pthread atomic stdc++fs systemd ) add_executable(processcopyrights copyrightMain.cpp - CommandLineParser.hpp - PiPedalException.hpp - asan_options.cpp ) + CommandLineParser.hpp + PiPedalException.hpp + asan_options.cpp) target_link_libraries(processcopyrights PRIVATE PiPedalCommon stdc++fs) set (REACT_BUILD_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/react/build/) @@ -854,13 +841,13 @@ elseif(EXISTS "/usr/share/doc/libboost1.67-dev") set (BOOST_COPYRIGHT_DIR "libboost1.67-dev") else() message(FATAL_ERROR "Boost libary version has changed. Please update me.") -endif() +endif() -add_custom_command(OUTPUT ${REACT_NOTICES_FILE} +add_custom_command(OUTPUT ${REACT_NOTICES_FILE} COMMAND "$" - --output ${REACT_NOTICES_FILE} - --projectCopyright ${DEBIAN_COPYRIGHT_FILE} + --output ${REACT_NOTICES_FILE} + --projectCopyright ${DEBIAN_COPYRIGHT_FILE} liblilv-0-0 ${BOOST_COPYRIGHT_DIR} lv2-dev libsdbus-c++-dev librsvg2-2 libpango-1.0-0 libx11-6 libxrandr2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${DEBIAN_COPYRIGHT_FILE} "$" @@ -869,14 +856,14 @@ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} add_custom_target ( CopyrightBuild ALL - DEPENDS ${REACT_NOTICES_FILE} + DEPENDS ${REACT_NOTICES_FILE} ) install (TARGETS pipedalconfig pipedal_kconfig pipedal_latency_test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin EXPORT pipedalTargets) - install (TARGETS pipedald pipedaladmind pipedal_update DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin +install (TARGETS pipedald pipedaladmind pipedal_update DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin EXPORT pipedalSbinTargets) diff --git a/src/Lv2Effect.cpp b/src/Lv2Effect.cpp index e7dd6cc..c964222 100644 --- a/src/Lv2Effect.cpp +++ b/src/Lv2Effect.cpp @@ -18,6 +18,7 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "pch.h" +#include "restrict.hpp" #include "Lv2Effect.hpp" #include "PiPedalException.hpp" #include @@ -514,15 +515,15 @@ int Lv2Effect::GetControlIndex(const std::string &key) const Lv2Effect::~Lv2Effect() { - if (activated) - { - Deactivate(); - } if (worker) { worker->Close(); worker = nullptr; // delete the worker first! } + if (activated) + { + Deactivate(); + } if (pInstance) { lilv_instance_free(pInstance); @@ -635,7 +636,7 @@ void Lv2Effect::Deactivate() lilv_instance_deactivate(pInstance); } -static inline void CopyBuffer(float *input, float *output, uint32_t frames) +static inline void CopyBuffer(float *restrict input, float *restrict output, uint32_t frames) { for (uint32_t i = 0; i < frames; ++i) { @@ -673,7 +674,7 @@ void Lv2Effect::Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBuff { for (size_t i = 0; i < this->outputMixBuffers.size(); ++i) { - float *__restrict input; + float *restrict input; if (i >= this->inputAudioBuffers.size()) { if (this->inputAudioBuffers.size() == 0) @@ -686,8 +687,8 @@ void Lv2Effect::Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBuff { input = this->inputAudioBuffers[i]; } - float *__restrict pluginOutput = this->outputMixBuffers[i].data(); - float *__restrict finalOutput = this->outputAudioBuffers[i]; + float *restrict pluginOutput = this->outputMixBuffers[i].data(); + float *restrict finalOutput = this->outputAudioBuffers[i]; for (uint32_t i = 0; i < samples; ++i) { @@ -698,11 +699,11 @@ void Lv2Effect::Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBuff else if (this->outputAudioPortIndices.size() == 1 && this->outputAudioBuffers.size() == 2) { // 1 plugin output into 2 outputs. - float *__restrict pluginOutput = this->outputMixBuffers[0].data(); + float *restrict pluginOutput = this->outputMixBuffers[0].data(); for (size_t i = 0; i < this->outputMixBuffers.size(); ++i) { - float *__restrict input = this->inputAudioBuffers[i]; - float *__restrict finalOutput = this->outputAudioBuffers[i]; + float *restrict input = this->inputAudioBuffers[i]; + float *restrict finalOutput = this->outputAudioBuffers[i]; for (uint32_t i = 0; i < samples; ++i) { @@ -750,8 +751,8 @@ void Lv2Effect::Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBuff if (this->outputAudioBuffers.size() == 1) { - float *input = this->inputAudioBuffers[0]; - float *output = this->outputAudioBuffers[0]; + float * restrict input = this->inputAudioBuffers[0]; + float * restrict output = this->outputAudioBuffers[0]; for (uint32_t i = 0; i < samples; ++i) { output[i] = currentBypass * output[i] + (1 - currentBypass) * input[i]; @@ -766,8 +767,8 @@ void Lv2Effect::Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBuff } else { - float *inputL; - float *inputR; + float * restrict inputL; + float * restrict inputR; if (this->inputAudioBuffers.size() == 1) { inputL = inputR = inputAudioBuffers[0]; @@ -777,8 +778,8 @@ void Lv2Effect::Run(uint32_t samples, RealtimeRingBufferWriter *realtimeRingBuff inputL = inputAudioBuffers[0]; inputR = inputAudioBuffers[1]; } - float *outputL = outputAudioBuffers[0]; - float *outputR = outputAudioBuffers[1]; + float * restrict outputL = outputAudioBuffers[0]; + float * restrict outputR = outputAudioBuffers[1]; for (uint32_t i = 0; i < samples; ++i) { outputL[i] = currentBypass * outputL[i] + (1 - currentBypass) * inputL[i]; diff --git a/src/Lv2Pedalboard.cpp b/src/Lv2Pedalboard.cpp index df6d0bd..4721f95 100644 --- a/src/Lv2Pedalboard.cpp +++ b/src/Lv2Pedalboard.cpp @@ -28,6 +28,7 @@ #include "Lv2EventBufferWriter.hpp" #include "Lv2Log.hpp" #include "CrashGuard.hpp" +#include "restrict.hpp" using namespace pipedal; @@ -417,7 +418,7 @@ void Lv2Pedalboard::Deactivate() } } -static void Copy(float *input, float *output, uint32_t samples) +static void Copy(float *restrict input, float *restrict output, uint32_t samples) { for (uint32_t i = 0; i < samples; ++i) { @@ -434,6 +435,7 @@ bool Lv2Pedalboard::Run(float **inputBuffers, float **outputBuffers, uint32_t sa return false; } } + for (size_t i = 0; i < samples; ++i) { float volume = this->inputVolume.Tick(); diff --git a/src/SchedulerPriority.cpp b/src/SchedulerPriority.cpp index 0eb5194..8effce9 100644 --- a/src/SchedulerPriority.cpp +++ b/src/SchedulerPriority.cpp @@ -104,7 +104,7 @@ static void SetPriority(int realtimePriority, const char *priorityName) int result = sched_setscheduler(0, SCHED_RR, ¶m); if (result == 0) { - Lv2Log::debug("Service thread priority successfully boosted."); + Lv2Log::debug(SS("Service thread priority successfully boosted. (" << priorityName << ")")); return; } else diff --git a/src/Worker.cpp b/src/Worker.cpp index 7fcca63..a1baea1 100644 --- a/src/Worker.cpp +++ b/src/Worker.cpp @@ -143,6 +143,7 @@ bool Worker::EmitResponses() void Worker::WaitForAllResponses() { + // do what we can to clear the response queue in order to avoid memory/object leaks using Clock = std::chrono::steady_clock; auto startTime = Clock::now(); while (true) @@ -157,11 +158,14 @@ void Worker::WaitForAllResponses() break; } } - std::chrono::seconds waitDuration = std::chrono::duration_cast(Clock::now()-startTime); - if (waitDuration.count() > 5) { - throw std::logic_error("Timed out waiting for a Worker task to complete."); + // pump the plugin with a zero-length buffer. + + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + std::chrono::milliseconds waitDuration = std::chrono::duration_cast(Clock::now()-startTime); + if (waitDuration.count() > 1500) { + Lv2Log::error("Timed out waiting for a Worker task to complete."); + // better to leak than to terminate the application. } - std::this_thread::sleep_for(std::chrono::milliseconds(15)); } } @@ -260,21 +264,16 @@ bool HostWorkerThread::StartThread() void HostWorkerThread::Close() { - bool sendClose = false; { std::lock_guard lock{submitMutex}; if (pThread) { if (!closed) { closed = true; - sendClose = true; + ScheduleWorkNoLock(nullptr, 0, nullptr); } } } - if (sendClose) - { - ScheduleWork(nullptr, 0, nullptr); - } } HostWorkerThread::~HostWorkerThread() { @@ -302,6 +301,11 @@ LV2_Worker_Status HostWorkerThread::ScheduleWork(Worker *worker, size_t size, co { exiting = true; } + return ScheduleWorkNoLock(worker, size, data); + +} +LV2_Worker_Status HostWorkerThread::ScheduleWorkNoLock(Worker *worker, size_t size, const void *data) +{ if (requestRingBuffer.writeSpace() < sizeof(worker) + sizeof(size) + size) { diff --git a/src/Worker.hpp b/src/Worker.hpp index 9cf38aa..154ec3d 100644 --- a/src/Worker.hpp +++ b/src/Worker.hpp @@ -57,6 +57,7 @@ namespace pipedal { bool Closed() const { return closed || pThread == nullptr; } LV2_Worker_Status ScheduleWork(Worker*worker, size_t size, const void*data); private: + LV2_Worker_Status ScheduleWorkNoLock(Worker*worker, size_t size, const void*data); std::atomic closed = false; std::unique_ptr pThread; void ThreadProc() noexcept; diff --git a/vite/src/pipedal/PiPedalModel.tsx b/vite/src/pipedal/PiPedalModel.tsx index 45a0d13..c62ddf6 100644 --- a/vite/src/pipedal/PiPedalModel.tsx +++ b/vite/src/pipedal/PiPedalModel.tsx @@ -1844,6 +1844,7 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.deleteItem(fromInstanceId); newPedalboard.addBefore(fromItem, toInstanceId); + newPedalboard.selectedPlugin = fromItem.instanceId; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); @@ -1863,7 +1864,7 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.deleteItem(fromInstanceId); newPedalboard.addAfter(fromItem, toInstanceId); - + newPedalboard.selectedPlugin = fromItem.instanceId; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); } @@ -1885,6 +1886,7 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.addToStart(fromItem); + newPedalboard.selectedPlugin = fromItem.instanceId; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); } @@ -1904,6 +1906,7 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.addToEnd(fromItem); + newPedalboard.selectedPlugin = fromItem.instanceId; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); @@ -1931,7 +1934,7 @@ export class PiPedalModel //implements PiPedalModel let emptyItem = newPedalboard.createEmptyItem(); newPedalboard.replaceItem(fromInstanceId, emptyItem); newPedalboard.replaceItem(toInstanceId, fromItem); - + newPedalboard.selectedPlugin = fromItem.instanceId; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); @@ -1955,6 +1958,7 @@ export class PiPedalModel //implements PiPedalModel } let newItem = newPedalboard.createEmptyItem(); newPedalboard.addItem(newItem, instanceId, append); + newPedalboard.selectedPlugin = newItem.instanceId; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); return newItem.instanceId; @@ -1980,6 +1984,8 @@ export class PiPedalModel //implements PiPedalModel } let newItem = newPedalboard.createEmptySplit(); newPedalboard.addItem(newItem, instanceId, append); + newPedalboard.selectedPlugin = newItem.instanceId; + this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); return newItem.instanceId; @@ -1998,6 +2004,7 @@ export class PiPedalModel //implements PiPedalModel newPedalboard.setItemEmpty(item); + newPedalboard.selectedPlugin = item.instanceId; this.setModelPedalboard(newPedalboard); this.updateServerPedalboard(); return item.instanceId;