Repository navigation
Releases
Releases · JackMechem/open-stomp-lib
v0.6.1
v0.5.1
Added
- Rename user slots without touching their sound:
Device::rename_user_amp(slot, name)and
Device::rename_user_ir(slot, name)(Python too) send only the import's name record (the AMP slot-info write,
the IR0x09name write) and re-read the slot. The official app can't rename; confirmed on the pedal (a slot's
sweep response before and after differs by at most 0.09 dB, rig noise; docs/05, "Renaming a slot"). Names are cut
to 31 characters.
Changed
- The activity event for a user AMP slot-info write is "User AMP slot" (it was "User AMP import"), since a rename
sends the same record; like "User IR slot". - README and docs site: the NAM and IR graphs re-measured on hardware in one session with the official app's, 0.4's
and 0.5's conversions (tools/pedalsim/readme_plots.py <session>, now with a dry-take reference instead of the
Mac rig's calibration); the real-playing comparison is on the README and the site's front page.
v0.5.0
Added
- Documentation site (mdBook,
site/, published to GitHub Pages by.github/workflows/pages.yml): install guides,
both repositories' docs, the NAM / IR analysis with an interactive re-amp comparison, and the API reference.
Changed
nam::optimise: the loss now weights frequencies so each octave counts about the same
(Options::weighting,Weighting::Octave, the new default). The old flat weighting gave the bottom octave
~0.5% of the fit, and imports came out 5–10 dB short at 50–160 Hz. In simulation the low-end error (40–160 Hz)
of the Ampeg SVT-VR Classic (Normal) model drops from 4.9 to 2.1 dB rms and the frequency response error from
2.5 to 1.2 dB; the frequency response improves on all six models tried, the low end on five (docs/05, "Low
end").Weighting::Flatkeeps the old loss;
examplenam_optimise --flat. On hardware, a bass DI re-amped through the pedal against the
model and IR in software: low end 5.2 → 3.8 dB rms, overall tone 3.5 → 2.8 dB (2.1 dB with the IR change below).ir::convert_optimised: the tap fit now covers 30 Hz – 16 kHz instead of 25 Hz – 20 kHz. Cab IRs have next to
nothing above 16 kHz, and matching it cost taps the rest of the range needs: on fifteen Ampeg IRs the 1/3-octave
error of what the pedal plays drops from 2.42 to 2.18 dB rms (better on 13; the two DI recordings get slightly
worse), and the 40–160 Hz error from 3.55 to 2.90 dB.
v0.4.0
Added
- NAM import level normalisation, like NAM plugins:
nam::convert::normalise_levelscales G2 (after the pedal's
saturation, so a pure volume change) so that every model plays at the same level,NORMALISED_LEVEL_DB,
measured withpedal_level_dbon pink noise and calibrated on the pedal to its built-in bass amps (two SVT-VR
models 6 dB apart raw land within 0.2 dB of each other; un-normalised they sat 13–19 dB below the built-in amps). Models span about 17 dB raw; the conversions inherit
the official app's level, which plays models quietly (24–34 dB below their own output). On by default for
Device::import_nam_file;Device::import_nam_file_as(.., normalise), Pythonnam.convert(..., normalise=True)
andDevice.import_nam_file(..., normalise=...).nam::Model::loudness(the file's metadata). Example
nam_level. irmodule: read and write WAV files (Wav: PCM 8–32-bit and float, any channel count), andconvert, the
official app's IR conversion recovered from its native code: files that aren't 48 kHz mono 24-bit are converted
first (first channel, JUCE's resampler,resample_like_app, 24-bit), then the first 2048 samples are reversed and
scaled so the 398 Hz – 3 kHz response is centred on 0 dB (app_gain). Identical to eleven captured imports
(tests/ir_import.rs).Device::import_ir_file(slot, path)converts and uploads, named like the app (first 16
characters). Also a windowed-sincresample. Python:open_stomp.ir,Device.import_ir_file. Examples
ir_check,ir_test_files(designed test IRs,tests/data/ir) andir_capture_check.- The pedal plays only the first 384 taps of an uploaded IR (re-amped probe IRs;
ir::PEDAL_IR_TAPS, docs/05). ir::convert_optimised/Method::Optimised(featurenam): a 384-tap minimum-phase filter fitted to the whole
IR's 1/6-octave response, at the level the app means to give it. On fifteen bass IRs in software, what the pedal
plays is 2.4 dB rms from the full IR against 7.9 dB for the official conversion, which leaves IRs with a delayed
start 35–44 dB too quiet. Confirmed on hardware (re-amped: 2.1 vs 4.8 dB rms, and 5.5 dB vs 16 dB rms plus 46 dB
too quiet for a delayed IR). The default forDevice::import_ir_file(Python too);convert_with,
Device::import_ir_file_with(.., Method::App)for the official conversion, Pythonmethod=, exampleir_compare.
Fixed
- User IR uploads put the slot in data-header byte 0, as the official app does (it was in byte 1, NAM's slot byte,
so only slot 0 was right).upload::Chunk::ir_slot;Reassemblerreports either slot.
v0.3.0
Added
namfeature and module (on by default): load and run Neural Amp Modeler.nammodels (a
pure-Rust port of NeuralAmpModelerCore's WaveNet, plain andSlimmableContainer; matches it to
≤ 3e-5 on its example models, which are now test vectors), andnam::convert, the official
app's NAM → pedal converter: a fundamental/3rd-harmonic tone test and a small-signal linear
response give two minimum-phase FIRs. With the app's own excitation the result matches its
upload to ≤ 0.03 dB; with ours (the default) within ~1–1.5 dB rms, the app's own measurement
noise.Device::import_nam_file(slot, path)converts and uploads. Examplesnam_convert,
nam_render,nam_check. Python:open_stomp.nam,Device.import_nam_file. Confirmed on
hardware: an official and an open conversion of the same bass model sound identical.nam::convert::Measure::Clean(convert_measured; Pythonnam.convert(..., measure="clean")),
experimental: the same converter with a steady-state small-signal measurement instead of the
app's transient-affected one. Re-amp tests on hardware against the real model (Ampeg SVT bass
model): closer mid scoop, top-end roll-off and upper-note distortion than the official
algorithm, but still short on the 63–90 Hz resonance and about 5 dB quieter. Not the default.nam::convert::PEDAL_TAPS,upload_data,pedal_irs: the pedal runs only the first 512 taps
of each uploaded filter (found by re-amping; docs/05).Measure::Cleannow uploads exactly
those taps, with the ignored halves zeroed;Measure::Appkeeps the app's layout.nam::optimiseandMeasure::Optimised, the default forDevice::import_nam_file(about a
minute per model): fit G1/G2 so a simulation of the pedal (y = G2 ⊛ f(G1 ⊛ x), its saturation
curve fitted from re-amp recordings) matches the model on sweeps, tones and pink noise, starting
from the clean conversion. Hand-written gradients, Adam, no ML framework. On hardware (Ampeg SVT
bass model) it scores 6.72–6.85 dB rms error against the real model, against 9.32 for the
official conversion in the same session.Device::import_nam_file_with(.., Measure::App)keeps
the official algorithm (a few seconds). Progress and cancel:convert::convert_optimised,
optimise::optimise_with_progress. Alsooptimise::simulate, examplenam_optimise.
Python:Device.import_nam_file(..., measure="optimised")(default) andnam.convert(..., measure="optimised").nam::convert::official_excitation/find_official_excitation: read the official app's test
signal from the user's own Stomp Manager install (located by fingerprint; no vendor data in the
source). With it the conversion equals the official one (error energy −51 to −93 dB on ten
models). Strictly opt-in:Device::import_nam_fileand everything else never read the app.
Python:nam.official_excitation().uploadmodule: user AMP (NAM, SysEx0x58) and user IR (0x10+0x09) upload framing:
chunking, the 128-byte slot-info record (UserAmpInfo: name, factor), delete, and a
Reassemblerthat turns captured chunks back into floats. Every captured import rebuilds
byte for byte.Device::import_user_amp/delete_user_amp/import_user_irsend the
official app's sequences (2048 finite floats, slots 0–9, elseUploadError). Also in the
Python bindings (open_stomp.upload,Device.import_user_amp…).DeviceStatefollows user AMP imports and deletes (slot names, log events with progress).
Changed
- docs/05: corrected chunk header (plain byte offset + total length, not 8-byte units), the
slot-info record layout, and the app selecting the slot's model before uploading. - docs/05, docs/09: the NAM converter algorithm, recovered from the vendor code and verified stage
by stage: a small-signal best linear approximation and a sine tone test (fundamental and 3rd
harmonic) through the network give two minimum-phase FIRs (Wiener–Hammerstein G1/G2) whose first
1024 taps, reversed, are the upload;factoris always 1.0.
v0.2.0
Added
- Python bindings (
bindings/python,pip install ./bindings/python,import open_stomp):
the whole library through PyO3, mirroring the crate's modules: protocol, catalogue, records,
DeviceState,RequestQueue, capture reader and theDeviceengine. Oneabi3wheel per
platform for Python ≥ 3.9, typed stubs checked withstubtest, GIL released while waiting,
Ctrl-C interrupts blocking calls.DeviceState.feed(update)applies engine updates. Tests
driven by the capture logs,monitor.pyandshell.py(interactive) examples and a Python
guide (docs/11). - The repository is now a Cargo workspace; the crate and the Python package share its version.