Repository navigation
Conformance test vectors, and decisions on note-offs, rounding, duplicate mappings, ranged CCs and timescale - #104
Merged
Merged
Conversation
…t behaviour spec/vectors/ records what the reference implementation does so other front ends (impsy-auv3, impsy-web) can run the same cases. Expected values come from driving the real IO, interaction and dataset code with fakes. Cases that depend on open design questions link #99-#102. Co-Authored-By: Claude Opus 5.5 <[email protected]>
spec/models/ holds a tiny 3-d, 2x16-unit, 5-mixture model with seeded weights. model.json records, per step, the scaled input, raw MDN output, mixture weights/means/stds and which tensor feeds which LSTM state, so other implementations can check they read .tflite files the way IMPSY does. Floats are compared with a per-file tolerance because TFLite kernels differ slightly between CPUs. Co-Authored-By: Claude Opus 5.5 <[email protected]>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved critical pipeline-vector aliasing and moderate WebSocket clipping coverage issues remain.
Review effort: Lite
Findings: 1
Open (3)
What changed in this PR
Adds machine-readable conformance vectors and tests for IMPSY’s MIDI, WebSocket, pipeline, dataset, and TFLite representations.
Changes:
- Adds JSON conformance vectors and a deterministic model fixture.
- Adds generation and validation runners.
- Documents vector usage and repository conventions.
| File | Summary |
|---|---|
tests/test_conformance.py |
Validates committed conformance vectors. |
spec/vectors/websocket_output.json |
Defines WebSocket output cases. |
spec/vectors/websocket_input.json |
Defines WebSocket input cases. |
spec/vectors/pipeline.json |
Defines pipeline timing and model-input cases; contains an unresolved aliasing issue. |
spec/vectors/model.json |
Defines TFLite model behavior cases. |
spec/vectors/midi_output.json |
Defines MIDI output cases. |
spec/vectors/midi_input.json |
Defines MIDI input cases. |
spec/vectors/dataset.json |
Defines dataset conversion cases. |
spec/README.md |
Documents vector formats and usage; model fixture instructions need correction. |
impsy/conformance.py |
Generates conformance vectors; WebSocket clipping coverage is incomplete. |
CLAUDE.md |
Documents the conformance workflow. |
.gitignore |
Allows the committed model directory. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Leaves room for half-precision runtimes (~1.6e-3 error) while still catching reader bugs, which produce errors of 3-5. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…mescale - #99: note-ons with velocity 0 are note-offs and are ignored on MIDI and WebSocket input. WebSocket input now goes through the same decoder as MIDI, so malformed messages are skipped instead of ending the handler. - #100: output values round to nearest (half up) for notes, CCs and CC min/max scaling, instead of ceil. - #102: a message mapped to several dimensions sets all of them as one interaction (callbacks now take a list of indices). On output, note dimensions that share a channel play polyphonically; MidiOutputState replaces the per-channel note-off logic duplicated across the MIDI, serial MIDI and WebSocket servers. - #103: playback feeds the model its own clamped dt; timescale only sets the wait. The step is now InteractionServer.prepare_rnn_playback and has its own vector file, playback.json. Co-Authored-By: Claude Opus 5.5 <[email protected]>
- #105: a CC mapped as [..., min, max] now matches on input; the raw value is clamped to [min, max] and mapped to (raw - min) / (max - min), inverting the output scaling, as impsy-auv3 and impsy-web already do. - Ranged CC output rounds once, round(min + v * (max - min)), instead of rounding to 0-127 first and again after scaling. - The same message can now give different values for different dimensions, so IO callbacks and construct_input_list take a list of (index, value) updates. Co-Authored-By: Claude Opus 5.5 <[email protected]>
construct_input_list edited the previous input vector in place through a view, but that vector could still be waiting in the model's queue. When several messages arrived in one handle() pass, the model received vectors already changed by later events. The pipeline vectors had recorded this as expected; they now match the log rows, and a test checks that. Also, from review: WebSocket output vectors go through send_back_values so clipping is covered, and the README says to copy spec/models/ too. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Closed
This was referenced Sep 26, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Adds
spec/: JSON conformance vectors that record how IMPSY maps input to model input, output back to messages, logs to datasets, and how it reads a.tflitemodel. It also implements the decisions from #99, #100, #102, #103 and #105, so the vectors describe the behaviour we want, not just what the code happened to do.Conformance vectors
spec/vectors/holds 29 cases:midi_input.json/websocket_input.json: messages → the[index, value]updates they make to the input vector, or ignoredmidi_output.json/websocket_output.json: output vectors → messages, including clipping, note-offs and polyphonypipeline.json: timed MIDI bytes → the[dt, x_1..x_n]vectors sent to the model, plus log rowsplayback.json: model outputs → wait time, values played, and the next model inputdataset.json: log lines → training rowsmodel.json: a fixed-weight 3-d TFLite model inspec/models/. For each step it records the scaled input, raw MDN output,pi/mu/stdafter temperatures, which output tensor feeds which LSTM state, and which mixture a given uniform draw selects.impsy/conformance.pydefines the cases and runs them through the realMIDIServer,WebSocketServer,InteractionServer,datasetandTfliteMDRNNcode with fake ports and a scripted clock.tests/test_conformance.pyruns every vector and fails if the committed files are stale.spec/README.mdexplains the format and how impsy-auv3 and impsy-web should vendor the vectors.Behaviour changes
ceil. Configurable velocity is still open and waits on midi note and velocity #98.(index, value)updates.MidiOutputStateinutils.pyreplaces the note-off logic that was duplicated across the MIDI, serial MIDI and WebSocket servers.[..., min, max]now matches on input: the raw value is clamped to[min, max]and mapped to(raw - min) / (max - min), which inverts the output scaling. Ranged output now rounds once,round(min + v * (max - min)), instead of rounding twice. Both match what impsy-auv3 and impsy-web already do.dt;timescaleonly sets the wait. That step is nowInteractionServer.prepare_rnn_playback.docs/config.mddescribes the new note-off, rounding, duplicate-mapping and ranged-CC behaviour.Downstream
As they stand, impsy-auv3 and impsy-web will need these changes to pass: rounding (AUv3 already rounds), velocity-0 handling (AUv3 already skips these), one interaction per message, per-dimension note polyphony, and the unscaled
dtfeedback.Also un-ignores
spec/models/, sincemodelsis in.gitignore.🤖 Generated with Claude Code