feat: integrate MixerEngine into AudioHost real-time audio pipeline

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
This commit is contained in:
2026-06-20 14:06:46 -04:00
parent df5a317ceb
commit 0422c91b4e
2 changed files with 45 additions and 0 deletions
+39
View File
@@ -24,6 +24,7 @@
#include <lv2/atom/atom.h>
#include "SchedulerPriority.hpp"
#include "AlsaSequencer.hpp"
#include "MixerEngine.hpp"
#include "Lv2Log.hpp"
@@ -535,6 +536,10 @@ private:
std::vector<std::shared_ptr<Lv2Pedalboard>> activePedalboards; // pedalboards that have been sent to the audio queue.
Lv2Pedalboard *realtimeActivePedalboard = nullptr;
// Band-in-a-Box Mixer Engine
std::shared_ptr<MixerEngine> 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<float *> *pInputBuffers;
@@ -1944,6 +1967,22 @@ public:
}
}
virtual void SetMixerEngine(const std::shared_ptr<MixerEngine> &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);