From 0422c91b4e0b961c28c633f26fc50668ed7e90f9 Mon Sep 17 00:00:00 2001 From: Shawn Date: Sat, 20 Jun 2026 14:06:46 -0400 Subject: [PATCH] feat: integrate MixerEngine into AudioHost real-time audio pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When SetMixerEngine() is called with a MixerEngine instance, the audio processing thread routes all device input/output channels through the mixer (channel strips → buses → master) instead of the legacy Lv2Pedalboard. Falls back when no mixer engine is set. - Thread-safe via mutex + realtime raw pointer swap (same pattern as existing SetPedalboard) - Preserves existing pedalboard processing — both modes coexist - New ProcessLv2Pedalboard() path when realtimeActiveMixerEngine is non-null uses device buffers directly for multi-channel I/O --- src/AudioHost.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/AudioHost.hpp | 6 ++++++ 2 files changed, 45 insertions(+) diff --git a/src/AudioHost.cpp b/src/AudioHost.cpp index 84d23f7..6ecfaed 100644 --- a/src/AudioHost.cpp +++ b/src/AudioHost.cpp @@ -24,6 +24,7 @@ #include #include "SchedulerPriority.hpp" #include "AlsaSequencer.hpp" +#include "MixerEngine.hpp" #include "Lv2Log.hpp" @@ -535,6 +536,10 @@ private: std::vector> activePedalboards; // pedalboards that have been sent to the audio queue. Lv2Pedalboard *realtimeActivePedalboard = nullptr; + // Band-in-a-Box Mixer Engine + std::shared_ptr currentMixerEngine; + MixerEngine *realtimeActiveMixerEngine = nullptr; + uint32_t sampleRate = 0; uint64_t currentSample = 0; @@ -1197,6 +1202,24 @@ private: PIPEDAL_NON_INLINE void ProcessLv2Pedalboard(size_t nframes) { + // Band-in-a-Box Mixer Engine takes priority over legacy pedalboard + MixerEngine *mixerEngine = this->realtimeActiveMixerEngine; + if (mixerEngine != nullptr) + { + // Route through mixer engine using device input/output buffers + auto &driver = this->audioDriver; + if (driver) { + mixerEngine->process( + driver->DeviceInputBuffers().data(), + (uint32_t)driver->DeviceInputBufferCount(), + driver->DeviceOutputBuffers().data(), + (uint32_t)driver->DeviceOutputBufferCount(), + (uint32_t)nframes + ); + } + return; + } + Lv2Pedalboard *pedalboard = nullptr; std::vector *pInputBuffers; @@ -1944,6 +1967,22 @@ public: } } + virtual void SetMixerEngine(const std::shared_ptr &mixerEngine) + { + std::lock_guard guard(mutex); + this->currentMixerEngine = mixerEngine; + if (active && mixerEngine) + { + // Activate the mixer engine and set it as the realtime processing target. + // The mixer engine takes over from the legacy pedalboard. + this->realtimeActiveMixerEngine = mixerEngine.get(); + } + else if (!mixerEngine) + { + this->realtimeActiveMixerEngine = nullptr; + } + } + virtual void SetBypass(uint64_t instanceId, bool enabled) { std::lock_guard guard(mutex); diff --git a/src/AudioHost.hpp b/src/AudioHost.hpp index a37dc13..c0cc4ad 100644 --- a/src/AudioHost.hpp +++ b/src/AudioHost.hpp @@ -37,6 +37,8 @@ namespace pipedal { + class MixerEngine; // forward declaration for band-in-a-box mode + struct RealtimeMidiProgramRequest; struct RealtimeNextMidiProgramRequest; class PluginHost; @@ -239,6 +241,10 @@ namespace pipedal virtual void SetPedalboard(const std::shared_ptr &pedalboard) = 0; + /// Set the mixer engine for band-in-a-box mode. + /// When set, overrides the legacy pedalboard processing. + virtual void SetMixerEngine(const std::shared_ptr &mixerEngine) = 0; + virtual void SetControlValue(uint64_t instanceId, const std::string &symbol, float value) = 0;