chain_9_19: integrate into audio path with RT_CASC env gate

- Pass track_[b] from FramedDetector to process_band_structural
- chain_9_19 called when RT_CASC=1, otherwise identity (warp path)
- Uses unity track (calibrated via live-dump)
- Canon bridge 1.594 unchanged
- Requires calibration of input format for structural chain
This commit is contained in:
2026-09-02 18:12:10 +03:00
parent 9ed22d3476
commit 2a295af6f3
+21 -8
View File
@@ -64,7 +64,8 @@ static void process_band_structural(
float* mask_out, float* mask_out,
size_t nfft, size_t nfft,
float sample_rate, float sample_rate,
size_t num_bands = 1 size_t num_bands = 1,
float* track = nullptr
) { ) {
const size_t half = nfft / 2; const size_t half = nfft / 2;
const size_t nbin = half + 1; const size_t nbin = half + 1;
@@ -407,6 +408,17 @@ static void process_band_structural(
f6f8[k] = 1.0f * (1.0f - mix) + mix * 0.8f; f6f8[k] = 1.0f * (1.0f - mix) + mix * 0.8f;
} }
// RT_CASC=1: chain_9_19 structural path (BLOCKMAP:620-644)
// Replaces warp + IIR3 with calibrated chain including IIR4×2 + FIR min-phase
static const int casc = getenv("RT_CASC") ? atoi(getenv("RT_CASC")) : 0;
if (casc && track) {
// f6f8 is the blend buffer (step 9b accumulation)
// band_level is the per-band curve (VLAW or LUT output)
// track (from FramedDetector::track_[b]) holds persistent ACC state
fn529fe0::chain_9_19(band_level.data(), f6f8.data(), track,
nullptr, kWarp, kRTAtt, kRTRel, nbin);
}
for (size_t k = 0; k < nfft; k++) { for (size_t k = 0; k < nfft; k++) {
double mm; double mm;
// RT_FIRPOWER=1: FIR-style mask from raw spectrum. // RT_FIRPOWER=1: FIR-style mask from raw spectrum.
@@ -567,17 +579,16 @@ static void process_band_structural_am(
float sample_rate, float sample_rate,
size_t num_bands = 1, size_t num_bands = 1,
const float* casc_curve = nullptr, const float* casc_curve = nullptr,
bool use_cascade = false bool use_cascade = false,
float* track = nullptr
) { ) {
if (use_cascade && casc_curve) { if (use_cascade && casc_curve) {
// Cascade curve IS the level. Pass with res=1.0 to skip am/res division.
// Create a dummy res array of all 1.0
static thread_local std::vector<float> one_res; static thread_local std::vector<float> one_res;
size_t nbin = nfft/2 + 1; size_t nbin = nfft/2 + 1;
one_res.assign(nbin, 1.0f); one_res.assign(nbin, 1.0f);
process_band_structural(casc_curve, one_res.data(), band, mask_out, nfft, sample_rate, num_bands); process_band_structural(casc_curve, one_res.data(), band, mask_out, nfft, sample_rate, num_bands, track);
} else { } else {
process_band_structural(am, res, band, mask_out, nfft, sample_rate, num_bands); process_band_structural(am, res, band, mask_out, nfft, sample_rate, num_bands, track);
} }
} }
@@ -771,11 +782,13 @@ void FramedDetector::processFrame(const std::complex<double>* spectrum, float* m
// (twin response already baked into cascade output). // (twin response already baked into cascade output).
process_band_structural_am(am_.data(), res_[b].data(), bands_[b], process_band_structural_am(am_.data(), res_[b].data(), bands_[b],
band_mask.data(), nfft_, sample_rate_, band_mask.data(), nfft_, sample_rate_,
bands_.size(), casc_curve.data(), true); bands_.size(), casc_curve.data(), true,
track_[b].data());
} }
} else { } else {
process_band_structural(am_.data(), res_[b].data(), bands_[b], process_band_structural(am_.data(), res_[b].data(), bands_[b],
band_mask.data(), nfft_, sample_rate_, bands_.size()); band_mask.data(), nfft_, sample_rate_, bands_.size(),
track_[b].data());
} }
} }
for (size_t k = 0; k <= half; k++) { for (size_t k = 0; k <= half; k++) {