Skip to content

  • Projects
  • Groups
  • Snippets
  • Help
  • This project
    • Loading...
  • Sign in / Register
T
Tidal
  • Overview
    • Overview
    • Details
    • Activity
    • Cycle Analytics
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Charts
  • Issues 0
    • Issues 0
    • List
    • Board
    • Labels
    • Milestones
  • Merge Requests 0
    • Merge Requests 0
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
    • Charts
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Charts
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • PLN
  • Tidal
  • Repository

Switch branch/tag
  • Tidal
  • tools
  • bridge
  • midistream.py
Find file
BlameHistoryPermalink
  • PLN (Algolia)'s avatar
    perf(bridge): the MIDI monitor had the LED bug's twin — it dropped the NEWEST event · 1c9df100
    Found by sweeping the rest of the gear for #71's bug class, which turned out to have a
    sibling living in the Bridge.
    
    `MidiStream._reader` did `q.put_nowait(ev)` and on `queue.Full` silently `pass`ed. That
    keeps 512 stale events and throws away the one that just happened -- exactly backwards
    for MIDI state, where the newest value IS the truth. A dashboard tab that stalled for
    ~1.3 s at 400 CC/s would fill its queue and then display frozen values for the rest of
    the set, with no error logged anywhere. Same failure shape as the LEDs: nothing breaks,
    it just quietly stops telling you the truth.
    
    Downstream, `_sse_midi` wrote and flushed once per event, so one fader sweep cost ~400
    HTTP flushes a second per open tab, each with its own json.dumps.
    
    Fixed the way the LCXL painter was: drop-OLDEST on a full queue, and batch a frame's
    worth of events into a single write. New `coalesce()` folds the batch on one rule --
    CONTINUOUS controls (CC, pitchbend, aftertouch) are STATE and may be superseded by a
    newer value; NOTES are EVENTS and may never be dropped. That distinction is the whole
    point: a fast monitor that loses a note is strictly worse than a slow one, so the tests
    assert every note survives a flood of 100 controller messages.
    
    Order is preserved by overwriting a superseded value where it stood rather than moving
    it to the end, so the monitor still reads as a timeline. The wire format is unchanged
    (one `data:` line per event), so ui/index.html's onmessage/JSON.parse is untouched.
    
    Also extracted `_fanout` so the drop policy is testable without ALSA. A green test on
    `parse_line` proved nothing about the queue behaviour behind it -- verify the seam.
    
    8 new tests, 32 green in tools/bridge.
    PLN (Algolia) authored Jul 28, 2026
    1c9df100
midistream.py 5.2 KB
EditWeb IDE
×

Replace midistream.py

Attach a file by drag & drop or click to upload


Cancel
A new branch will be created in your fork and a new merge request will be started.