Commit be43aff1 by PLN (Algolia)

gig: 9 of 9 off-map orbits were ghosts, and no Master to fall back on

Corrections and additions to the Thu-24 reconstruction, all from sources
that should have been read first.

The fader claim was wrong on cause: I blamed the LCXL lap reset, but every
one of those journal lines says 'effect knobs -> 0' and '(no CC sent)' —
Tidal params, not Ardour gain. The 2026-08-14 forensics had already settled
it as a faithful save of faders in motion. Same verdict now reached from
the audio side, which is the new part.

Verified rather than assumed: dN == Ardour 'Tidal NN', from BootTidal.hs,
fold-orbits.py and check-mix.py independently. That is what makes the
missing stem d8.

New: all nine off-map orbits were declared by the immediately preceding
track, so #68's ghost mechanism is now measured in audio, with levels —
take_5_drops ran its whole 8m43s under piment_bresilien's orbit 04 at 99%
active. And the answer to 'why no Master to recover from': Master is a bus
Ardour cannot arm, while the out-of-Ardour net gig_record.sh has no unit
and no inventory entry, so nothing ever asserts it.

Dropped: a killed-recorder verdict that was an artifact of reporting on a
sliced log, a laptop-speaker inference the data does not support, and a
13-of-15 peak count that should have been 12 of the 13 captured.
parent b3546c65
......@@ -39,8 +39,17 @@ percussive material is not an optimisation, it is a wrong answer.
- **Orbit 08 was never armed** (`rec-enable value="0"`, alone among 12), and the
control map lists it in all 15 tracks. No file was created — an absent stem,
not a silent one.
- **No MIDI from either recorder.** gig-log bound seq port `133:0` at 00:59 and
never rebound; Ardour's `Keys` wrote 24 files of 26 bytes each.
- **No MIDI at all**: gig-log bound seq port `133:0` at 00:59 and never rebound.
Zero control moves for the whole set. (Ardour's `Keys` track is not a second
chance — nothing routed the board to it.)
- **No Master either.** `Master` is a bus: no playlist, no `rec-enable`. Ardour
cannot arm it. The out-of-Ardour safety net `tools/gig_record.sh` exists, is
item 9 of the RUNBOOK, and has never been started on this machine — no
`recordings/` dir, no systemd unit, no entry in `rig_units.py`.
- **#68 measured in audio for the first time.** Nine orbits sounded off-map;
**9 of 9** were declared by the immediately preceding track. Two at 99% active:
`take_5_drops` ran its whole 8m43s with `piment_bresilien`'s orbit 04 — the
loudest orbit of the night — still underneath it.
## Sel (the shareable learning)
**The lens that saved the night was not built for it.** gig-log has a MIDI lens,
......@@ -54,11 +63,13 @@ first record to the last: Ardour's own transport feedback never once said
Redundancy is not three copies of the good instrument. It is four instruments
that fail differently.
Corollary, learned the same morning: **the session file no longer holds the mix
you played.** Nine of twelve faders read −∞ in `Tidal Live.ardour`, saved at
19:44:41, twenty-six seconds after a surface `lap reset` zeroed the board. The
stems prove those faders were up — orbit 04 sits at a −17 dBFS median and is the
loudest orbit in 13 of 15 tracks. Audit the artifact, not the config.
Corollary, and it closes an old file: **the session save does not hold the mix you
played.** Nine of twelve faders read −∞ in `Tidal Live.ardour` (saved 19:44:41)
while the stems, written post-fader, are loud. `2026-08-14-ardour-inf-forensics.md`
had already ruled out automation and corruption and called it a faithful photograph
of wherever the physical faders were at save time. This is the same verdict reached
from the opposite side — for the first time with the audio to prove the routes were
live. Audit the artifact, not the config.
## Hameçon (hook)
"I forgot to hit record." Ninety-four minutes later the laptop could still name
......@@ -67,7 +78,8 @@ the LEDs.
## Sillage (what it unlocks)
- Mastering can start: 11 stems, 76m19s, t0 = 18:27:41.201, per-orbit levels done.
- Peaks over 0 dBFS on 13 of 15 tracks (worst +7.7) — the limiter was working.
His ear decides whether that is the sound.
- Peaks over 0 dBFS on 12 of the 13 captured tracks (worst +7.7) — the limiter was
working. His ear decides whether that is the sound.
- A REC reminder is now buildable **and** the lens it must not use is identified.
- Two open holes with names: orbit 08's arm, and gig-log's MIDI rebind.
- Three open holes with names: orbit 08's arm, gig-log's MIDI rebind, and
`gig_record.sh` having no unit in the inventory that asserts it.
......@@ -18,6 +18,12 @@ uses audio to guess a name.
track uses. Independent of gig-log; it survived the gig where
gig-log's MIDI lens did not (it had bound port 133:0 at 00:59 and
never rebound, so `cc` is empty for the whole set).
ORBIT NUMBERING, verified not assumed: `dN` is `xfade N . (|< orbit N-1)`
(BootTidal.hs:215-226), fold-orbits.py:166 states "orbit k is played by `dk`",
and check-mix.py's docstring diagnoses "`d9`-`d12` make no sound" as the
`Tidal 09`..`Tidal 12` faders being shut — so LCXL column N == dN == Ardour
stem `Tidal NN`, one-to-one across all three layers.
stems full-resolution 1 s RMS/peak per orbit from the Ardour take. Ground
truth for what actually reached the DAW.
......@@ -27,8 +33,11 @@ measured INSIDE those windows.
TWO READINGS THAT ARE NOT ERRORS
* an orbit MAPPED BUT QUIET — a knob existed, the orbit stayed under the
floor. Same reading as an unresolved sample name: normal, never an error.
* an orbit HEARD OFF-MAP — it played with no knob on the surface. Can also be
a previous pattern still running, so it is reported, not interpreted.
* an orbit HEARD OFF-MAP — it sounded with no knob painted for it. Usually
#68: `dN $ ...` replaces orbit N and says nothing about the others, so
every orbit the outgoing track declares and the incoming one does not keeps
running underneath (see tools/orphan-orbits.py). The `ghost` field says
whether the previous track declared it; that is a mechanism, not a fault.
DECIMATION IS A TRAP HERE. The first pass read 4096 of every 48000 frames and
the window kept landing between hits, so most orbits looked 0% active. Every
......@@ -124,8 +133,8 @@ def stem_levels(stem_dir: Path, take: str) -> tuple[dict[int, dict], float, floa
# ── lenses ───────────────────────────────────────────────────────────────────
def gig_log(log: Path, day: str, lo: str, hi: str):
"""(eval events, rec transitions, session stats) inside the window."""
evals, recs, samples = [], [], []
"""(eval events, rec transitions, 1 Hz samples, MIDI events) in the window."""
evals, recs, samples, midi = [], [], [], []
for line in log.open(errors="replace"):
if not line.strip():
continue
......@@ -146,7 +155,9 @@ def gig_log(log: Path, day: str, lo: str, hi: str):
recs.append(r)
elif k == "s":
samples.append(r)
return evals, recs, samples
elif k in ("cc", "note"):
midi.append(r)
return evals, recs, samples, midi
def surface_loads(day: str, lo: str, hi: str):
......@@ -179,7 +190,7 @@ def db(x: float) -> float:
def build(args) -> dict:
day = args.date
lo, hi = args.window
evals, recs, samples = gig_log(Path(args.log), day, lo, hi)
evals, recs, samples, midi = gig_log(Path(args.log), day, lo, hi)
loads = surface_loads(day, lo, hi)
if not loads:
raise SystemExit("surface lens empty — is lcxl3-driver's journal still there?")
......@@ -241,6 +252,8 @@ def build(args) -> dict:
row["mapped_but_quiet"] = [o for o in s["orbits_mapped"]
if o in orbits and o not in heard]
row["heard_off_map"] = [o for o in heard if o not in s["orbits_mapped"]]
prev = seq[i - 2]["orbits_mapped"] if i > 1 else []
row["ghost_of_previous"] = [o for o in row["heard_off_map"] if o in prev]
row["peak_db"] = max(v["peak_db"] for v in lv.values())
row["loudest_orbit"] = max(lv, key=lambda o: lv[o]["rms_p50_db"])
row["levels"] = lv
......@@ -259,7 +272,7 @@ def build(args) -> dict:
"captured_pct": round(100 * dur / (seq[-1]["end"] - seq[0]["start"])),
"orbits_missing_from_take": missing,
"rec_lens_conflicts": len(conflicts),
"midi_cc_in_window": 0 if not any(r.get("k") == "cc" for r in samples) else None,
"midi_events_in_window": len(midi),
"planned_not_played": [p for p in planned if p not in played],
"played_not_planned": [p for p in played if p not in planned],
"post_set_loads": post,
......@@ -303,6 +316,10 @@ def main() -> int:
print(f" head lost: {out['head_lost_s']//60}m{out['head_lost_s']%60:02d}s")
if out["orbits_missing_from_take"]:
print(f" orbits with NO stem: {out['orbits_missing_from_take']}")
print(f" MIDI events logged during the set: {out['midi_events_in_window']}")
off = sum(len(r.get("heard_off_map") or []) for r in out["tracks"])
gh = sum(len(r.get("ghost_of_previous") or []) for r in out["tracks"])
print(f" orbits heard off-map: {off}, of which #68 ghosts of the previous track: {gh}")
print()
print(table(out))
if out["played_not_planned"]:
......
......@@ -27,6 +27,13 @@ independent, and the audio is only ever *measured* — never used to name a trac
Surface and eval agree to the second on all 15 boundaries, so the timeline below
is not a fusion verdict — it is two witnesses saying the same thing.
**Orbit numbering, verified not assumed.** `dN` is `xfade N . (|< orbit N-1)`
(`BootTidal.hs:215-226`); `tools/fold-orbits.py:166` states "orbit k is played by
`dk`"; and `tools/check-mix.py`'s docstring diagnoses the real 2026-07-27 fault
"`d9`-`d12` make no sound at all" as the `Tidal 09`…`Tidal 12` faders sitting at
−∞. Three layers, one-to-one: **LCXL column N == `dN` == Ardour stem
`Tidal NN`**. That is what makes the missing stem below `d8` and not `d9`.
## Headline
```
......@@ -71,9 +78,32 @@ Per-orbit `active_pct`, median and max RMS, and peak for every window are in
Two readings in that table are **not errors**. *quiet* means a knob existed and
the orbit stayed under the floor — the same reading as an unresolved sample name.
*off-map* means an orbit sounded with no knob painted for it, which can equally be
a previous pattern still running; `piment_bresilien`'s orbit 12 arrives with
`love_first` still in the room, and is reported, not interpreted.
*off-map* is better than that: it is **#68, measured in audio for the first time.**
`dN $ ...` replaces orbit N and says nothing about the others, so every orbit the
outgoing track declares and the incoming one does not keeps running underneath
(`tools/orphan-orbits.py`, confirmed by ear 2026-07-28 and by code, never by
level). Nine orbits sounded off-map across the set, and **9 of 9 were declared by
the immediately preceding track**:
| track | ghost orbit | active | inherited from |
|---|---|---|---|
| `piment_bresilien` | 12 | 25% | `love_first` |
| `take_5_drops` | 04 | **99%** | `piment_bresilien` |
| `take_5_drops` | 09 | 90% | `piment_bresilien` |
| `bain_electrique` | 05 | 66% | `take_5_drops` |
| `bain_electrique` | 12 | 59% | `take_5_drops` |
| `sunny_side_up` | 09 | 33% | `bain_electrique` |
| `oct_16_haunted_house…` | 04 | **99%** | `sunny_side_up` |
| `ete_a_mauerpark` | 07 | 30% | `oct_16_haunted_house…` |
| `force_motrice` | 01 | 56% | `cafe_tiede` |
Zero false positives, zero unexplained off-map orbits. The two 99% rows are the
loud ones: a ghost that plays through **the entire next track**, not a tail.
`take_5_drops` inherited `piment_bresilien`'s orbit 04 — the loudest orbit of the
night — and ran the whole 8m43s with it underneath. `orphan-orbits.py` predicts
these from the setlist before a gig; this is the first time the stems confirm
what it predicts, and at what level.
## What the recording is missing, and why
......@@ -90,19 +120,40 @@ about; the two numbers he did not have are *when* and *how much*.
not a silent stem, an absent one.
That costs something in every single track: the surface lens lists orbit 8 in the
control map of **all 15**. `d8` is `xfade 8 . (|< orbit 7)` (`BootTidal.hs:222`),
Ardour's `Tidal 08` is that orbit's stem, and the gig-log `eval` stream lists
`d8` in every evaluated block of the night. Whatever it was carrying per track is
not recoverable from this take — and cannot be measured, because the Master bus
was not recorded either, so there is no reference to subtract the 11 stems from.
**3. No MIDI, from either recorder.** gig-log's `cc` stream has 145 records, all
between 00:59 and 01:01 the night *before*: it bound sequencer port `133:0` at
startup and never rebound after the board was replugged. That is the known bug
already written down in `TODO_GIG.md` ("gig-log loses its MIDI address and never
looks for it again"). Ardour's `Keys` track wrote `Take104_Keys-1.mid` and
23 others at 26 bytes each — empty files. So **not one fader move or knob turn
from the performance was captured as MIDI.**
control map of **all 15**, and the gig-log `eval` stream lists `d8` in every
evaluated block of the night. Whatever it was carrying per track is not
recoverable from this take.
**And there is no Master to recover it from.** `Master` in that session is a
*bus*: no `audio-playlist`, no `rec-enable` Controllable at all, where every
`Tidal NN` route has both. Ardour cannot arm a bus — recording the mix needs
either an extra audio track fed from Master, or a capture outside Ardour.
The capture outside Ardour **already exists and was not running**:
`tools/gig_record.sh`, "lean, always-on stereo master capture (compressed,
black-box style) … so a take never goes uncaptured" — opus, hourly segments off
the default sink monitor, written since OPAL and item 9 of `RUNBOOK.md`'s
checklist. There is no `recordings/` directory on this machine, so it has never
been started here. It has **no systemd unit and no entry in `tools/rig_units.py`**,
which is exactly the shape of the bug that cost CosmicFest its session log:
a tool that exists, that nothing in the authored inventory knows about, so nothing
asserts it and `gig-up` cannot gate on it.
Had it been running, the missing 17m44s AND orbit 08 would both be recoverable
as a stereo mix — imperfect for mastering, decisive for "what did we play".
**3. No MIDI at all.** gig-log's `cc` stream has 145 records, all between 00:59
and 01:01 the night *before*: it bound sequencer port `133:0` at startup and never
rebound after the board was replugged. That is the known bug already written down
in `TODO_GIG.md` ("gig-log loses its MIDI address and never looks for it again").
**Not one fader move or knob turn from the performance exists as MIDI** — the
count for the whole set is zero.
Ardour's `Keys` track is not a second chance at this: it wrote
`Take104_Keys-1.mid` and 23 others at 26 bytes each, but nothing routed the LCXL
to it. Those are what an armed MIDI track with no keyboard plugged in produces,
not a failed capture. One recorder was meant to catch the surface, and it was the
one that was broken.
What survived instead is the `lcxl3-driver` journal: 89 lines across the gig,
every track load with its orbit list, its control count, its lap reset. That is
......@@ -127,21 +178,22 @@ ArdourGUI 30.8% median (max 141), RSS 585 → 679 MB
pulsar 108% median (max 265), RSS 1332 → 1482 MB, peak 1685
```
**Five xruns in ninety-four minutes** is the number of the night. The session's
full 1182 belong to soundcheck and to the two `sof_sdw` laptop-sink nodes
(466 + 464) — the laptop speakers `TODO_GIG` step 4 said to cut and whose
checkbox stayed unticked. Ardour itself: 60 for the whole session, and the audio
path took 5 during the actual set. The `parvagues-protect` thread demotion from
**Five xruns in ninety-four minutes** is the number of the night, and they are
1 SuperCollider, 3 on the UMC's input, 1 on the laptop sink. The session's full
1182 are almost all soundcheck, and 930 of them sit on the two `sof_sdw`
laptop-sink nodes (466 + 464) — a path that is not the PA. Ardour itself took 60
across the whole session. The `parvagues-protect` thread demotion from
the 22nd holds up under load: four earlier sessions logged 5172 / 4852 / 1114 /
987 Ardour xruns.
Two things the log says happened and memory would not:
* **ArdourGUI was absent for 349 s of the window** — up at 17:12:45, gone at
17:21:00, back at 17:21:06. Both during soundcheck, both before the set.
* **pulsar disappeared at 19:44:22**, sixteen seconds after REC stopped. Not
during the music.
* **gig-log itself was killed**, not stopped: no `end` record.
* **Ardour was not up when the stage was handed over.** It first appears at
17:12:45 — six minutes into the 17:00 sound-test hour — and restarted once at
17:21:00→17:21:06. Both before the set; nothing crashed during the music.
* **pulsar disappeared at 19:44:22**, sixteen seconds after REC stopped.
* **The music stopped at 19:43:38**, dead silence from 19:43:39, REC off at
19:44:06. The set ended **16m22s before the 20:00 handover** to DJ Gredine.
## Two instrument bugs this take exposes
......@@ -152,15 +204,22 @@ agreed at the stop. Ardour's own transport feedback never once said "recording"
while it was recording. Anything built on that signal — a REC reminder above all
— would have fired continuously through a perfectly good take.
**The saved session no longer holds the gig's mix.** `Tidal Live.ardour` was
written at 19:44:41 and has `Tidal 02, 03, 04, 05, 06, 07, 08, 10, 12` at
`gaincontrol` = 0 → −∞ dB. The stems prove those faders were up while playing:
orbit 04 alone sits at a −17 dBFS median and is the loudest orbit in 13 of the
15 tracks. Between the last note and the save, the LCXL logged two `lap reset`
lines (19:44:15, 19:44:16) and `surface-state.json` went to all-zero. So the
faders on disk are the post-gig surface state, not the performance — do not read
that file as a mix reference. (`TODO_GIG` step 6, "Master fader up with the
mouse. Then Ctrl+S", was never checked off either.)
**The saved session does not hold the gig's mix, and that is expected.**
`Tidal Live.ardour` was written at 19:44:41 with nine of twelve Tidal routes at
`gaincontrol` = 0 → −∞ dB. The stems prove audio was flowing through those routes
while playing — the take is written `DiskIOPostFader`, and orbit 04 sits at a
−17 dBFS median, the loudest orbit in 13 of the 15 tracks.
This is not a new bug. `armada/tasks/2026-08-14-ardour-inf-forensics.md` settled
it: automation `state="Off"` and `n_events=0` on all twelve, no VCA, no route
group, and the *set* of −∞ tracks changing twice in one evening by non-round
amounts in both directions. It is a faithful photograph of wherever the physical
LCXL faders were at `Session::save_state()`. What is new here is the confirmation
from the other side: the stems say loud, the save says −∞, same routes, same
night.
**So the session file is not a mix reference.** Use it for routing, arm state and
processor chains — structure, not gain. For what the mix *was*, measure the stems.
## For the mastering pass
......@@ -168,7 +227,8 @@ mouse. Then Ctrl+S", was never checked off either.)
plain RIFF/WAVE float32 — Ardour wrote no `bext` chunk, so there is no BWF
origination timestamp and the wall clock comes from `mtime − duration`,
corroborated within 6 s by the files lens at 18:27:47.
* **Peaks are over 0 dBFS on 13 of 15 tracks**, worst `take_5_drops` at +7.7 and
* **Peaks are over 0 dBFS on 12 of the 13 captured tracks** (`piment_bresilien`,
the partial one, is the exception at −4.1), worst `take_5_drops` at +7.7 and
`cafe_bouillant` at +7.6. Float, so nothing clipped on disk; but the Master
bus ran at −5.0 dB into an ACE Compressor and an LSP Limiter, and those numbers
say the limiter was doing real work. Whether that is the sound wanted is PLN's
......
......@@ -14,7 +14,7 @@
8
],
"rec_lens_conflicts": 4579,
"midi_cc_in_window": 0,
"midi_events_in_window": 0,
"planned_not_played": [],
"played_not_planned": [
"sunny_side_up"
......@@ -147,6 +147,9 @@
"heard_off_map": [
12
],
"ghost_of_previous": [
12
],
"peak_db": -4.1,
"loudest_orbit": 1,
"levels": {
......@@ -271,6 +274,10 @@
4,
9
],
"ghost_of_previous": [
4,
9
],
"peak_db": 7.7,
"loudest_orbit": 4,
"levels": {
......@@ -399,6 +406,10 @@
5,
12
],
"ghost_of_previous": [
5,
12
],
"peak_db": 5.3,
"loudest_orbit": 4,
"levels": {
......@@ -523,6 +534,9 @@
"heard_off_map": [
9
],
"ghost_of_previous": [
9
],
"peak_db": 1.4,
"loudest_orbit": 4,
"levels": {
......@@ -650,6 +664,9 @@
"heard_off_map": [
4
],
"ghost_of_previous": [
4
],
"peak_db": 5.1,
"loudest_orbit": 4,
"levels": {
......@@ -769,6 +786,9 @@
"heard_off_map": [
7
],
"ghost_of_previous": [
7
],
"peak_db": 4.2,
"loudest_orbit": 4,
"levels": {
......@@ -897,6 +917,7 @@
12
],
"heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 5.3,
"loudest_orbit": 4,
"levels": {
......@@ -1021,6 +1042,7 @@
12
],
"heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 6.7,
"loudest_orbit": 4,
"levels": {
......@@ -1139,6 +1161,7 @@
11
],
"heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 7.6,
"loudest_orbit": 4,
"levels": {
......@@ -1260,6 +1283,7 @@
12
],
"heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 2.6,
"loudest_orbit": 4,
"levels": {
......@@ -1388,6 +1412,9 @@
"heard_off_map": [
1
],
"ghost_of_previous": [
1
],
"peak_db": 4.7,
"loudest_orbit": 4,
"levels": {
......@@ -1503,6 +1530,7 @@
7
],
"heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 3.5,
"loudest_orbit": 4,
"levels": {
......@@ -1627,6 +1655,7 @@
10
],
"heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 5.8,
"loudest_orbit": 5,
"levels": {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment