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
  • at
  • lens.py
Find file
BlameHistoryPermalink
  • PLN (Algolia)'s avatar
    feat(pv-at): --track proves every control on a REAL track moves the sound (#74) · ab368180
    PLN's ask, verbatim: "all controls have impact on sound... even the crushes should
    change noticeably". The existing suite proves the RIG works against a fixture;
    this proves a TRACK is wired, which is the thing that bites at 160 BPM when a knob
    turns out to do nothing.
    
        python3 tools/at --track live/.../gimme_acid.tidal --dry-run   # no audio
        python3 tools/at --track live/.../gimme_acid.tidal [--json]
    
    Per control: park at REST, take TWO baselines, probe, restore, judge. Four
    outcomes, not two — MOVED / NO_IMPACT / INCONCLUSIVE / UNMEASURABLE — because a
    swing that does not clearly beat the pattern's own drift is genuinely unknown, and
    calling that a pass is how a green suite comes to mean nothing. NO_SIGNAL is kept
    separate from NO_IMPACT: "nothing was playing" and "the control is dead" have
    different fixes, and conflating them once cost a whole evening chasing SuperDirt.
    
    THE BUG THE FIRST DRY RUN FOUND, which is the real content of this commit
    
    The plan for gimme_acid came back "0 bipolar, no CC 49/50/51 at all" — on a track
    that applies gF1/gF2/gF3 to SIX orbits. gF1/gF2/gF3 are defined in BootTidal.hs,
    not in the track, so lens.py's scan of the .tidal file alone was structurally
    blind to the three DJ FILTERS and to EVERY MUTE in the rig. The controls PLN
    reaches for most were the ones the acceptance test could not see.
    
    Fixed by PARSING BootTidal.hs (parsers-over-copy — it is the source of truth and
    it moves: gF1 was rewired onto gDJF, midiGGlobal was retired hours ago, and a
    hardcoded table would rot into a confidently wrong report). boot_helpers() now
    resolves:
      * `gF1 = gDJF "^49"` -> CC49, and BORROWS its lens from gDJF's body, since
        "gDJF" is not a keyword any table knows and the lpf/hpf evidence sits on two
        separate lines
      * `gM1 = gMask . gMute1` -> composition, inheriting CC41 AND CC73
      * a track's own `let gMute = ...` SHADOWS the boot one, as Tidal does
    Result on gimme_acid: 18 controls -> 22, with 49/50/51 present, bipolar, resting
    at 64 and probing downward. Across the OPAL set: 275 controls, 15-29 per track,
    all three filters resolved in all 13, zero Ardour-owned CCs.
    
    Two parse bugs found and fixed on the way, both by reading the output instead of
    trusting it:
      * `mask "f*16"` was classified as DENSITY. An all-false mask is a MUTE — same
        keyword, opposite lens (rms vs onsets) — and my first all-false test asked
        "does it contain a 1", which the *16 repeat count satisfies. So gMute1/2/3,
        three textually IDENTICAL helpers, came back mute/density/density: rms would
        have been the wrong lens on two of PLN's three mutes, and two working mutes
        would have reported NO_IMPACT.
      * `gM3 = gMask . gMute3` swallowed the Launchpad block that follows it and
        reported CC 7 and CC 9 as mutes, because continuation lines were appended to
        whatever was defined last. A continuation now has to LOOK like one.
    
    SAFETY
    CC93 is added to a new lens.NEVER_PROBE. It arms panic — gPanic gates on "^93", so
    sending it high silences every gPanic'd stream. "Probe every control" plus "one
    control is a kill switch" is how a self-test mutes a rehearsal and gets blamed on
    the rig. It is reported and never swept. CC77-84 stay excluded by construction in
    lens AND re-asserted at the probe; CC77 down is total silence, so belt and braces
    is proportionate there.
    Controls are restored per control, not at exit, so Ctrl-C mid-run is safe. Restore
    goes to Control.rest — 64 for a DJ filter, because djf 0.05 is a ~26 Hz low-pass,
    i.e. silence, and parking one at 0 to get a "baseline" measures silence and then
    calls the track broken (#48).
    
    --dry-run exists deliberately: it prints the plan with no audio and no MIDI, so
    the half that can be checked tonight — which controls were found, which lens each
    gets, what will be sent, what will be restored — is checkable at all. "Built but
    never run" is exactly how the LED work shipped a colour ramp that was never
    called.
    
    TESTS: +79 (22 in test_lens.py, 57 in the new test_track_runner.py), suite
    345 -> 424, all green. Every boot-helper regression above is pinned, including a
    parametrised all-false-mask table with `f*16` in it; each lens is asserted to have
    a floor (2 * max(drift, 0) is zero, so without one any tiny swing looks
    significant on a quiet capture); the probe is asserted to REFUSE all of CC77-84;
    and the dry-run plan is built for all 13 OPAL tracks with the DJ filters asserted
    bipolar-and-resting-at-64 in each.
    
    STATUS: the judgement half is validated. The AUDIO half is built but unrun — it
    needs monitors, and the house is quiet. First thing to run with sound up.
    PLN (Algolia) authored Jul 29, 2026
    ab368180
lens.py 20 KB
EditWeb IDE
×

Replace lens.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.