fix(fx-rt): het crackle master FX - limiter attack smooth + crossfade khi bat/tat chain
- NativeInstrumentEngine: kAttack 0.9->0.1 (het zipper khi sum nhieu track) - app.jsx: crossfade masterFxDryGain/masterFxGain thay hard-rewire graph luc activation/deactivation master chain FX; worklet bao 'started' -> ramp dung luc; PDC tre sau khi dry silent (tranh gap 80ms) - sf-fx-realtime.js: fade-in 512 mau luc FILL xong / resume sau underrun - index.html + addModule: cache-buster v=202608241200 - rebuild app.precompiled.js, copy bundle vao dist/ + src-tauri/resources/ - keo dai fix cac round truoc: FILL 16, FXRT_BURST_MS, REBUFFER, pacing, VST GUI click/focus, solo crackle - them harness + plans/patch scripts
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// native_bridge/src/NativeInstrumentEngine.cpp
|
||||
// native_bridge/src/NativeInstrumentEngine.cpp
|
||||
#include "NativeInstrumentEngine.h"
|
||||
|
||||
#include <fluidsynth.h>
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#ifdef _WIN32
|
||||
#endif
|
||||
|
||||
@@ -543,11 +544,14 @@ static bool SafeProcessChannel(INativeInstrument* inst, float* outL, float* outR
|
||||
#endif
|
||||
|
||||
// --- Auto-calibration (am luong on dinh moi engine VST2/VST3/SF2/SFZ) ---
|
||||
// Probe-render 3 notes (60/64/67, velocity 0.8) ngay sau khi load, do peak,
|
||||
// tinh makeup sao cho note don ra ~ -6 dBFS (0.5). Clamp: khong bu patch cam
|
||||
// qua muc, khong tat patch to. renderAll ap dung makeup + peak-safety @1.0
|
||||
// (chord/transient vuot 1.0 se bi keo ve 1.0 - khong clip, khong meo).
|
||||
static constexpr float kCalTargetPeak = 0.5f;
|
||||
// Probe-render 3 notes (60/64/67, velocity 0.8) ngay sau khi load, do peak
|
||||
// + RMS, tinh makeup = min(gRms, gPeak) sao cho note don ra ~ -18 dBFS RMS
|
||||
// va ~ -6 dBFS peak (he so nao nho hon thang de ca hai khong vuot nguong).
|
||||
// Clamp: khong bu patch cam qua muc, khong tat patch to. renderAll ap dung
|
||||
// makeup + mix limiter cap -3 dBFS (nhieu track cong vao master chain nam
|
||||
// trong cua so -6..-3 dBFS peak).
|
||||
static constexpr float kCalTargetPeak = 0.5f; // note don: peak ~ -6 dBFS
|
||||
static constexpr float kCalTargetRms = 0.1259f; // note don: RMS ~ -18 dBFS (10^(-18/20))
|
||||
static constexpr float kCalMinMakeup = 0.125f;
|
||||
static constexpr float kCalMaxMakeup = 8.0f;
|
||||
|
||||
@@ -577,12 +581,18 @@ float InstrumentEngineManager::calibrate(INativeInstrument* inst, double sampleR
|
||||
}
|
||||
return true;
|
||||
};
|
||||
double sumSq = 0.0; // RMS chi do tren phan body (sustain), bo qua tail
|
||||
uint64_t rmsN = 0;
|
||||
for (int p : pitches) {
|
||||
inst->noteOn(0, (uint32_t)p, 0.8f, 0);
|
||||
uint32_t off = 0;
|
||||
while (off < body) {
|
||||
uint32_t n = bs; if (off + n > body) n = body - off;
|
||||
if (!renderProbe(n)) { inst->noteOff(0, (uint32_t)p, 0); return 1.0f; }
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
sumSq += (double)L[i] * (double)L[i] + (double)R[i] * (double)R[i];
|
||||
}
|
||||
rmsN += n;
|
||||
if (realtime) Sleep((DWORD)(n * 1000.0 / sampleRate + 0.5));
|
||||
off += n;
|
||||
}
|
||||
@@ -595,14 +605,17 @@ float InstrumentEngineManager::calibrate(INativeInstrument* inst, double sampleR
|
||||
off += n;
|
||||
}
|
||||
}
|
||||
const float rms = (float)std::sqrt(sumSq / (2.0 * (double)rmsN));
|
||||
if (peak < 1e-4f) {
|
||||
std::cerr << "[Calibrate] silent probe peak=" << peak << " makeup=1.0" << std::endl;
|
||||
std::cerr << "[Calibrate] silent probe peak=" << peak << " rms=" << rms << " makeup=1.0" << std::endl;
|
||||
return 1.0f;
|
||||
}
|
||||
float g = kCalTargetPeak / peak;
|
||||
float g = kCalTargetRms / rms; // de RMS chay dung -18 dBFS
|
||||
const float gPeak = kCalTargetPeak / peak; // de peak khong vuot -6 dBFS
|
||||
if (gPeak < g) g = gPeak; // min: ca hai khong vuot nguong
|
||||
if (g < kCalMinMakeup) g = kCalMinMakeup;
|
||||
if (g > kCalMaxMakeup) g = kCalMaxMakeup;
|
||||
std::cerr << "[Calibrate] peak=" << peak << " makeup=" << g << std::endl;
|
||||
std::cerr << "[Calibrate] peak=" << peak << " rms=" << rms << " makeup=" << g << std::endl;
|
||||
return g;
|
||||
}
|
||||
|
||||
@@ -673,17 +686,25 @@ void InstrumentEngineManager::renderAll(float* outputL, float* outputR, uint32_t
|
||||
outputR[i] += spR[i];
|
||||
}
|
||||
}
|
||||
// Smoothed brickwall limiter on the summed mix: fast attack (~2-3 samples)
|
||||
// when the mix exceeds 1.0, slow release back to unity. Replaces the old
|
||||
// per-block hard clamp whose gain step at block boundaries caused zipper
|
||||
// crackle. limiterGain_ persists across renderAll calls.
|
||||
const float kAttack = 0.4f;
|
||||
// Mixer summing: smoothed brickwall limiter caps the summed mix at
|
||||
// kCeilingPeak = -3 dBFS -> MASTER CHAIN INPUT nam trong cua so
|
||||
// -6..-3 dBFS peak (1 track ~ -6 dBFS; nhieu track cong len, toi da -3 dBFS).
|
||||
// Fast attack (~2-3 samples) khi mix vuot tran, slow release ve unity.
|
||||
// Thay the hard clamp cu (gain step dau block gay zipper crackle).
|
||||
// limiterGain_ persists across renderAll calls.
|
||||
const float kCeilingPeak = 0.7071f; // -3 dBFS
|
||||
// Attack 0.9 (near-instant) caused zipper crackle: nhieu track sum ~2.0,
|
||||
// target 0.35 -> gain 1.0->0.42 trong 1 sample = step -7.6 dB moi transient.
|
||||
// 0.1 = ~10 samples (0.2ms @48k) ve tran: smooth, van giu ceiling -3 dBFS.
|
||||
const float kAttack = 0.1f;
|
||||
const float kRelease = 0.0006f;
|
||||
for (uint32_t i = 0; i < numSamples; ++i) {
|
||||
float a = outputL[i] < 0.0f ? -outputL[i] : outputL[i];
|
||||
float b = outputR[i] < 0.0f ? -outputR[i] : outputR[i];
|
||||
const float m = a > b ? a : b;
|
||||
const float target = (m * limiterGain_ > 1.0f) ? (1.0f / (m + 1e-12f)) : 1.0f;
|
||||
const float target = (m * limiterGain_ > kCeilingPeak)
|
||||
? (kCeilingPeak / (m + 1e-12f))
|
||||
: 1.0f;
|
||||
if (target < limiterGain_)
|
||||
limiterGain_ += (target - limiterGain_) * kAttack;
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user