Phase 4+5: WebAudio I/O shim + verify DAW checklist — live=export, order, fader, PDC, smoke
This commit is contained in:
@@ -205,6 +205,23 @@ public:
|
||||
}
|
||||
bool setParam(const std::string& key, double value) override {
|
||||
if (key == "amount") { amount_ = value / 100.0; rebuild(); return true; }
|
||||
if (key.compare(0, 4, "band") == 0) {
|
||||
const size_t us = key.find('_', 4);
|
||||
if (us != std::string::npos && us > 4) {
|
||||
const int idx = std::atoi(key.c_str() + 4);
|
||||
const std::string field = key.substr(us + 1);
|
||||
if (idx >= 0 && idx < (int)bands_.size()) {
|
||||
Band& b = bands_[idx];
|
||||
if (field == "freq") b.freq = value;
|
||||
else if (field == "gain") b.gain = value;
|
||||
else if (field == "q") b.q = value;
|
||||
else if (field == "active") b.active = (value != 0.0);
|
||||
else return false;
|
||||
rebuild();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
|
||||
@@ -1144,6 +1144,12 @@ struct RealtimeFxChain::Impl {
|
||||
};
|
||||
struct Chain { std::vector<Entry> entries; };
|
||||
|
||||
// SET_PARAM chờ chain swap (setParam tới trước setChain): worker áp sau
|
||||
// khi swap — không mất param race lúc khởi động.
|
||||
struct PendingParam { int slot; std::string key; double value; };
|
||||
std::mutex pmutex_; // guards pending_
|
||||
std::vector<PendingParam> pending_;
|
||||
|
||||
std::mutex mutex_; // guards chain_ / retired_
|
||||
std::shared_ptr<Chain> chain_;
|
||||
std::shared_ptr<Chain> retired_; // dtor deferred to the worker thread
|
||||
@@ -1224,9 +1230,14 @@ void RealtimeFxChain::setParam(int slot, const std::string& key, double value) {
|
||||
if (!impl_) return;
|
||||
std::shared_ptr<Impl::Chain> c;
|
||||
{ std::lock_guard<std::mutex> lk(impl_->mutex_); c = impl_->chain_; }
|
||||
if (!c || slot < 0 || (size_t)slot >= c->entries.size()) return;
|
||||
auto& e = c->entries[(size_t)slot];
|
||||
if (e.bfx) e.bfx->setParam(key, value);
|
||||
if (c && slot >= 0 && (size_t)slot < c->entries.size()) {
|
||||
auto& e = c->entries[(size_t)slot];
|
||||
if (e.bfx) e.bfx->setParam(key, value);
|
||||
return;
|
||||
}
|
||||
// Chain chưa swap (SET_PARAM tới trước setChain) — stash, worker áp sau swap.
|
||||
std::lock_guard<std::mutex> lk(impl_->pmutex_);
|
||||
impl_->pending_.push_back({slot, key, value});
|
||||
}
|
||||
|
||||
uint64_t RealtimeFxChain::chainGen() {
|
||||
@@ -1325,6 +1336,16 @@ void RealtimeFxChain::Impl::workerLoop() {
|
||||
retired_ = std::move(chain_); // old chain destroyed on THIS thread
|
||||
chain_ = std::move(next);
|
||||
}
|
||||
{
|
||||
// Áp param chờ (đăng ký trước khi chain tồn tại).
|
||||
std::lock_guard<std::mutex> lk(pmutex_);
|
||||
for (const auto& p : pending_) {
|
||||
if (p.slot < 0 || (size_t)p.slot >= chain_->entries.size()) continue;
|
||||
auto& e = chain_->entries[(size_t)p.slot];
|
||||
if (e.bfx) e.bfx->setParam(p.key, p.value);
|
||||
}
|
||||
pending_.clear();
|
||||
}
|
||||
gen_.fetch_add(1, std::memory_order_release); // loop báo lại latency
|
||||
}
|
||||
#ifdef _WIN32
|
||||
|
||||
Reference in New Issue
Block a user