From 6c441ecfee6b35fb4d86d788ff6337c8de9dd24f Mon Sep 17 00:00:00 2001 From: "Robin E.R. Davies" Date: Tue, 27 Jan 2026 23:45:13 -0500 Subject: [PATCH] WIP Sync --- .vscode/c_cpp_properties.json | 1 - CMakeLists.txt | 19 +- src/AlsaDriver.cpp | 5 - src/AlsaDriver.hpp | 3 +- src/AlsaDriverTest.cpp | 203 ++++++++++-------- src/AudioHost.cpp | 8 +- src/Banks.hpp | 2 +- src/CMakeLists.txt | 12 +- src/ChannelRouterSettings.cpp | 4 +- src/ChannelRouterSettings.hpp | 40 ++-- src/DummyAudioDriver.hpp | 1 + src/Lv2Pedalboard.cpp | 43 +++- src/Lv2Pedalboard.hpp | 4 + src/Pedalboard.cpp | 10 +- src/Pedalboard.hpp | 21 +- src/PiLatencyMain.cpp | 28 ++- src/PiPedalModel.cpp | 22 +- src/PiPedalModel.hpp | 4 +- src/PiPedalSocket.cpp | 27 ++- src/RingBufferReader.hpp | 10 +- src/StateInterface.hpp | 3 +- src/Storage.cpp | 7 +- src/Storage.hpp | 2 +- vite/src/pipedal/ChannelRouterSettings.tsx | 131 ++++++++++- .../pipedal/ChannelRouterSettingsDialog.tsx | 21 +- vite/src/pipedal/Pedalboard.tsx | 8 +- vite/src/pipedal/PiPedalModel.tsx | 13 +- vite/src/pipedal/SettingsDialog.tsx | 90 ++++---- 28 files changed, 480 insertions(+), 262 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index a709077..fac3cf6 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -13,7 +13,6 @@ "/usr/include/x86_64-linux-gnu", "/usr/lib" ], - "compilerPath": "/usr/bin/gcc-12", "cStandard": "c17", "cppStandard": "c++20", "intelliSenseMode": "linux-gcc-arm64", diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ed3d0b..bc7919d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,17 @@ set (DISPLAY_VERSION "PiPedal v1.5.99-Beta") set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE}) set (CMAKE_INSTALL_PREFIX "/usr/") +set (LIBZIP_DO_INSTALL OFF CACHE BOOL "Disable libzip install" FORCE) +set (SQLITECPP_INSTALL OFF CACHE BOOL "Disable SQLiteCpp install" FORCE) + +set(SUBMODULE_INSTALL OFF CACHE BOOL "" FORCE) + +# Remove SQLiteCPP install files. +set(CPACK_SOURCE_IGNORE_FILES + "*.a;sqlite3.h;$(CPACK_SOURCE_IGNORE_FILES)" +) + + set (PIPEDAL_EXCLUDE_TESTS false) include(CTest) enable_testing() @@ -96,9 +107,9 @@ set(CPACK_DEBIAN_PACKAGE_SECTION sound) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE) -# Accept either libzip4 or libzip5 to satisfy libzip 4 linkage (because Ubuntu nonsense) -set(CPACK_DEBIAN_PACKAGE_DEPENDS "libicu-dev ,lv2-dev, ffmpeg, authbind, curl, gpg, alsa-base| pipewire, alsa-utils") + +set(CPACK_DEBIAN_PACKAGE_DEPENDS "libicu-dev ,lv2-dev,iw, ffmpeg, authbind, curl, gpg, alsa-base| pipewire, alsa-utils") set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE}) set(CPACK_PACKAGING_INSTALL_PREFIX /usr) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) @@ -118,4 +129,8 @@ set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA ) + include(CPack) + +message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") + diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index 92472d6..b75e52d 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -354,11 +354,6 @@ namespace pipedal std::vector outputBufferMixes; - - - std::vector deviceCaptureBuffers; - std::vector devicePlaybackBuffers; - std::vector rawCaptureBuffer; std::vector rawPlaybackBuffer; diff --git a/src/AlsaDriver.hpp b/src/AlsaDriver.hpp index 1b9ee0e..3d833a8 100644 --- a/src/AlsaDriver.hpp +++ b/src/AlsaDriver.hpp @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2025 Robin E. R. Davies + * Copyright (c) 2026 Robin E. R. Davies * * 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 @@ -24,6 +24,7 @@ #pragma once +#include #include "AudioDriver.hpp" #include "JackServerSettings.hpp" diff --git a/src/AlsaDriverTest.cpp b/src/AlsaDriverTest.cpp index 129fa37..fbe3a72 100644 --- a/src/AlsaDriverTest.cpp +++ b/src/AlsaDriverTest.cpp @@ -1,18 +1,18 @@ /* * MIT License - * + * * Copyright (c) 2022 Robin E. R. Davies - * + * * 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 @@ -27,28 +27,34 @@ #include #include #include +#include #include "AlsaDriver.hpp" -#include "JackDriver.hpp" +#include "ChannelRouterSettings.hpp" using namespace pipedal; using namespace std; - -class AlsaTester: private AudioDriverHost { +class AlsaTester : private AudioDriverHost +{ public: - enum class TestType { Oscillator, LatencyMonitor, NullTest}; + enum class TestType + { + Oscillator, + LatencyMonitor, + NullTest + }; + private: AudioDriver *audioDriver = nullptr; TestType testType; public: AlsaTester(TestType testType) - : testType(testType) + : testType(testType) { // audioDriver = CreateAlsaDriver(this); // audioDriver = CreateJackDriver(this); - } ~AlsaTester() { @@ -57,47 +63,47 @@ public: delete[] outputBuffers; } - bool useJack = false; + void initializeChannelSelection(JackConfiguration &jackConfiguration, ChannelSelection &channelSelection) + { + size_t nInputs = std::max(jackConfiguration.inputAudioPorts().size(),size_t(2)); + size_t nOutputs = std::max(jackConfiguration.outputAudioPorts().size(),size_t(2)); + auto &inputSelections = channelSelection.mainInputChannels(); + auto &outputSelections = channelSelection.mainOutputChannels(); + inputSelections.resize(nInputs); + for (size_t i = 0; i < nInputs; ++i) + { + inputSelections[i] = i; + } + outputSelections.resize(nOutputs); + for (size_t i = 0; i < nOutputs; ++i) + { + outputSelections[i] = i; + } + + } void Test() { AlsaFormatEncodeDecodeTest(this); - JackServerSettings serverSettings("hw:M2","hw:M2",48000,32,3); + JackServerSettings serverSettings("hw:M2", "hw:M2", 48000, 32, 3); JackConfiguration jackConfiguration; - if (useJack) - { - jackConfiguration.JackInitialize(); - } else { - jackConfiguration.AlsaInitialize(serverSettings); - } + jackConfiguration.AlsaInitialize(serverSettings); - JackChannelSelection channelSelection( - jackConfiguration.inputAudioPorts(), - jackConfiguration.outputAudioPorts(), - jackConfiguration.inputMidiDevices()); + ChannelSelection channelSelection; -#if JACK_HOST - if (useJack) - { - audioDriver = CreateJackDriver(this); - - } else { - audioDriver = CreateAlsaDriver(this); - } -#else audioDriver = CreateAlsaDriver(this); -#endif + initializeChannelSelection(jackConfiguration, channelSelection); - oscillator.Init(440,jackConfiguration.sampleRate()); + oscillator.Init(440, jackConfiguration.sampleRate()); latencyMonitor.Init(jackConfiguration.sampleRate()); - audioDriver->Open(serverSettings,channelSelection); + audioDriver->Open(serverSettings, channelSelection); - inputBuffers = new float*[channelSelection.GetInputAudioPorts().size()]; - outputBuffers = new float*[channelSelection.GetOutputAudioPorts().size()]; + inputBuffers = new float *[channelSelection.mainInputChannels().size()]; + outputBuffers = new float *[channelSelection.mainOutputChannels().size()]; audioDriver->Activate(); @@ -107,7 +113,7 @@ public: if (testType == TestType::LatencyMonitor) { auto latency = this->latencyMonitor.GetLatency(); - double ms = 1000.0*latency/jackConfiguration.sampleRate(); + double ms = 1000.0 * latency / jackConfiguration.sampleRate(); cout << "Latency: " << latency << " samples " << ms << "ms" << " xruns: " << GetXruns() << " Cpu: " << audioDriver->CpuUse() << "%" << endl; } @@ -115,37 +121,40 @@ public: audioDriver->Deactivate(); audioDriver->Close(); - } - float**inputBuffers = nullptr; - float**outputBuffers = nullptr; + float **inputBuffers = nullptr; + float **outputBuffers = nullptr; - class Oscillator { + class Oscillator + { private: double dx = 0; double x = 0; double dx2 = 0; double x2 = 0; - public: + public: void Init(float frequency, size_t sampleRate) { - dx = frequency*3.141592736*2/sampleRate; - dx2 = 0.5*3.141592736*2/sampleRate; + dx = frequency * 3.141592736 * 2 / sampleRate; + dx2 = 0.5 * 3.141592736 * 2 / sampleRate; } - float Next() { + float Next() + { float result = (float)std::cos(x); float env = (float)std::cos(x2); x += dx; x2 += dx2; - return result*env; + return result * env; } }; - class LatencyMonitor { - enum class State { + class LatencyMonitor + { + enum class State + { Idle, Waiting, }; @@ -156,67 +165,74 @@ public: size_t current_latency = 0; size_t latency = 0; std::mutex sync; + public: void Init(uint64_t sampleRate) { - idle_samples = (uint64_t)sampleRate*2; - waiting_samples = (uint64_t)sampleRate*2; + idle_samples = (uint64_t)sampleRate * 2; + waiting_samples = (uint64_t)sampleRate * 2; state = State::Idle; t = idle_samples; latency = 0; } - size_t GetLatency() { - std::lock_guard lock { sync}; + size_t GetLatency() + { + std::lock_guard lock{sync}; return latency; } float Next(float input) { - switch(state) + switch (state) { - default: - case State::Idle: + default: + case State::Idle: + { + if (t-- == 0) { - if (t-- == 0) { - state = State::Waiting; - current_latency = 0; - } - return 0.01; + state = State::Waiting; + current_latency = 0; } - break; - case State::Waiting: + return 0.01; + } + break; + case State::Waiting: + { + if (std::abs(input) > 0.1 || current_latency > 500) { - if (std::abs(input) > 0.1 || current_latency > 500) { - { - std::lock_guard lock { sync}; - latency = current_latency; - } - state = State::Idle; - t = idle_samples; - } else { - ++current_latency; + { + std::lock_guard lock{sync}; + latency = current_latency; } - return current_latency < 100 ? 0.25 : 0.0; + state = State::Idle; + t = idle_samples; } - break; + else + { + ++current_latency; + } + return current_latency < 100 ? 0.25 : 0.0; + } + break; } } }; - Oscillator oscillator; LatencyMonitor latencyMonitor; - virtual void OnAudioTerminated() { - + virtual void OnAudioTerminated() + { } - virtual void OnAlsaDriverStopped() { + virtual void OnAlsaDriverStopped() + { } - virtual void OnProcess(size_t nFrames) { - if (testType == TestType::NullTest) return; - + virtual void OnProcess(size_t nFrames) + { + if (testType == TestType::NullTest) + return; size_t inputs = audioDriver->MainInputBufferCount(); size_t outputs = audioDriver->MainOutputBufferCount(); @@ -233,14 +249,15 @@ public: { for (size_t i = 0; i < nFrames; ++i) { - float v = oscillator.Next()*0.25f; + float v = oscillator.Next() * 0.25f; for (size_t c = 0; c < outputs; ++c) { outputBuffers[c][i] = v; } } } - else { + else + { for (size_t i = 0; i < nFrames; ++i) { float v = latencyMonitor.Next(inputBuffers[0][i]); @@ -249,36 +266,34 @@ public: outputBuffers[c][i] = v; } } - } - } std::mutex sync; uint64_t xruns; - uint64_t GetXruns() { - lock_guard lock { sync}; + uint64_t GetXruns() + { + lock_guard lock{sync}; return xruns; } - virtual void OnUnderrun() { - lock_guard lock { sync }; + virtual void OnUnderrun() + { + lock_guard lock{sync}; ++xruns; - } }; +TEST_CASE("alsa_test", "[alsa_test]") +{ -TEST_CASE( "alsa_test", "[alsa_test]" ) { - AlsaTester alsaDriver(AlsaTester::TestType::Oscillator); alsaDriver.Test(); } - -TEST_CASE( "alsa_midi_test", "[alsa_midi_test]" ) { +TEST_CASE("alsa_midi_test", "[alsa_midi_test]") +{ AlsaTester alsaDriver(AlsaTester::TestType::Oscillator); MidiDecoderTest(); } - diff --git a/src/AudioHost.cpp b/src/AudioHost.cpp index c1eb2ca..8a0f37c 100644 --- a/src/AudioHost.cpp +++ b/src/AudioHost.cpp @@ -1900,11 +1900,11 @@ public: PIPEDAL_NON_INLINE RealtimePedalboardItemIndex GetRealtimeItemIndex(int64_t instanceId) { - Pedalboard::InstanceType instanceType = Pedalboard::GetInstanceTypeFromInstanceId(instanceId); + Pedalboard::PedalboardType instanceType = Pedalboard::GetInstanceTypeFromInstanceId(instanceId); int64_t index = -1; switch (instanceType) { - case Pedalboard::InstanceType::MainPedalboard: + case Pedalboard::PedalboardType::MainPedalboard: if (this->currentPedalboard) { if (instanceId == Pedalboard::START_CONTROL_ID) { index = Pedalboard::START_CONTROL_ID; @@ -1915,7 +1915,7 @@ public: } } break; - case Pedalboard::InstanceType::MainInsert: + case Pedalboard::PedalboardType::MainInsert: if (this->currentMainInsertPedalboard) { if (instanceId == Pedalboard::MAIN_INSERT_START_CONTROL_ID) { index = Pedalboard::MAIN_INSERT_START_CONTROL_ID; @@ -1926,7 +1926,7 @@ public: } } break; - case Pedalboard::InstanceType::AuxInsert: + case Pedalboard::PedalboardType::AuxInsert: if (this->currentAuxInsertPedalboard) { if (instanceId == Pedalboard::AUX_INSERT_START_CONTROL_ID) { index = Pedalboard::START_CONTROL_ID; diff --git a/src/Banks.hpp b/src/Banks.hpp index 18951f3..cc24fce 100644 --- a/src/Banks.hpp +++ b/src/Banks.hpp @@ -240,7 +240,7 @@ namespace pipedal { // zero length? We can never have a zero-length bank. // Add a default preset and make it the selected preset. - Pedalboard pedalboard = Pedalboard::MakeDefault(Pedalboard::InstanceType::MainPedalboard); + Pedalboard pedalboard = Pedalboard::MakeDefault(Pedalboard::PedalboardType::MainPedalboard); this->addPreset(pedalboard); newSelection = presets_[0]->instanceId(); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8f0bae..2ed9781 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -352,8 +352,9 @@ target_compile_definitions(libpipedald PUBLIC "_REENTRANT") target_include_directories(libpipedald PUBLIC ${PIPEDAL_INCLUDES}) target_link_libraries(libpipedald - PUBLIC + PUBLIC PiPedalCommon + PRIVATE SQLiteCpp ${PipeWire_LIBRARIES} ) @@ -762,6 +763,7 @@ add_executable(pipedal_latency_test target_link_libraries(pipedal_latency_test PRIVATE pthread asound PiPedalCommon) +target_include_directories(pipedal_latency_test PRIVATE ${PIPEDAL_INCLUDES}) add_executable(pipedal_alsa_info alsaCheck.cpp alsaCheck.hpp @@ -859,10 +861,14 @@ add_custom_target ( ) + install (TARGETS pipedalconfig pipedal_kconfig pipedal_latency_test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin - EXPORT pipedalTargets) + EXPORT pipedalTargets + ) install (TARGETS pipedald pipedaladmind pipedal_update DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin - EXPORT pipedalSbinTargets) + EXPORT pipedalSbinTargets + ) + diff --git a/src/ChannelRouterSettings.cpp b/src/ChannelRouterSettings.cpp index 0b9e9be..9410e3b 100644 --- a/src/ChannelRouterSettings.cpp +++ b/src/ChannelRouterSettings.cpp @@ -129,8 +129,8 @@ void ChannelSelection::normalizeChannelSelection() { ChannelRouterSettings::ChannelRouterSettings() -: mainInserts_(Pedalboard::InstanceType::MainInsert) -, auxInserts_(Pedalboard::InstanceType::AuxInsert) +: mainInserts_(Pedalboard::PedalboardType::MainInsert) +, auxInserts_(Pedalboard::PedalboardType::AuxInsert) { } diff --git a/src/ChannelRouterSettings.hpp b/src/ChannelRouterSettings.hpp index 885b6e9..0c15f3d 100644 --- a/src/ChannelRouterSettings.hpp +++ b/src/ChannelRouterSettings.hpp @@ -49,7 +49,7 @@ namespace pipedal std::vector controlValues_; - public: + public: using self = ChannelRouterSettings; using ptr = std::shared_ptr; @@ -57,7 +57,7 @@ namespace pipedal uint64_t numberOfAudioInputChannels() const; uint64_t numberOfAudioOutputChannels() const; - + JSON_GETTER_SETTER(configured) JSON_GETTER_SETTER(channelRouterPresetId) JSON_GETTER_SETTER_REF(mainInputChannels) @@ -70,28 +70,34 @@ namespace pipedal JSON_GETTER_SETTER_REF(sendOutputChannels) JSON_GETTER_SETTER_REF(controlValues) - DECLARE_JSON_MAP(ChannelRouterSettings); - }; - // just the channel selecttions. - class ChannelSelection { + // just the channel selecttions. + class ChannelSelection + { public: ChannelSelection() = default; - ChannelSelection(ChannelRouterSettings&settings); - ChannelSelection(const ChannelSelection&other) = default; - ChannelSelection(ChannelSelection&&other) = default; - ChannelSelection& operator=(const ChannelSelection&other) = default; - ChannelSelection& operator=(ChannelSelection&&other) = default; + ChannelSelection(ChannelRouterSettings &settings); + ChannelSelection(const ChannelSelection &other) = default; + ChannelSelection(ChannelSelection &&other) = default; + ChannelSelection &operator=(const ChannelSelection &other) = default; + ChannelSelection &operator=(ChannelSelection &&other) = default; ~ChannelSelection() = default; - const std::vector&mainInputChannels() const { return mainInputChannels_; } - const std::vector&mainOutputChannels() const { return mainOutputChannels_; } - const std::vector&auxInputChannels() const { return auxInputChannels_; } - const std::vector&auxOutputChannels() const { return auxOutputChannels_; } - const std::vector&sendInputChannels() const { return sendInputChannels_; } - const std::vector&sendOutputChannels() const { return sendOutputChannels_; } + const std::vector &mainInputChannels() const { return mainInputChannels_; } + const std::vector &mainOutputChannels() const { return mainOutputChannels_; } + const std::vector &auxInputChannels() const { return auxInputChannels_; } + const std::vector &auxOutputChannels() const { return auxOutputChannels_; } + const std::vector &sendInputChannels() const { return sendInputChannels_; } + const std::vector &sendOutputChannels() const { return sendOutputChannels_; } + + std::vector &mainInputChannels() { return mainInputChannels_; } + std::vector &mainOutputChannels() { return mainOutputChannels_; } + std::vector &auxInputChannels() { return auxInputChannels_; } + std::vector &auxOutputChannels() { return auxOutputChannels_; } + std::vector &sendInputChannels() { return sendInputChannels_; } + std::vector &sendOutputChannels() { return sendOutputChannels_; } private: void normalizeChannelSelection(); diff --git a/src/DummyAudioDriver.hpp b/src/DummyAudioDriver.hpp index 35f2d31..59d5f09 100644 --- a/src/DummyAudioDriver.hpp +++ b/src/DummyAudioDriver.hpp @@ -24,6 +24,7 @@ #pragma once +#include #include "AudioDriver.hpp" #include "JackServerSettings.hpp" diff --git a/src/Lv2Pedalboard.cpp b/src/Lv2Pedalboard.cpp index 34d0055..ad2b5cf 100644 --- a/src/Lv2Pedalboard.cpp +++ b/src/Lv2Pedalboard.cpp @@ -320,6 +320,7 @@ std::vector Lv2Pedalboard::PrepareItems( void Lv2Pedalboard::Prepare(IHost *pHost, Pedalboard &pedalboard, Lv2PedalboardErrorList &errorList, ExistingEffectMap *existingEffects) { this->pHost = pHost; + this->pedalboardType = pedalboard.GetInstanceType(); inputVolume.SetSampleRate((float)(this->pHost->GetSampleRate())); outputVolume.SetSampleRate((float)(this->pHost->GetSampleRate())); @@ -329,13 +330,15 @@ void Lv2Pedalboard::Prepare(IHost *pHost, Pedalboard &pedalboard, Lv2PedalboardE inputVolume.SetTarget(pedalboard.input_volume_db()); outputVolume.SetTarget(pedalboard.output_volume_db()); - for (int i = 0; i < pHost->GetNumberOfInputAudioChannels(); ++i) + size_t nInputs = std::max(GetNumberOfAudioInputChannels(),(size_t)1); + + for (size_t i = 0; i < nInputs; ++i) { this->pedalboardInputBuffers.push_back(bufferPool.AllocateBuffer(pHost->GetMaxAudioBufferSize())); } auto outputs = PrepareItems(pedalboard.items(), this->pedalboardInputBuffers, errorList, existingEffects); - int nOutputs = pHost->GetNumberOfOutputAudioChannels(); + size_t nOutputs = GetNumberOfAudioOutputChannels(); if (nOutputs == 1) { this->pedalboardOutputBuffers.push_back(outputs[0]); @@ -572,7 +575,12 @@ void Lv2Pedalboard::ComputeVus(RealtimeVuBuffers *vuConfiguration, uint32_t samp { for (size_t i = 0; i < vuConfiguration->enabledIndexes.size(); ++i) { - int index = vuConfiguration->enabledIndexes[i]; + auto& rtIndex = vuConfiguration->enabledIndexes[i]; + if (rtIndex.instanceType != this->pedalboardType) + { + continue; + } + int index = rtIndex.index; VuUpdate *pUpdate = &vuConfiguration->vuUpdateWorkingData[i]; if (index == Pedalboard::START_CONTROL_ID) { @@ -1016,3 +1024,32 @@ void Lv2Pedalboard::handleTapTempo(uint8_t value, const MidiTimestamp& timestamp mapping.lastTapTimestamp = timestamp; } } + + +size_t Lv2Pedalboard::GetNumberOfAudioInputChannels() const { + switch (pedalboardType) + { + case Pedalboard::PedalboardType::MainPedalboard: + return pHost->GetChannelSelection().mainInputChannels().size(); + case Pedalboard::PedalboardType::MainInsert: + return pHost->GetChannelSelection().mainOutputChannels().size(); + case Pedalboard::PedalboardType::AuxInsert: + return pHost->GetChannelSelection().auxInputChannels().size(); + default: + throw std::runtime_error("Invalid argument"); + } +} + +size_t Lv2Pedalboard::GetNumberOfAudioOutputChannels() const { + switch (pedalboardType) + { + case Pedalboard::PedalboardType::MainPedalboard: + return pHost->GetChannelSelection().mainOutputChannels().size(); + case Pedalboard::PedalboardType::MainInsert: + return pHost->GetChannelSelection().mainOutputChannels().size(); + case Pedalboard::PedalboardType::AuxInsert: + return pHost->GetChannelSelection().auxOutputChannels().size(); + default: + throw std::runtime_error("Invalid argument"); + } +} \ No newline at end of file diff --git a/src/Lv2Pedalboard.hpp b/src/Lv2Pedalboard.hpp index c893824..620c035 100644 --- a/src/Lv2Pedalboard.hpp +++ b/src/Lv2Pedalboard.hpp @@ -51,6 +51,7 @@ namespace pipedal class Lv2Pedalboard { private: + Pedalboard::PedalboardType pedalboardType; IHost *pHost = nullptr; size_t currentFrameOffset = 0; DbDezipper inputVolume; @@ -128,6 +129,9 @@ namespace pipedal std::vector &GetEffects() { return realtimeEffects; } std::vector> &GetSharedEffectList() { return effects; } + size_t GetNumberOfAudioInputChannels() const; + size_t GetNumberOfAudioOutputChannels() const; + int GetIndexOfInstanceId(uint64_t instanceId) { for (int i = 0; i < this->realtimeEffects.size(); ++i) diff --git a/src/Pedalboard.cpp b/src/Pedalboard.cpp index 5cdc8fb..6a3f0fb 100644 --- a/src/Pedalboard.cpp +++ b/src/Pedalboard.cpp @@ -210,7 +210,7 @@ PedalboardItem Pedalboard::MakeSplit() -Pedalboard Pedalboard::MakeDefault(InstanceType instanceType) +Pedalboard Pedalboard::MakeDefault(PedalboardType instanceType) { // copy insanity. but it happens so rarely. Pedalboard result; @@ -510,17 +510,17 @@ Snapshot Pedalboard::MakeSnapshotFromCurrentSettings(const Pedalboard &previousP } -Pedalboard::Pedalboard(InstanceType instanceType = InstanceType::MainPedalboard) +Pedalboard::Pedalboard(PedalboardType instanceType) { switch (instanceType) { - case InstanceType::MainPedalboard: + case PedalboardType::MainPedalboard: nextInstanceId_ = 0; break; - case InstanceType::MainInsert: + case PedalboardType::MainInsert: nextInstanceId_ = MAIN_INSERT_INSTANCE_BASE;; break; - case InstanceType::AuxInsert: + case PedalboardType::AuxInsert: nextInstanceId_ = AUX_INSERT_INSTANCE_BASE;; break; } diff --git a/src/Pedalboard.hpp b/src/Pedalboard.hpp index 9532efb..df7f425 100644 --- a/src/Pedalboard.hpp +++ b/src/Pedalboard.hpp @@ -230,13 +230,14 @@ class Pedalboard { int64_t selectedPlugin_ = -1; + static constexpr int64_t TWO_POWER_52 = 4503599627370496; // Maximum Javascript integer value. static constexpr int64_t TWO_POWER_48 = 281474976710656; // Number of possible instance IDs for Main Pedalboards. static constexpr int64_t MAX_INSTANCE_ID = TWO_POWER_48; public: - enum class InstanceType { + enum class PedalboardType { MainPedalboard, MainInsert, AuxInsert @@ -253,25 +254,25 @@ public: static constexpr int64_t AUX_INSERT_START_CONTROL_ID = AUX_INSERT_INSTANCE_BASE + MAX_INSTANCE_ID -2; static constexpr int64_t AUX_INSERT_END_CONTROL_ID = AUX_INSERT_INSTANCE_BASE + MAX_INSTANCE_ID -3; - static InstanceType GetInstanceTypeFromInstanceId(int64_t instanceId) { - if (instanceId == START_CONTROL_ID) return InstanceType::MainPedalboard; - if (instanceId == END_CONTROL_ID) return InstanceType::MainPedalboard; + static PedalboardType GetInstanceTypeFromInstanceId(int64_t instanceId) { + if (instanceId == START_CONTROL_ID) return PedalboardType::MainPedalboard; + if (instanceId == END_CONTROL_ID) return PedalboardType::MainPedalboard; if (instanceId >= MAIN_INSERT_INSTANCE_BASE) { - return InstanceType::MainInsert; + return PedalboardType::MainInsert; } else if (instanceId >= AUX_INSERT_INSTANCE_BASE) { - return InstanceType::AuxInsert; + return PedalboardType::AuxInsert; } else { - return InstanceType::MainPedalboard; + return PedalboardType::MainPedalboard; } } - InstanceType GetInstanceType() const { + PedalboardType GetInstanceType() const { return GetInstanceTypeFromInstanceId(this->nextInstanceId_); // instanceId is irrelevant here. } - Pedalboard(InstanceType instanceType = InstanceType::MainPedalboard); + Pedalboard(PedalboardType instanceType = PedalboardType::MainPedalboard); // deep copy, breaking shared pointers. Pedalboard DeepCopy(); @@ -307,7 +308,7 @@ public: PedalboardItem MakeSplit(); - static Pedalboard MakeDefault(Pedalboard::InstanceType instanceType); + static Pedalboard MakeDefault(Pedalboard::PedalboardType instanceType = Pedalboard::PedalboardType::MainPedalboard); }; #undef GETTER_SETTER_REF diff --git a/src/PiLatencyMain.cpp b/src/PiLatencyMain.cpp index edc6d4f..8c93f1c 100644 --- a/src/PiLatencyMain.cpp +++ b/src/PiLatencyMain.cpp @@ -34,6 +34,7 @@ #include #include #include +#include "ChannelRouterSettings.hpp" using namespace pipedal; @@ -169,19 +170,26 @@ public: delete[] inputBuffers; delete[] outputBuffers; } - std::vector SelectChannels(const std::vector &available, const std::vector &selection) + std::vector SelectChannels(const std::vector &available, const std::vector &selection) { + std::vector result; if (selection.size() == 0) - return available; + { + result.resize(available.size()); + for (size_t i = 0; i < result.size(); ++i) + { + result[i] = (int64_t)i; + } + return result; + } - std::vector result; for (int sel : selection) { if (sel < 0 || sel >= available.size()) { throw PiPedalArgumentException(SS("Invalid channel: " + sel)); } - result.push_back(available[sel]); + result.push_back(sel); } return result; } @@ -199,22 +207,22 @@ public: auto &availableInputs = jackConfiguration.inputAudioPorts(); auto &availableOutputs = jackConfiguration.outputAudioPorts(); - std::vector inputAudioPorts, outputAudioPorts; + std::vector inputAudioPorts, outputAudioPorts; inputAudioPorts = SelectChannels(availableInputs, this->inputChannels); outputAudioPorts = SelectChannels(availableOutputs, this->outputChannels); - JackChannelSelection channelSelection( - inputAudioPorts, outputAudioPorts, - std::vector()); + ChannelSelection channelSelection; + channelSelection.mainInputChannels() = inputAudioPorts; + channelSelection.mainOutputChannels() = outputAudioPorts; audioDriver = CreateAlsaDriver(this); latencyMonitor.Init(jackConfiguration.sampleRate()); audioDriver->Open(serverSettings, channelSelection); - inputBuffers = new float *[channelSelection.GetInputAudioPorts().size()]; - outputBuffers = new float *[channelSelection.GetOutputAudioPorts().size()]; + inputBuffers = new float *[channelSelection.mainInputChannels().size()]; + outputBuffers = new float *[channelSelection.mainOutputChannels().size()]; audioDriver->Activate(); diff --git a/src/PiPedalModel.cpp b/src/PiPedalModel.cpp index f07b645..8262dae 100644 --- a/src/PiPedalModel.cpp +++ b/src/PiPedalModel.cpp @@ -81,7 +81,7 @@ PiPedalModel::PiPedalModel() this->updater = Updater::Create(); this->updater->Start(); this->currentUpdateStatus = updater->GetCurrentStatus(); - this->pedalboard = Pedalboard::MakeDefault(Pedalboard::InstanceType::MainPedalboard); + this->pedalboard = Pedalboard::MakeDefault(Pedalboard::PedalboardType::MainPedalboard); #if JACK_HOST this->jackServerSettings = this->storage.GetJackServerSettings(); // to get onboarding flag. this->jackServerSettings.ReadJackDaemonConfiguration(); @@ -216,14 +216,20 @@ void PiPedalModel::Init(const PiPedalConfiguration &configuration) storage.Initialize(); pluginHost.SetPluginStoragePath(storage.GetPluginUploadDirectory()); - this->channelRouterSettings = storage.GetChannelRouterSettings(); this->systemMidiBindings = storage.GetSystemMidiBindings(); #if JACK_HOST this->jackConfiguration = this->jackConfiguration.JackInitialize(); #else this->jackServerSettings = storage.GetJackServerSettings(); + this->jackConfiguration.AlsaInitialize(jackServerSettings); #endif + + this->channelRouterSettings = storage.GetChannelRouterSettings(); + pluginHost.OnConfigurationChanged( + jackConfiguration, + storage.GetChannelSelection()); + } void PiPedalModel::LoadLv2PluginInfo() @@ -299,7 +305,7 @@ void PiPedalModel::Load() if (CrashGuard::HasCrashed()) { // ignore the current preset, and load a blank pedalboard in order to avoid a potential plugin crash. - this->pedalboard = Pedalboard::MakeDefault(Pedalboard::InstanceType::MainPedalboard); + this->pedalboard = Pedalboard::MakeDefault(Pedalboard::PedalboardType::MainPedalboard); } else { @@ -1429,7 +1435,7 @@ void PiPedalModel::RestartAudio(bool useDummyAudioDriver) this->pluginHost.OnConfigurationChanged(jackConfiguration, channelSelection); - FireChannelSelectionChanged(-1); + FireChannelRouterSettingsChanged(-1); LoadCurrentPedalboard(); this->UpdateRealtimeVuSubscriptions(); @@ -1526,17 +1532,17 @@ std::vector PiPedalModel::GetAlsaSequencerPorts() } -void PiPedalModel::FireChannelSelectionChanged(int64_t clientId) +void PiPedalModel::FireChannelRouterSettingsChanged(int64_t clientId) { std::lock_guard guard{mutex}; { // take a snapshot incase a client unsusbscribes in the notification handler (in which case the mutex won't protect us) - JackChannelSelection channelSelection = storage.GetJackChannelSelection(this->jackConfiguration); + ChannelRouterSettings::ptr channelRouterSettings = this->channelRouterSettings; std::vector t{subscribers.begin(), subscribers.end()}; for (auto &subscriber : t) { - subscriber->OnChannelSelectionChanged(clientId, channelSelection); + subscriber->OnChannelRouterSettingsChanged(clientId, *channelRouterSettings); } } } @@ -3331,7 +3337,7 @@ void PiPedalModel::SetChannelRouterSettings(int64_t clientId,ChannelRouterSettin } RestartAudio(); // no lock to avoid mutex deadlock when reader thread is sending notifications.. - this->FireChannelSelectionChanged(clientId); + this->FireChannelRouterSettingsChanged(clientId); } diff --git a/src/PiPedalModel.hpp b/src/PiPedalModel.hpp index 17f1cf9..3aab379 100644 --- a/src/PiPedalModel.hpp +++ b/src/PiPedalModel.hpp @@ -73,7 +73,7 @@ namespace pipedal virtual void OnSnapshotModified(int64_t selectedSnapshot, bool modified) = 0; virtual void OnSelectedSnapshotChanged(int64_t selectedSnapshot) = 0; virtual void OnPluginPresetsChanged(const std::string &pluginUri) = 0; - virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection &channelSelection) = 0; + virtual void OnChannelRouterSettingsChanged(int64_t clientId, const ChannelRouterSettings &channelRouterSettings) = 0; virtual void OnVuMeterUpdate(const std::vector &updates) = 0; virtual void OnBankIndexChanged(const BankIndex &bankIndex) = 0; virtual void OnJackServerSettingsChanged(const JackServerSettings &jackServerSettings) = 0; @@ -206,7 +206,7 @@ namespace pipedal void FirePresetChanged(bool changed); void FirePluginPresetsChanged(const std::string &pluginUri); void FirePedalboardChanged(int64_t clientId, bool reloadAudioThread = true); - void FireChannelSelectionChanged(int64_t clientId); + void FireChannelRouterSettingsChanged(int64_t clientId); void FireBanksChanged(int64_t clientId); void FireJackConfigurationChanged(const JackConfiguration &jackConfiguration); void FireLv2StateChanged(int64_t instanceId, const Lv2PluginState &lv2State); diff --git a/src/PiPedalSocket.cpp b/src/PiPedalSocket.cpp index 85d0624..1028295 100644 --- a/src/PiPedalSocket.cpp +++ b/src/PiPedalSocket.cpp @@ -537,17 +537,24 @@ JSON_MAP_REFERENCE(SnapshotModifiedBody, snapshotIndex) JSON_MAP_REFERENCE(SnapshotModifiedBody, modified) JSON_MAP_END() -class ChannelSelectionChangedBody +class ChannelRouterSettingsChangedBody { public: - int64_t clientId_ = -1; - JackChannelSelection *jackChannelSelection_ = nullptr; + ChannelRouterSettingsChangedBody( + int64_t clientId, + const ChannelRouterSettings &channelRouterSettings + ): clientId_(clientId), channelRouterSettings_(channelRouterSettings) + { - DECLARE_JSON_MAP(ChannelSelectionChangedBody); + } + int64_t clientId_ = -1; + ChannelRouterSettings channelRouterSettings_; + + DECLARE_JSON_MAP(ChannelRouterSettingsChangedBody); }; -JSON_MAP_BEGIN(ChannelSelectionChangedBody) -JSON_MAP_REFERENCE(ChannelSelectionChangedBody, clientId) -JSON_MAP_REFERENCE(ChannelSelectionChangedBody, jackChannelSelection) +JSON_MAP_BEGIN(ChannelRouterSettingsChangedBody) +JSON_MAP_REFERENCE(ChannelRouterSettingsChangedBody, clientId) +JSON_MAP_REFERENCE(ChannelRouterSettingsChangedBody, channelRouterSettings) JSON_MAP_END() class PresetsChangedBody @@ -2000,11 +2007,9 @@ private: Send("onShowStatusMonitorChanged", show); } - virtual void OnChannelSelectionChanged(int64_t clientId, const JackChannelSelection &channelSelection) + virtual void OnChannelRouterSettingsChanged(int64_t clientId, const ChannelRouterSettings &channelRouterSettings) { - ChannelSelectionChangedBody body; - body.clientId_ = clientId; - body.jackChannelSelection_ = const_cast(&channelSelection); + ChannelRouterSettingsChangedBody body(clientId, channelRouterSettings); Send("onChannelSelectionChanged", body); } diff --git a/src/RingBufferReader.hpp b/src/RingBufferReader.hpp index 46f8c46..990b6fa 100644 --- a/src/RingBufferReader.hpp +++ b/src/RingBufferReader.hpp @@ -98,20 +98,20 @@ namespace pipedal struct RealtimePedalboardItemIndex { RealtimePedalboardItemIndex() - : instanceType(Pedalboard::InstanceType::MainPedalboard), index(-1) + : instanceType(Pedalboard::PedalboardType::MainPedalboard), index(-1) { } RealtimePedalboardItemIndex( - Pedalboard::InstanceType instanceType, - int index) + Pedalboard::PedalboardType instanceType, + int64_t index) : instanceType(instanceType), index(index) { } RealtimePedalboardItemIndex(const RealtimePedalboardItemIndex& other) = default; RealtimePedalboardItemIndex& operator=(const RealtimePedalboardItemIndex& other) = default; - Pedalboard::InstanceType instanceType = Pedalboard::InstanceType::MainPedalboard; - int index = -1; + Pedalboard::PedalboardType instanceType = Pedalboard::PedalboardType::MainPedalboard; + int64_t index = -1; }; struct RealtimeMidiEventRequest diff --git a/src/StateInterface.hpp b/src/StateInterface.hpp index c09cc33..311455d 100644 --- a/src/StateInterface.hpp +++ b/src/StateInterface.hpp @@ -19,13 +19,12 @@ #pragma once -#include "lilv/lilv.h" #include "lv2/state/state.h" #include #include "json_variant.hpp" #include "MapFeature.hpp" #include "IHost.hpp" -#include "lilv/lilv.h" +#include namespace pipedal { diff --git a/src/Storage.cpp b/src/Storage.cpp index 83a9524..3c726cf 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -377,7 +377,7 @@ void Storage::Initialize() LoadTone3000Auth(); try { - LoadChannelSelection(); + LoadJackChannelSelection(); } catch (const std::exception &) { @@ -476,7 +476,7 @@ void Storage::LoadBankIndex() if (bankIndex.entries().size() == 0) { currentBank.clear(); - Pedalboard defaultPedalboard = Pedalboard::MakeDefault(); + Pedalboard defaultPedalboard = Pedalboard::MakeDefault(Pedalboard::PedalboardType::MainPedalboard); int64_t instanceId = currentBank.addPreset(defaultPedalboard); currentBank.selectedPreset(instanceId); @@ -1135,7 +1135,7 @@ AlsaSequencerConfiguration Storage::GetAlsaSequencerConfiguration() const return this->alsaSequencerConfiguration; } -void Storage::LoadChannelSelection() +void Storage::LoadJackChannelSelection() { auto fileName = this->GetChannelSelectionFileName(); if (std::filesystem::exists(fileName)) @@ -3102,6 +3102,7 @@ ChannelRouterSettings::ptr Storage::LoadChannelRouterSettings() json_reader reader(is); ChannelRouterSettings::ptr result; reader.read(&result); + this->channelSelection = ChannelSelection(*result); return result; } catch (const std::exception &e) { Lv2Log::error("Failed to load Channel Router settings: %s", e.what()); diff --git a/src/Storage.hpp b/src/Storage.hpp index 76b4199..c2459dc 100644 --- a/src/Storage.hpp +++ b/src/Storage.hpp @@ -100,7 +100,7 @@ private: void LoadCurrentBank(); void SaveCurrentBank(); - void LoadChannelSelection(); + void LoadJackChannelSelection(); void SaveChannelSelection(); void LoadAlsaSequencerConfiguration(); diff --git a/vite/src/pipedal/ChannelRouterSettings.tsx b/vite/src/pipedal/ChannelRouterSettings.tsx index bea7ef7..26bc7d9 100644 --- a/vite/src/pipedal/ChannelRouterSettings.tsx +++ b/vite/src/pipedal/ChannelRouterSettings.tsx @@ -1,23 +1,61 @@ import { Pedalboard, ControlValue } from "./Pedalboard.tsx"; +import JackServerSettings from "./JackServerSettings.tsx"; +import JackConfiguration from "./Jack.tsx"; +function isActiveChannel(channels: number[]): boolean { + if (channels.length < 2) return false; + return channels[1] >= 0 || channels[0] >= 0; +} + +function chName(ch: number): string { + if (ch === -1) { + return "None"; + } + return "Ch " + (ch + 1); +} +function channelPairName(channels: number[], maxChannels: number): string { + if (channels.length !== 2) { + return "Invalid"; + } + if (channels[0] === -1 && channels[1] === -1) { + return "None"; + } + + if (maxChannels === 2) { + if (channels[0] === 0 && channels[1] === 1) { + return "Stereo"; + } + if (channels[0] === 0 && (channels[0] === channels[1] || channels[1] === -1)) { + return "Left"; + } + if (channels[1] === 1 && (channels[0] === channels[1])) { + return "Right"; + } + if (channels[0] === 1 && channels[1] === 0) { + return "Right,Left"; + } + } + return chName(channels[0]) + "," + chName(channels[1]); +} + export default class ChannelRouterSettings { configured: boolean = false; channelRouterPresetId: number = -1; - mainInputChannels: number[] = [1,1]; - mainOutputChannels: number[] = [0,1]; + mainInputChannels: number[] = [1, 1]; + mainOutputChannels: number[] = [0, 1]; mainInserts: Pedalboard = new Pedalboard(); - auxInputChannels: number[] = [0,0]; - auxOutputChannels: number[] = [-1,-1]; + auxInputChannels: number[] = [0, 0]; + auxOutputChannels: number[] = [-1, -1]; auxInserts: Pedalboard = new Pedalboard(); - sendInputChannels: number[] = [-1,-1]; - sendOutputChannels: number[] = [-1,-1]; + sendInputChannels: number[] = [-1, -1]; + sendOutputChannels: number[] = [-1, -1]; controlValues: ControlValue[] = []; // Inserts... @@ -55,10 +93,89 @@ export default class ChannelRouterSettings { return true; } } - let newValue = new ControlValue(symbol,value); + let newValue = new ControlValue(symbol, value); this.controlValues.push(newValue); this.controlValues = this.controlValues.slice(); // trigger observers. return true; } + getDescription(jackConfiguration: JackConfiguration): string { + if (!this.configured) { + return "Not configured"; + } + if (!jackConfiguration.isValid) + { + return "Not configured" + } + if (!this.isValid(jackConfiguration)) { + return "Invalid configuration"; + } + let nInputs = jackConfiguration.inputAudioPorts.length; + let nOutputs = jackConfiguration.outputAudioPorts.length; + let description = channelPairName(this.mainInputChannels, nInputs) + " -> " + + channelPairName(this.mainOutputChannels, nOutputs); + if (isActiveChannel(this.auxInputChannels) && isActiveChannel(this.auxOutputChannels)) + { + description += " " + "+ re-amp: " + channelPairName(this.auxInputChannels, nInputs) + " -> " + + channelPairName(this.auxOutputChannels, nOutputs); + } + if (isActiveChannel(this.sendInputChannels) && isActiveChannel(this.sendOutputChannels)) { + description += " " + "+ send: " +channelPairName(this.sendOutputChannels, nOutputs) + + " -> " + channelPairName(this.sendInputChannels, nInputs); + } + return description; + } + canEdit(jackConfiguration: JackConfiguration): boolean { + return jackConfiguration.isValid; + } + + isValid(jackConfiguration: JackConfiguration): boolean { + if (!this.configured) { + return false; + } + let maxInputChannels = jackConfiguration.inputAudioPorts.length; + let maxOutputChannels = jackConfiguration.outputAudioPorts.length; + + let hasInput = false; + let hasOutput = false; + for (let ch of this.mainInputChannels) { + if (ch >= 0) { + hasInput = true; + if (ch >= maxInputChannels) { + return false; + } + } + } + if (!hasInput) { + return false; + } + for (let ch of this.mainOutputChannels) { + if (ch >= 0) { + hasOutput = true; + if (ch >= maxOutputChannels) { + return false; + } + } + } + if (!hasOutput) { + return false; + } + for (let ch of this.auxInputChannels) { + if (ch >= maxInputChannels) { + return false; + } + } + for (let ch of this.auxOutputChannels) { + if (ch >= maxOutputChannels) { + return false; + } + } + for (let ch of this.sendInputChannels) { + if (ch >= maxInputChannels) { + return false; + } + } + return true; + } + } \ No newline at end of file diff --git a/vite/src/pipedal/ChannelRouterSettingsDialog.tsx b/vite/src/pipedal/ChannelRouterSettingsDialog.tsx index 5fbb414..b1b51d1 100644 --- a/vite/src/pipedal/ChannelRouterSettingsDialog.tsx +++ b/vite/src/pipedal/ChannelRouterSettingsDialog.tsx @@ -42,6 +42,11 @@ import DialogEx from './DialogEx'; import { PiPedalModelFactory } from './PiPedalModel'; + +let debugInputChannels: number | null = 2; +let debugOutputChannels: number | null = 4; + + export interface ChannelRouterSettingsDialogProps { open: boolean; onClose: () => void; @@ -309,6 +314,12 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) { let ChannelSelect = (routeType: RouteType, channelIndex: number, input: boolean, icon: boolean = true) => { let channelCount = input ? config.inputAudioPorts.length : config.outputAudioPorts.length; + if (input && debugInputChannels != null) { + channelCount = debugInputChannels; + } + if (!input && debugOutputChannels != null) { + channelCount = debugOutputChannels; + } let value: number; @@ -336,7 +347,7 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) { } onChange={(event) => { let newValue = event.target.value as number; - let newSettings = Object.assign(new ChannelRouterSettings(), settings); + let newSettings = new ChannelRouterSettings().deserialize(settings); switch (routeType) { case RouteType.Main: if (input) { @@ -385,7 +396,11 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) { } for (let preset of channelRouterPresets) { if (preset.id === presetId) { - model.setChannelRouterSettings(preset.settings); + let newPreset = Object.assign(new ChannelRouterSettings(), preset.settings); + // mark the presets as inserts. + newPreset.mainInserts.nextInstanceId = Pedalboard.MAIN_INSERT_INSTANCE_BASE; + newPreset.auxInserts.nextInstanceId = Pedalboard.AUX_INSERT_INSTANCE_BASE; + model.setChannelRouterSettings(newPreset); return; } } @@ -759,7 +774,7 @@ function ChannelRouterSettingsDialog(props: ChannelRouterSettingsDialogProps) { {ChannelSelect(RouteType.Send, 0, true, false)} - {ChannelSelect(RouteType.Send, 1, false, false)} + {ChannelSelect(RouteType.Send, 1, true, false)} diff --git a/vite/src/pipedal/Pedalboard.tsx b/vite/src/pipedal/Pedalboard.tsx index c96f0d0..423640f 100644 --- a/vite/src/pipedal/Pedalboard.tsx +++ b/vite/src/pipedal/Pedalboard.tsx @@ -381,10 +381,10 @@ export class Pedalboard implements Deserializable { static readonly START_CONTROL = -2; // synthetic PedalboardItem for input volume. static readonly END_CONTROL = -3; // synthetic PedalboardItem for output volume. - static readonly MAIN_INSERT_START_CONTROL_ID = Pedalboard.MAIN_INSERT_INSTANCE_BASE + MAX_INSTANCE_ID -2; - static readonly MAIN_INSERT_END_CONTROL_ID = Pedalboard.MAIN_INSERT_INSTANCE_BASE + MAX_INSTANCE_ID -3; - static readonly AUX_INSERT_START_CONTROL_ID = Pedalboard.AUX_INSERT_INSTANCE_BASE + MAX_INSTANCE_ID -2; - static readonly AUX_INSERT_END_CONTROL_ID = Pedalboard.AUX_INSERT_INSTANCE_BASE + MAX_INSTANCE_ID -3; + static readonly MAIN_INSERT_START_CONTROL_ID = Pedalboard.MAIN_INSERT_INSTANCE_BASE + -2 + MAX_INSTANCE_ID; + static readonly MAIN_INSERT_END_CONTROL_ID = Pedalboard.MAIN_INSERT_INSTANCE_BASE + -3 + MAX_INSTANCE_ID; + static readonly AUX_INSERT_START_CONTROL_ID = Pedalboard.AUX_INSERT_INSTANCE_BASE + -2 + MAX_INSTANCE_ID + static readonly AUX_INSERT_END_CONTROL_ID = Pedalboard.AUX_INSERT_INSTANCE_BASE + -3 + MAX_INSTANCE_ID; static readonly START_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#Start"; diff --git a/vite/src/pipedal/PiPedalModel.tsx b/vite/src/pipedal/PiPedalModel.tsx index 569a2e3..d764a5e 100644 --- a/vite/src/pipedal/PiPedalModel.tsx +++ b/vite/src/pipedal/PiPedalModel.tsx @@ -431,9 +431,9 @@ interface MonitorPortOutputBody { } -interface ChannelSelectionChangedBody { +interface ChannelRouterSettingsChangedBody { clientId: number; - jackChannelSelection: JackChannelSelection; + channelRouterSettings: ChannelRouterSettings; } interface RenamePresetBody { clientId: number; @@ -730,10 +730,11 @@ export class PiPedalModel //implements PiPedalModel } else if (message === "onShowStatusMonitorChanged") { let value = body as boolean; this.showStatusMonitor.set(value); - } else if (message === "onChannelSelectionChanged") { - let channelSelectionBody = body as ChannelSelectionChangedBody; - let channelSelection = new JackChannelSelection().deserialize(channelSelectionBody.jackChannelSelection); - this.jackSettings.set(channelSelection); + } else if (message === "onChannelRouterSettingsChanged") { + let channelRouterSettingChangedBody = body as ChannelRouterSettingsChangedBody; + let channelRouterSettings = new ChannelRouterSettings().deserialize( + channelRouterSettingChangedBody.channelRouterSettings); + this.channelRouterSettings.set(channelRouterSettings); } else if (message === "onSnapshotModified") { let { snapshotIndex, modified } = (body as { snapshotIndex: number, modified: boolean }); let snapshots = this.pedalboard.get().snapshots; diff --git a/vite/src/pipedal/SettingsDialog.tsx b/vite/src/pipedal/SettingsDialog.tsx index dc579ee..d008cfc 100644 --- a/vite/src/pipedal/SettingsDialog.tsx +++ b/vite/src/pipedal/SettingsDialog.tsx @@ -519,29 +519,10 @@ const SettingsDialog = withStyles( } handleSelectChannelsDialogResult(channels: string[] | null): void { - if (this.state.jackSettings === null) { return; } - if (channels) { - let newSelection = this.state.jackSettings.clone(); - if (this.state.showInputSelectDialog) { - newSelection.inputAudioPorts = channels; - } else { - newSelection.outputAudioPorts = channels; - } - this.setState({ - jackSettings: newSelection, - showInputSelectDialog: false, - showOutputSelectDialog: false - - }); - this.model.setJackSettings(newSelection); - } else { - this.setState({ - showInputSelectDialog: false, - showOutputSelectDialog: false - - }); - - } + this.setState({ + showInputSelectDialog: false, + showOutputSelectDialog: false + }); } midiSummary(): string { @@ -618,8 +599,10 @@ const SettingsDialog = withStyles( let disableShutdown = this.state.shuttingDown || this.state.restarting; let canKeepScreenOn = this.model.canKeepScreenOn; - let hasAudioConfig = isConfigValid && this.state.jackConfiguration.outputAudioPorts.length >= 1 + let hasAudioConfig = isConfigValid && this.state.jackConfiguration.inputAudioPorts.length >= 1 + && this.state.jackConfiguration.outputAudioPorts.length >= 1; + return (
Channel Routing - { - this.state.jackSettings == null ? "" : - this.state.jackSettings.getAudioInputDisplayValue(this.state.jackConfiguration)} + { + this.state.channelRouterSettings?.getDescription(this.state.jackConfiguration)??""}
+ {/* Old Input and Output selection + this.handleInputSelection()} + disabled={!isConfigValid || this.state.jackConfiguration.outputAudioPorts.length <= 1} + style={{ opacity: !isConfigValid ? 0.6 : 1.0 }} - this.handleInputSelection()} - disabled={!isConfigValid || this.state.jackConfiguration.outputAudioPorts.length <= 1} - style={{ opacity: !isConfigValid ? 0.6 : 1.0 }} - - > - -
- Input channels - { - this.state.jackSettings == null ? "" : - this.state.jackSettings.getAudioInputDisplayValue(this.state.jackConfiguration)} -
-
- this.handleOutputSelection()} - disabled={!isConfigValid || this.state.jackConfiguration.outputAudioPorts.length <= 1} - style={{ opacity: !isConfigValid ? 0.6 : 1.0 }} - > - -
- Output channels - { - this.state.jackSettings == null ? "" : - this.state.jackSettings.getAudioOutputDisplayValue(this.state.jackConfiguration)} -
-
+ > + +
+ Input channels + { + this.state.jackSettings == null ? "" : + this.state.jackSettings.getAudioInputDisplayValue(this.state.jackConfiguration)} +
+
+ this.handleOutputSelection()} + disabled={!isConfigValid || this.state.jackConfiguration.outputAudioPorts.length <= 1} + style={{ opacity: !isConfigValid ? 0.6 : 1.0 }} + > + +
+ Output channels + { + this.state.jackSettings == null ? "" : + this.state.jackSettings.getAudioOutputDisplayValue(this.state.jackConfiguration)} +
+
+ */}
MIDI