// levelpath.cpp — transcription of FUN_180563440 (LUT curve + band combine) // and FUN_18056e3e0 (twin-mask factory) // // Extracted from: handoff/nls_dasm/f_563440.dis (222 lines) // Constants from: soothe_mem.bin at ImageBase 0x180000000 // // Key addresses: // 0x540000+0x2198 = r13+0x2198 = output accumulator (1024 doubles, stride 0x2000) // 0x540000+0x188 = band config struct (A, B, C, flag, callback) // 0x5408b0 = LUT coefficient table (PRNG state) // 0x540868 = band count (max 6) // 0x540870 = level weight (float) // 0x540874 = level-dependent weight (float) // 0x54087c = band weight (float) // 0x54088c = sharpness weight (float) // 0x540658 = window table (2048 floats, live-captured) // 0x540698 = freq-axis (2049 floats, live-captured) // 0x5406a8 = warp table (2049 floats) // 0x5406b8 = warp exponent (float, = A_FIT) #include #include #include #include // Constants extracted from binary static constexpr float SCALE = 0.0009775171056389809f; // 1/1024 (DAT_1824c3c54) static constexpr float ONE = 1.0f; // DAT_1824c3ea4 static constexpr float TWO = 2.0f; // DAT_1824c41e0 static constexpr float NEG1 = -1.0f; // DAT_1824c4680 static constexpr float HALF = 0.5f; // DAT_1824c3d8c static constexpr float ZERO = 0.0f; // DAT_1824c4140 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) // PRNG state offsets from param_1 static constexpr int PRNG_STATE = 0x2404e0; static constexpr int PRNG_LUT = 0x5408b0; // Band config struct layout (offsets from band_base = param_1 + 0x188) struct BandConfig { float A; // +0x00: start value float B; // +0x04: end value float _pad[2]; float threshold; // +0x0c: threshold (compared to 1.0) uint8_t flag; // +0x10: 0=linear, 1=power-law uint8_t _pad2[3]; float _pad3[15]; void* callback; // +0x50: vtable callback (if non-null, use callback) }; // LUT evaluation for a single bin // x is in [0, 1] range static float eval_lut_bin(float x, const BandConfig* band) { // Path 1: callback exists → use vtable if (band->callback != nullptr) { // TODO: transcribe callback vtable call return x; } // Path 2: power-law (flag != 0 and threshold != 1.0) if (band->flag != 0 && band->threshold != ONE) { float C = band->threshold; // x = 2*x - 1 (center at zero: [-1, 1]) float centered = TWO * x - ONE; if (C == ONE || centered == ZERO) { // fall through to linear } else { // sign(x) * 10^(log10(|x|) / C) float sign = (centered < ZERO) ? NEG1 : ONE; // absolute value: |x| float abs_x = fabsf(centered); // if abs_x > 0: result = sign * exp(log(|x|) * (1/C)) if (abs_x > ZERO) { float log_val = log10f(abs_x); float result = powf(10.0f, log_val / C); centered = sign * result; } // fall through to linear with transformed x x = centered * HALF + HALF; // remap back to [0,1] } } // Path 3: linear interpolation (always applied after transform) float slope = band->B - band->A; return slope * x + band->A; } // FUN_180563440: LUT curve evaluation for 1024 bins // r13 = context pointer (param_1) // Reads: band config at r13+0x188 (one per band) // Writes: output at r13+0x198 (1024 doubles, stride 8) void lut_curve_eval(void* ctx, int bin_start, int bin_end) { auto* base = static_cast(ctx); int band_count = *reinterpret_cast(base + 0x540868); if (band_count <= 0) { // Initialize with default 0x800 bins band_count = 0x800; // 2048? or 1024? } // Output pointer: r13+0x198 double* output = reinterpret_cast(base + 0x198); // Evaluate LUT curve for each bin (0x400 = 1024 iterations) for (int bin = 0; bin < 0x400; bin++) { float x = static_cast(bin) * SCALE; x = fminf(fmaxf(x, ZERO), ONE); // clamp to [0, 1] BandConfig* band = reinterpret_cast(base + 0x188); float result = eval_lut_bin(x, band); // Store as double-precision (line 196: cvtss2sd + movsd [rsi]) output[bin] = static_cast(result); } } // 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) void twin_mask_factory(void* ctx, int band_idx, int n_bins) { auto* base = static_cast(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 } // 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) { auto* base = static_cast(ctx); int band_count = *reinterpret_cast(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(base + 0x2198 + ch * 0x2000); for (int bin = 0; bin < n_bins; bin++) { acc[bin] = ONE - acc[bin]; } } } // FUN_180529fe0: coefficient setup (from decomp_funs.txt) // Generates per-band coefficients via PRNG, applies depth scaling // This is the vtable method for Soothe2Module void coefficient_setup(void* ctx, int band_idx, int param3, int param4) { auto* base = static_cast(ctx); // Lock (atomic flag at 0x2404dc) uint32_t* lock = reinterpret_cast(base + 0x2404dc); // LOCK(); *lock |= 1; UNLOCK(); // simplified // PRNG state update (LCG) int32_t state = *reinterpret_cast(base + PRNG_STATE); state = (state + 0x3cdca) & 0x7fffffff; *reinterpret_cast(base + PRNG_STATE) = state; // Load LUT coefficients float* lut_table = reinterpret_cast(base + PRNG_LUT); float coeff0 = lut_table[state]; float coeff1 = lut_table[state + 1]; // Generate 6 coefficient pairs // Each pair: (coeff_i * scale + offset) * global_scale float acc = ZERO; for (int i = 0; i < 3; i++) { state = (state + 0x140236 + i * 0x10d56) & 0x7fffffff; float a = lut_table[state]; float b = lut_table[state + 1]; acc += a * b; } // Normalize float normalized = acc / static_cast(param3); // Apply depth scaling: powf(normalized, depth) float depth = *reinterpret_cast(base + 0x2c); float depthScaled = powf(normalized, depth); // Store result *reinterpret_cast(base + 0x54088c) = depthScaled; // Apply sharpness weight float sharpness = *reinterpret_cast(base + 0x540870); depthScaled *= sharpness; // Invert: gain = 1 - mask *reinterpret_cast(base + 0x54088c) = ONE - depthScaled; }