Files
soothe2-re/dsp/fn529fe0.hpp
T
Matiq 96816f9921 chain_9_19: add IIR4 generator (FUN_180533340) + integrate in audio path
- Add generate_iir4_coefs() — frequency-dependent warp coefficients from BLOCKMAP:135-150
- Integrate chain_9_19 in process_band_structural via RT_CASC=1 env gate
- chain_9_19 now runs full pipeline: LOG#1→DIVIDE→dc40→FMA→EXP#1→track→warp→LOG#2→IIR4×2→FIR→EXP#2
- IIR4×2 uses double precision (movsd/mulsd per disasm)
- FIR min-phase (52b3cd) enabled
- Canon bridge 1.594 unchanged when RT_CASC=0
- Requires live-dump or ph*.npz capture for input format calibration
2026-09-02 18:25:14 +03:00

103 lines
4.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <cstddef>
#include <vector>
// Structural transcription of the soothe2 mask-apply mono path
// FUN_180529fe0 (0x5408b8==0), BITEXACT_PLAN step 1. Uses the live-captured
// tables (dsp/rt_mask_tables.*, dsp/rt_weights.*) and the exact step sequence
// from NOTES_LEVEL:820-840 / :237-253.
//
// Unlike the empirical bridge (dsp/framed_model.cpp), this reproduces the real
// reduction/exp2-domain chain:
// scale -> IIR1 -> copy -> IIR2 -> mirror -> blend(0.8 pedestal)
// -> exp2(-level)*blend -> combine/acc -> warp(kBand768*kWarp)
// -> IIR3 x2 -> dry/wet -> (FFT-conv is step 4, separate module)
//
// The IIR/weight tables are indexed 0..N/2 of the INTERNAL grid (N=4096/SR=48000);
// per-bin level is supplied by the caller (level-path), same xv domain as bridge
// (level = am/res) but fed through the structural chain instead of the LUT bridge.
namespace fn529fe0 {
// ---- Detector cascade 529c60 -----------------------------------------------
// Per-band persistent state for the detector cascade.
// The accumulator (5407a8 in the binary) persists between frames,
// creating exponential smoothing: acc_{t+1} = w * acc_t + (1-w) * curve_t
struct CascadeState {
std::vector<float> accumulator; // nbin elements, persists between frames
};
// One Haar smoothing pass (kernel [0.25, 0.5, 0.25]).
// Decoded from 529c60 Haar loop (BLOCKMAP 24mm14, lines 35-74).
// Net effect: b[i] = 0.25*b[i-1] + 0.5*b[i] + 0.25*b[i+1] (wavelet smooth).
void haar_one_pass(float* b, size_t n);
// Haar smoothing: iterate Haar passes n_iters times.
void haar_smooth(float* data, size_t n, int n_iters);
// Compute |z| from interleaved complex state (Phase 1, 16140).
// in: interleaved [re0,im0,re1,im1,...], out: [mag0,mag1,...]
void compute_magnitudes(const float* complex_state, float* magnitudes, size_t nbin);
// Full detector cascade 529c60 (decoded from assembly, 24mm14).
//
// Pipeline:
// 1. compute_magnitudes: complex → |z| (skipped if is_magnitude=true)
// 2. haar_smooth: |z| → smoothed curve
// 3. peak = max(curve)
// 4. sin_peak = sin(param*30 - 90) * 0.115129 * peak
// 5. curve[i] = max(curve[i], sin_peak)
// 6. w = -log10(pow(50, ratio*0.001) * ratio*0.001)
// 7. acc[i] = acc[i] * w + curve[i] * (1-w)
// 8. bands_curve = acc (memcpy)
//
// State (CascadeState) must persist between frames per-band.
// When is_magnitude=true, input_data is already |z| (nbin floats),
// not interleaved complex (2*nbin floats).
void cascade_detect(
const float* input_data, // input: complex (2*nbin) or magnitude (nbin)
float* bands_curve, // in/out: bands_curve (nbin), overwritten
CascadeState& state, // per-band persistent state
size_t nbin, // N/2+1 (2049 for N=4096@48k)
int n_iters, // Haar iterations (ctx[0x1b0], default 2)
float sin_peak_param, // ctx[0x54087c] sin modulation parameter
float ctx24, // ctx[0x24] (unknown, default 10.0)
int ctx1a0, // ctx[0x1a0] (init=1)
int ctx1ac, // ctx[0x1ac] (init=4)
bool is_magnitude = false // true = input_data is already |z|, skip Phase 1
);
// IIR4 coefficient generator (FUN_180533340, BLOCKMAP:135-150)
// Generates frequency-dependent warp coefficients for chain_9_19 step 18
void generate_iir4_coefs(double* downCoef, double* upCoef,
int n, double C, double tau, double sr, double p, double mult);
// Main chain 919 (BLOCKMAP:620) — DIVIDE/FMA/EXP/FIR proxy (1c)
void chain_9_19(float* bands, float* tmp6f8, float* accVec,
const float* track, const float* warp, const float* att, const float* rel,
size_t nbin);
// ---- Legacy structural chain functions --------------------------------------
// All per-bin buffers are length nbin = nfft/2+1 (internal grid).
// IIR stage: y[i] = A[i]*acc + B[i]*x[i]; acc=y (first-order leaky, like leveltrack).
void iir1(float* x, const double* A, const double* B, size_t nbin, double acc0);
// Blend step 6: f6f8[k] = freqaxis[k]*(1-mix) + mix*0.8; out = exp2(-x)*f6f8.
void blend_exp2(float* mask, const float* x, const float* freqaxis,
float mix, size_t nbin);
// Combine step 7 (reduction/exp2 domain): accumulates per-band.
// acc = band - f6f8; += wAtt[mirror]*upper; += wRel[mirror]*lower; += band
// In-place on acc; band and f6f8 are inputs (len nbin, mirrored to full nfft).
void combine_acc(double* acc, const float* band, const float* f6f8,
const float* wAtt, const float* wRel, size_t nfft);
// Warp step 8: mask *= kBand768 * kWarp (two multiplies).
void warp_mask(float* mask, const float* kBand768, const float* kWarp, size_t nbin);
// Dry/wet step 10 (fVar30=1, 0x540888=1 -> identity for default).
void dry_wet(float* mask, float fVar30, float wet, size_t nbin);
} // namespace fn529fe0