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 порядок).
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user