Repository navigation
Add note_velocity and pitch_bend mapping types; don't resend unchanged CCs - #108
Merged
Merged
Conversation
A note_velocity dimension pairs with the note_on dimensions on its channel: a note-on sets both as one interaction, and on output notes take their velocity from it (never 0). ["note_on", ch, velocity] sets a fixed output velocity. pitch_bend maps the 14-bit pitch bend message to [0, 1], matching impsy-auv3, and gets a /pitchbend/ websocket message. Adds conformance cases for all of these and bumps SPEC_VERSION to 0.2.0. Refs #98 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_016oUxTsghWZWfnCnnkKcuNv
Closed
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
No unresolved review issues were identified.
Review effort: Lite
Findings: None
What changed in this PR
Adds MIDI note_velocity, fixed-velocity note, and pitch_bend mapping support across runtime handling, WebSocket transport, UI labels, documentation, tests, and conformance vectors.
Changes:
- Adds velocity-aware MIDI note and pitch-bend input/output handling.
- Adds WebSocket support and realtime labels.
- Updates documentation, tests, and specification vectors.
| File | Reviewed changes |
|---|---|
tests/test_webui.py |
Realtime label tests |
tests/test_utils.py |
Mapping behavior tests |
tests/test_impsio.py |
WebSocket tests |
spec/vectors/websocket_output.json |
WebSocket output vectors |
spec/vectors/websocket_input.json |
WebSocket input vectors |
spec/vectors/playback.json |
Specification version updates |
spec/vectors/pipeline.json |
Pipeline conformance vectors |
spec/vectors/model.json |
Specification version updates |
spec/vectors/midi_output.json |
MIDI output vectors |
spec/vectors/midi_input.json |
MIDI input vectors |
spec/vectors/dataset.json |
Specification version updates |
impsy/web_interface.py |
Realtime labels |
impsy/utils.py |
MIDI mapping and conversion logic |
impsy/impsio.py |
WebSocket pitch-bend transport |
impsy/conformance.py |
Conformance cases and version |
docs/config.md |
Mapping and WebSocket documentation |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
MidiOutputState skips a CC or pitch bend when it's the same MIDI value as the last one sent to that channel (and controller). Notes are always sent. Disconnecting (all notes off) forgets the values, and so does a new WebSocket client connecting, so they're resent on the next step. Two existing conformance cases change (a repeated CC is no longer sent), so SPEC_VERSION goes to 1.0.0. Fixes #110 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_016oUxTsghWZWfnCnnkKcuNv
This was referenced Sep 26, 2026
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.
Implements the design in #98.
["note_velocity", channel]note_ondimensions on its channel tonote/127and thenote_velocitydimensions on its channel tovelocity/127, as one update (one model input, one log row). Velocity-0 note-ons are still note-offs and change nothing.note_velocitydimension there, asmax(1, round(v * 127)), so it never sends a velocity-0 note-off. Polyphonic note dimensions on a channel share it.["note_on", channel, velocity]: a fixed output velocity, clamped to 1–127. Anote_velocitydimension on the same channel overrides it. On input it behaves like["note_on", channel]. Without the third element, velocity stays at 127.["pitch_bend", channel]: the value israw / 16383for the 14-bit valueraw(0–16383, centred at 8192) on input, andround(v * 16383)on output. This matches what impsy-auv3 and impsy-web already do. Over WebSocket it's/channel/{ch}/pitchbend/{raw}.Don't resend unchanged CC and pitch bend values (#110). Each output step used to send every CC and pitch bend. Now a CC or pitch bend is skipped when it's the same MIDI value as the last one sent to that channel (and controller). Notes are always sent. The remembered values are cleared on disconnect and when a new WebSocket client connects, so the next step sends everything. This rule has no time window, so it's deterministic and the vectors can describe it. impsy-auv3 instead dedups per dimension within a configurable time window, and should be brought into line with this.
Other changes:
Vel chNandPB chN.docs/config.mddocuments the new types and the WebSocket message.midi_input,midi_output,websocket_input,websocket_outputandpipeline.SPEC_VERSIONgoes to 1.0.0, because dedup changes two existing cases:note_and_cc_encodingandwebsocket_outputno longer repeat a CC whose value didn't change. There's also a newunchanged_cc_and_pitch_bend_not_resentcase.Follow-ups in the other repos: impsy-auv3 and impsy-web need a "Note velocity" type, the fixed-velocity form, the dedup rule, and to pass the new vectors. impsy-auv3's config parser currently returns nil for unknown types; see the comment on #98.
Refs #98
Fixes #110
🤖 Generated with Claude Code
https://claude.ai/code/session_016oUxTsghWZWfnCnnkKcuNv