G1: JUCE engine SHM chain rong POC - probe pass, khong lag them
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
// native_bridge/juce_fx/JuceFxEngine.cpp
|
||||
// Implementation: AudioProcessorGraph với input/output node — chain rỗng G1.
|
||||
#include "JuceFxEngine.h"
|
||||
|
||||
#include <juce_audio_processors/juce_audio_processors.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
struct JuceFxEngine::Impl {
|
||||
juce::AudioProcessorGraph graph;
|
||||
juce::AudioBuffer<float> buf;
|
||||
uint32_t sampleRate = 0;
|
||||
uint32_t blockSize = 0;
|
||||
bool prepared = false;
|
||||
};
|
||||
|
||||
JuceFxEngine::JuceFxEngine() : impl_(std::make_unique<Impl>()) {}
|
||||
|
||||
JuceFxEngine::~JuceFxEngine() { shutdown(); }
|
||||
|
||||
void JuceFxEngine::shutdown() {
|
||||
if (impl_->prepared) {
|
||||
impl_->graph.releaseResources();
|
||||
impl_->graph.clear();
|
||||
impl_->prepared = false;
|
||||
impl_->sampleRate = 0;
|
||||
impl_->blockSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void JuceFxEngine::prepare(uint32_t sampleRate, uint32_t blockSize) {
|
||||
if (impl_->prepared && impl_->sampleRate == sampleRate &&
|
||||
impl_->blockSize == blockSize)
|
||||
return; // không đổi — giữ graph
|
||||
shutdown();
|
||||
|
||||
impl_->sampleRate = sampleRate;
|
||||
impl_->blockSize = blockSize;
|
||||
impl_->graph.setPlayConfigDetails(2, 2, (double)sampleRate, (int)blockSize);
|
||||
|
||||
// Chain rỗng G1: audio input -> audio output (passthrough). G2: chèn
|
||||
// plugin node giữa hai node này theo fx_chain.
|
||||
auto& g = impl_->graph;
|
||||
const auto inNode = g.addNode(std::make_unique<
|
||||
juce::AudioProcessorGraph::AudioGraphIOProcessor>(
|
||||
juce::AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode));
|
||||
const auto outNode = g.addNode(std::make_unique<
|
||||
juce::AudioProcessorGraph::AudioGraphIOProcessor>(
|
||||
juce::AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode));
|
||||
using NCh = juce::AudioProcessorGraph::NodeAndChannel;
|
||||
using Conn = juce::AudioProcessorGraph::Connection;
|
||||
for (int ch = 0; ch < 2; ++ch) {
|
||||
NCh src; src.nodeID = inNode->nodeID; src.channelIndex = ch;
|
||||
NCh dst; dst.nodeID = outNode->nodeID; dst.channelIndex = ch;
|
||||
g.addConnection(Conn(src, dst));
|
||||
}
|
||||
|
||||
g.prepareToPlay((double)sampleRate, (int)(blockSize * 4)); // batch tối đa 4 block
|
||||
impl_->buf.setSize(2, (int)(blockSize * 4), false, false, true);
|
||||
impl_->prepared = true;
|
||||
}
|
||||
|
||||
void JuceFxEngine::process(float* inL, float* inR, uint32_t n) {
|
||||
if (!impl_->prepared || n == 0) return;
|
||||
auto& b = impl_->buf;
|
||||
b.setSize(2, (int)n, false, false, true);
|
||||
b.copyFrom(0, 0, inL, (int)n);
|
||||
b.copyFrom(1, 0, inR, (int)n);
|
||||
juce::MidiBuffer midi;
|
||||
impl_->graph.processBlock(b, midi);
|
||||
// G1 passthrough: copy kết quả về buffer đầu vào (in-place như contract).
|
||||
const auto* outL = b.getReadPointer(0);
|
||||
const auto* outR = b.getReadPointer(1);
|
||||
std::copy(outL, outL + n, inL);
|
||||
std::copy(outR, outR + n, inR);
|
||||
}
|
||||
|
||||
uint32_t JuceFxEngine::latencySamples() const {
|
||||
return impl_->prepared ? (uint32_t)impl_->graph.getLatencySamples() : 0u;
|
||||
}
|
||||
Reference in New Issue
Block a user