Two pieces of the cockpit (#155, #41), both written the same way: resolve by
IDENTITY every time, never cache an address.
tools/bridge/surface.py — THE control-surface tap
-------------------------------------------------
Four tools each spawned their own aseqdump. This morning three of them were
bound to ALSA client 24 (an Arturia KeyStep) instead of 20 (the Launch Control
XL) because a replug had renumbered the clients, and each resolves its port
once, at start. I "fixed" them by moving them to 20:0.
Then PLN replugged again this evening and the numbers SWAPPED BACK:
client 20: 'Arturia KeyStep 32' <- was the LCXL
client 24: 'Launch Control XL' <- was the KeyStep
So the two I fixed are wrong again and the one I called broken is now right.
An address is a lease, not an identity. This module resolves "Launch Control
XL" by name on EVERY respawn, so a replug costs one backoff interval instead of
a silent session. First run against the live rig, with zero configuration:
starting port=None
ok port=24:0
It also keeps the last value of every CC, and — the part that matters — records
`seen: false` distinctly from `value: 0`. An untouched control is what silences
a Tidal stream (a bare "^NN" with no value yields NO EVENTS), so a cockpit that
rendered untouched-as-zero would hide the exact failure it exists to show.
And it does not litter. Three smoke runs of this file each orphaned an
aseqdump to pid 1 — precisely the mess PLN complained about this morning
("i see 4 aseqdumps... you had one job"). try/finally is not enough, because
SIGKILL, OOM and `timeout` all skip it. PR_SET_PDEATHSIG puts the guarantee in
the kernel: the tap dies with its parent however the parent dies.
tools/master-out.py — Ardour Master follows a preference list
-------------------------------------------------------------
PLN: "can we control this tedious routing... ideally theres a tie breaking list
of choice, from uhc to headphones to speakers". Ardour's master does not follow
the PipeWire default sink, so every rig move means re-patching in qjackctl.
Not "route to X" but "route to the best X actually present": UMC -> Headphones
-> Speakers, matched as substrings of the node name so serial numbers and
profile suffixes do not matter.
Two properties make it safe to run mid-set:
* IDEMPOTENT — computes wanted links, diffs against existing, applies only
the delta. Already correct = zero pw-link calls = cannot glitch the audio.
The naive unlink-then-relink is a guaranteed dropout even when nothing
changed.
* EXCLUSIVE BUT NARROW — removes Master links to other sinks (or plugging the
UMC back in gives you doubled output), and touches nothing else. The limit
is a predicate, `_is_ours`, not a good intention: apply() refuses to unlink
any source that is not a Master output.
Verified against KNOWN-BAD states, not just against agreement with reality —
the whole lesson of this session. Ten checks: preference order at each of the
three tiers, the "master stranded on headphones when the UMC appears" case
(2 adds + 2 removes), idempotency (0 and 0), and the guard refusing both a
foreign link in plan() and a foreign source handed straight to apply().
All pass. Live dry-run reports "already correct — 0 changes".
| Name |
Last commit
|
Last update |
|---|---|---|
| .. | ||
| at | Loading commit data... | |
| bridge | Loading commit data... | |
| foundry | Loading commit data... | |
| pulsar-parvagues-hud | Loading commit data... | |
| pvlint | Loading commit data... | |
| tests | Loading commit data... | |
| README.md | Loading commit data... | |
| analyze_samples.py | Loading commit data... | |
| audio-lens.py | Loading commit data... | |
| bank-check.py | Loading commit data... | |
| button_roles.py | Loading commit data... | |
| cheat-sheet.py | Loading commit data... | |
| check-audio-graph.sh | Loading commit data... | |
| check-boot-blocks.py | Loading commit data... | |
| check-boot.sh | Loading commit data... | |
| check-drift.sh | Loading commit data... | |
| check-mix.py | Loading commit data... | |
| check-preload.sh | Loading commit data... | |
| check-tracks.sh | Loading commit data... | |
| control-lens.py | Loading commit data... | |
| deshadow-helpers.py | Loading commit data... | |
| fader-baseline.py | Loading commit data... | |
| fan_check.sh | Loading commit data... | |
| fix-button-roles.py | Loading commit data... | |
| fix-mute-roles.py | Loading commit data... | |
| gen_tokens.py | Loading commit data... | |
| gen_ts_types.py | Loading commit data... | |
| gig-log.py | Loading commit data... | |
| gig-metadata.py | Loading commit data... | |
| gig-up.sh | Loading commit data... | |
| gig_record.sh | Loading commit data... | |
| lcxl-init.py | Loading commit data... | |
| lcxl-leds-watch.service | Loading commit data... | |
| lcxl-leds.py | Loading commit data... | |
| lcxl_grid.json | Loading commit data... | |
| lcxl_grid.py | Loading commit data... | |
| master-out.py | Loading commit data... | |
| migrate-columns.py | Loading commit data... | |
| mock-lcxl.py | Loading commit data... | |
| mute.tidal | Loading commit data... | |
| orphan-orbits.py | Loading commit data... | |
| parvagues-samples.service | Loading commit data... | |
| parvagues-sc-watchdog.service | Loading commit data... | |
| probe-chain.py | Loading commit data... | |
| pvbanks.py | Loading commit data... | |
| rig-pulse.py | Loading commit data... | |
| sample-watcher.py | Loading commit data... | |
| sample_tfidf.py | Loading commit data... | |
| sc-watchdog.sh | Loading commit data... | |
| set-coherence.py | Loading commit data... | |
| setlist.py | Loading commit data... | |
| setlist_samples.py | Loading commit data... | |
| shipowiz.py | Loading commit data... | |
| silent-eval.py | Loading commit data... | |
| solo.tidal | Loading commit data... | |
| surface-columns.py | Loading commit data... | |
| take-lens.py | Loading commit data... | |
| take-master.py | Loading commit data... | |
| take-segments.py | Loading commit data... | |
| tempo-lens.py | Loading commit data... | |
| tidal-remote.py | Loading commit data... | |
| tools.png | Loading commit data... | |
| unmute.tidal | Loading commit data... | |
| unsolo.tidal | Loading commit data... |