Files
Matiq 25cf786c54 Initial commit: soothe2 RE workspace + roadmap
- Инфраструктура: RTTI-дампы (rtti_dsp/full.json), декомпиляции DSP-классов (decomp_*.txt),
  Ghidra-скрипты (Dump*.java, ImportRtti*.java, Diag.java), depthcurve/curve_fits LUT.
- Поведенческая модель sim_v5.py + sim.py (RMSE ~0.3dB), утилиты (measure, tt_sweep, patchparam,
  sweep, harness_*, verify_sim).
- summary.md + roadmap.md (контракт из manual M1-M12, топология пайплайна из OCR, фазы A-C).
- pipeline_ocr.txt: OCR диаграммы Appendix A (mid/side ручка, trim/mix/bypass порядок).
2026-08-16 18:54:40 +03:00

63 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Patch a soothe2 PARAM value inside an RPP's base64 state block.
Usage: patchparam.py <in.rpp> <out.rpp> param=value [param=value...]
Value formatting: %16 params (depth, band freq/q/sens/balance, offset etc)
need %.16f; short params (selectivity, mix, mode, oversample, resolution,
attack, band on/balance?) use 'X.0'. Append '!' to force %.16f, e.g.
depth=0.0! to guarantee full precision.
"""
import re, sys, base64
def fmt(val: float, force16: bool):
if force16:
return '%.16f' % val
s = repr(val)
if '.' not in s:
s += '.0'
if '.' in s and float(s) == int(float(s)) and len(s.rstrip('0').rstrip('.')) <= 4:
return s.rstrip('0').rstrip('.') if '.' in s else s
return '%.16f' % val
def main():
src, out = sys.argv[1], sys.argv[2]
params = {}
for a in sys.argv[3:]:
if a in ('-f16',):
continue
k, v, f16 = a.split('=', 1)[0], a.split('=', 1)[1], '!' in a
params[k] = (float(v.rstrip('!')), f16)
s = open(src, encoding='utf8', errors='replace').read()
i = s.find('PpeX')
if i < 0:
i = s.find('VkMy')
if i < 0:
sys.exit('no state block found')
j = s.find('>', i)
if j < 0:
sys.exit('malformed state block')
block = s[i:j]
raw = bytearray(base64.b64decode(block))
txt = raw.decode('latin-1')
n = 0
for pm in re.finditer(r'(<PARAM id="([^"]*)" value=")[^"]*(")/>', txt):
did = pm.group(2)
if did in params:
val, f16 = params[did]
txt = txt[:pm.start()] + pm.group(1) + fmt(val, f16) + pm.group(3) + '/>' + txt[pm.end():]
n += 1
if n != len(params):
print(f'warning: patched {n}/{len(params)} params')
raw = txt.encode('latin-1')
enc = base64.b64encode(raw).decode('ascii')
line_start = s.rfind('\n', 0, i) + 1
indent = s[line_start:i]
wrapped = '\n'.join(indent + enc[i:i+128] for i in range(0, len(enc), 128))
jline = s.rfind('\n', 0, j) + 1
gt_indent = s[jline:j]
s = s[:line_start] + wrapped + '\n' + gt_indent + s[j:]
open(out, 'w', encoding='utf8').write(s)
print(f'{out}: patched {n} params')
if __name__ == '__main__':
main()