fix(fxrt): toggle VST bypass khong reload plugin - cache instance trong bridge, chain giu slot bypassed, bypass state trong chainKey, poll 100ms + fade-in 512 samples che gap latency
This commit is contained in:
@@ -1244,6 +1244,12 @@ struct RealtimeFxChain::Impl {
|
||||
double sampleRate_ = 44100.0;
|
||||
int32_t blockSize_ = 256;
|
||||
|
||||
// VST3 instance cache: giữ plugin đã load qua các lần buildChain để toggle
|
||||
// bypass không phải load lại từ disk (tránh delay dry->wet). Key = path + #occ.
|
||||
std::map<std::string, std::shared_ptr<Vst3Fx>> cache_;
|
||||
std::map<std::string, std::string> lastPreset_; // preset b64 da ap (tranh ap lai)
|
||||
std::map<std::string, int> occ_; // so lan xuat hien cua path trong chain
|
||||
|
||||
std::shared_ptr<Chain> buildChain(const std::string& json);
|
||||
void workerLoop();
|
||||
};
|
||||
@@ -1332,12 +1338,13 @@ std::vector<uint32_t> RealtimeFxChain::entryLatencies() {
|
||||
if (!c) return out;
|
||||
out.reserve(c->entries.size());
|
||||
for (const auto& e : c->entries)
|
||||
out.push_back(e.fx ? (uint32_t)e.fx->latencySamples() : 0u);
|
||||
out.push_back((!e.bypass && e.fx) ? (uint32_t)e.fx->latencySamples() : 0u);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::shared_ptr<RealtimeFxChain::Impl::Chain> RealtimeFxChain::Impl::buildChain(const std::string& json) {
|
||||
auto chain = std::make_shared<Chain>();
|
||||
occ_.clear(); // key theo vị trí slot trong CHAIN NÀY — reset mỗi build
|
||||
json_parse_result_s pres = {};
|
||||
json_value_s* root = json_parse_ex(json.data(), json.size(), json_parse_flags_default,
|
||||
nullptr, nullptr, &pres);
|
||||
@@ -1373,21 +1380,42 @@ std::shared_ptr<RealtimeFxChain::Impl::Chain> RealtimeFxChain::Impl::buildChain(
|
||||
if (path.empty()) continue;
|
||||
Entry ent;
|
||||
ent.bypass = memberBool(o, "bypass", false);
|
||||
const std::string preset = memberString(o, "preset_b64", "");
|
||||
// Key ổn định theo vị trí slot: đếm MỌI lần path xuất hiện (kể cả
|
||||
// bypassed) — toggle bypass không đổi key → không reload nhầm instance.
|
||||
const std::string ckey = path + "#" + std::to_string(occ_[path]++);
|
||||
if (!ent.bypass) {
|
||||
auto fx = std::make_shared<Vst3Fx>();
|
||||
if (fx->load(path, sampleRate_, blockSize_)) {
|
||||
const std::string preset = memberString(o, "preset_b64", "");
|
||||
if (!preset.empty()) {
|
||||
if (fx->applyPreset(preset))
|
||||
std::cerr << "[RealtimeFx] preset applied: " << path << std::endl;
|
||||
auto it = cache_.find(ckey);
|
||||
if (it != cache_.end()) {
|
||||
ent.fx = it->second; // đã load: reuse ngay, khong reload
|
||||
const std::string last = lastPreset_[ckey];
|
||||
if (!preset.empty() && preset != last) {
|
||||
if (ent.fx->applyPreset(preset))
|
||||
std::cerr << "[RealtimeFx] preset applied (cached): " << path << std::endl;
|
||||
else
|
||||
std::cerr << "[RealtimeFx] preset apply FAILED (default kept): " << path << std::endl;
|
||||
lastPreset_[ckey] = preset;
|
||||
}
|
||||
ent.fx = std::move(fx);
|
||||
if (preset.empty()) lastPreset_[ckey] = "";
|
||||
}
|
||||
else {
|
||||
std::cerr << "[RealtimeFx] load failed — slot bypassed: " << path << std::endl;
|
||||
ent.bypass = true;
|
||||
auto fx = std::make_shared<Vst3Fx>();
|
||||
if (fx->load(path, sampleRate_, blockSize_)) {
|
||||
if (!preset.empty()) {
|
||||
if (fx->applyPreset(preset))
|
||||
std::cerr << "[RealtimeFx] preset applied: " << path << std::endl;
|
||||
else
|
||||
std::cerr << "[RealtimeFx] preset apply FAILED (default kept): " << path << std::endl;
|
||||
}
|
||||
ent.fx = fx;
|
||||
cache_[ckey] = fx;
|
||||
lastPreset_[ckey] = preset;
|
||||
}
|
||||
else {
|
||||
std::cerr << "[RealtimeFx] load failed — slot bypassed: " << path << std::endl;
|
||||
ent.bypass = true;
|
||||
occ_[path]--; // khong dem lan that bai
|
||||
}
|
||||
}
|
||||
}
|
||||
chain->entries.push_back(std::move(ent));
|
||||
|
||||
Reference in New Issue
Block a user