P2.5: decode twin-mask factory (FUN_18056e3e0 = constant fill 2π/(count·SR)) + band LUT apply (FUN_180563a60: level->gain t^γ/power-law); implement in levelpath.cpp, levelpath_check ALL OK

This commit is contained in:
2026-08-20 01:23:22 +03:00
parent a49e35dc25
commit d3db772121
5 changed files with 142 additions and 24 deletions
+51 -24
View File
@@ -34,6 +34,9 @@ static constexpr float DEPTH_SCALE = 4.0f; // DAT_1824c4334
static constexpr float DB_CONV = 8.68588924407959f; // 20/ln(10) (DAT_1824c43e0)
static constexpr float FLOOR_DB = -6.907755374908447f; // ln(0.001) (DAT_1824c4704)
static constexpr float FLOOR_LIN = 0.001f; // exp(FLOOR_DB)
static constexpr double TWO_PI = 6.283185307179586; // DAT_1824c4248 (2π, twin-mask factory)
static constexpr float SCALE_1024 = 0.0009765625f; // 1/1024 (DAT_1824c3c50, band LUT apply)
static constexpr float CONST_5 = 5.0f; // DAT_1824c4230 (AudioProcessingModule ctor)
// PRNG state offsets from param_1
static constexpr int PRNG_STATE = 0x2404e0;
@@ -96,35 +99,59 @@ void lut_curve_eval(void* ctx) {
}
// FUN_18056e3e0: twin-mask factory
// Creates per-band mask by applying twin resonance to the LUT curve
// band_count = number of bands (max 6)
// N = 1024 (FFT size for LUT evaluation)
// Output stride: 0x2000 (8192 bytes = 1024 doubles)
// DECODED (decomp_funs2.txt:7988 + f_56e3e0.dis): fills the 0x400-bin mask
// with a SINGLE scalar s = 2π / (count·SR), where
// count = [ctx+0x240080] (int), SR = [ctx+0x24] (float, internal SR).
// NOT a per-bin twin resonance — a constant fill (the "twin" shape enters
// elsewhere via the LUT curve FUN_180563440). Output mask stride 0x2000/band.
void twin_mask_factory(void* ctx, int band_idx, int n_bins) {
auto* base = static_cast<uint8_t*>(ctx);
// Calls twin evaluation for each bin
// TODO: transcribe the full loop from disassembly
// The factory applies the band's resonance shape to the LUT curve
int count = *reinterpret_cast<int*>(base + 0x240080);
float sr = *reinterpret_cast<float*>(base + 0x24);
double s = TWO_PI / (static_cast<double>(count) * static_cast<double>(sr));
float* mask = reinterpret_cast<float*>(base + 0x4198 + band_idx * 0x2000);
for (int i = 0; i < 0x400; i++) {
mask[i] = static_cast<float>(s);
}
}
// FUN_180563a60: band combine
// Combines 6 band masks into final per-bin gain
// Stereo: max 2 channels, output stride per band = 0x2000
// Pattern: gain = 1.0 - sum(band_masks)
void band_combine(void* ctx, int n_channels, int n_bins) {
// FUN_180563a60: band LUT apply (level -> gain). DECODED (decomp_funs2.txt:8975 + f_563a60.dis).
// For each of 6 bands and 0x400 bins:
// level_dB = 20·log10(mask[band][bin]) (logf · 8.6859)
// level_axis[bin] = bin·(1/1024) (SCALE_1024)
// t = clamp((dB A)/(B A), 0, 1) (BandConfig ctx+0x180: A,B,gamma,flag)
// if gamma == 1.0: val = t
// elif flag == 0 (linear): val = t^gamma (powf, NOT 1/gamma)
// else (power-law): val = 0.5·(1 + sign(2t1)·|2t1|^gamma)
// level_axis[bin+1] = val (pairs level, gain)
// NOTE: this is the INVERSE curve of FUN_180563440 (which uses x^(1/γ)).
void band_lut_apply(void* ctx) {
auto* base = static_cast<uint8_t*>(ctx);
int band_count = *reinterpret_cast<int*>(base + 0x540868);
if (band_count > 6) band_count = 6;
// Output accumulator at r13+0x2198
// Each band's mask is at r13+0x2198 + band_idx * 0x2000
for (int ch = 0; ch < n_channels; ch++) {
// For each bin: sum all band contributions
// Then invert: gain = 1.0 - sum
double* acc = reinterpret_cast<double*>(base + 0x2198 + ch * 0x2000);
for (int bin = 0; bin < n_bins; bin++) {
acc[bin] = ONE - acc[bin];
float* bandcfg = *reinterpret_cast<float**>(base + 0x180);
float A = bandcfg[0];
float B = bandcfg[1];
float gamma = bandcfg[3];
float flag = bandcfg[4];
double* mask = reinterpret_cast<double*>(base + 0x4198);
for (int band = 0; band < 6; band++) {
double* m = mask + band * 0x400;
float* level_gain = *reinterpret_cast<float**>(base + 0xe0 + band * 0x18);
for (int bin = 0; bin < 0x400; bin++) {
float db = logf(static_cast<float>(m[bin])) * DB_CONV;
level_gain[bin * 2] = static_cast<float>(bin) * SCALE_1024;
float t = (db - A) / (B - A);
t = std::max(ZERO, std::min(ONE, t));
float val = t;
if (gamma != ONE) {
if (flag == ZERO) {
val = powf(t, gamma);
} else {
float u = TWO * t - ONE;
float sgn = (u < ZERO) ? NEG1 : ONE;
val = HALF * (ONE + sgn * powf(fabsf(u), gamma));
}
}
level_gain[bin * 2 + 1] = val;
}
}
}