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. ...@@ -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 - **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, control map lists it in all 15 tracks. No file was created — an absent stem,
not a silent one. not a silent one.
- **No MIDI from either recorder.** gig-log bound seq port `133:0` at 00:59 and - **No MIDI at all**: gig-log bound seq port `133:0` at 00:59 and never rebound.
never rebound; Ardour's `Keys` wrote 24 files of 26 bytes each. 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) ## Sel (the shareable learning)
**The lens that saved the night was not built for it.** gig-log has a MIDI lens, **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 ...@@ -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 Redundancy is not three copies of the good instrument. It is four instruments
that fail differently. that fail differently.
Corollary, learned the same morning: **the session file no longer holds the mix Corollary, and it closes an old file: **the session save does not hold the mix you
you played.** Nine of twelve faders read −∞ in `Tidal Live.ardour`, saved at played.** Nine of twelve faders read −∞ in `Tidal Live.ardour` (saved 19:44:41)
19:44:41, twenty-six seconds after a surface `lap reset` zeroed the board. The while the stems, written post-fader, are loud. `2026-08-14-ardour-inf-forensics.md`
stems prove those faders were up — orbit 04 sits at a −17 dBFS median and is the had already ruled out automation and corruption and called it a faithful photograph
loudest orbit in 13 of 15 tracks. Audit the artifact, not the config. 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) ## Hameçon (hook)
"I forgot to hit record." Ninety-four minutes later the laptop could still name "I forgot to hit record." Ninety-four minutes later the laptop could still name
...@@ -67,7 +78,8 @@ the LEDs. ...@@ -67,7 +78,8 @@ the LEDs.
## Sillage (what it unlocks) ## Sillage (what it unlocks)
- Mastering can start: 11 stems, 76m19s, t0 = 18:27:41.201, per-orbit levels done. - 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. - Peaks over 0 dBFS on 12 of the 13 captured tracks (worst +7.7) — the limiter was
His ear decides whether that is the sound. working. His ear decides whether that is the sound.
- A REC reminder is now buildable **and** the lens it must not use is identified. - 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. ...@@ -18,6 +18,12 @@ uses audio to guess a name.
track uses. Independent of gig-log; it survived the gig where 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 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). 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 stems full-resolution 1 s RMS/peak per orbit from the Ardour take. Ground
truth for what actually reached the DAW. truth for what actually reached the DAW.
...@@ -27,8 +33,11 @@ measured INSIDE those windows. ...@@ -27,8 +33,11 @@ measured INSIDE those windows.
TWO READINGS THAT ARE NOT ERRORS TWO READINGS THAT ARE NOT ERRORS
* an orbit MAPPED BUT QUIET — a knob existed, the orbit stayed under the * 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. 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 * an orbit HEARD OFF-MAP — it sounded with no knob painted for it. Usually
a previous pattern still running, so it is reported, not interpreted. #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 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 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 ...@@ -124,8 +133,8 @@ def stem_levels(stem_dir: Path, take: str) -> tuple[dict[int, dict], float, floa
# ── lenses ─────────────────────────────────────────────────────────────────── # ── lenses ───────────────────────────────────────────────────────────────────
def gig_log(log: Path, day: str, lo: str, hi: str): def gig_log(log: Path, day: str, lo: str, hi: str):
"""(eval events, rec transitions, session stats) inside the window.""" """(eval events, rec transitions, 1 Hz samples, MIDI events) in the window."""
evals, recs, samples = [], [], [] evals, recs, samples, midi = [], [], [], []
for line in log.open(errors="replace"): for line in log.open(errors="replace"):
if not line.strip(): if not line.strip():
continue continue
...@@ -146,7 +155,9 @@ def gig_log(log: Path, day: str, lo: str, hi: str): ...@@ -146,7 +155,9 @@ def gig_log(log: Path, day: str, lo: str, hi: str):
recs.append(r) recs.append(r)
elif k == "s": elif k == "s":
samples.append(r) 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): def surface_loads(day: str, lo: str, hi: str):
...@@ -179,7 +190,7 @@ def db(x: float) -> float: ...@@ -179,7 +190,7 @@ def db(x: float) -> float:
def build(args) -> dict: def build(args) -> dict:
day = args.date day = args.date
lo, hi = args.window 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) loads = surface_loads(day, lo, hi)
if not loads: if not loads:
raise SystemExit("surface lens empty — is lcxl3-driver's journal still there?") raise SystemExit("surface lens empty — is lcxl3-driver's journal still there?")
...@@ -241,6 +252,8 @@ def build(args) -> dict: ...@@ -241,6 +252,8 @@ def build(args) -> dict:
row["mapped_but_quiet"] = [o for o in s["orbits_mapped"] row["mapped_but_quiet"] = [o for o in s["orbits_mapped"]
if o in orbits and o not in heard] 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"]] 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["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["loudest_orbit"] = max(lv, key=lambda o: lv[o]["rms_p50_db"])
row["levels"] = lv row["levels"] = lv
...@@ -259,7 +272,7 @@ def build(args) -> dict: ...@@ -259,7 +272,7 @@ def build(args) -> dict:
"captured_pct": round(100 * dur / (seq[-1]["end"] - seq[0]["start"])), "captured_pct": round(100 * dur / (seq[-1]["end"] - seq[0]["start"])),
"orbits_missing_from_take": missing, "orbits_missing_from_take": missing,
"rec_lens_conflicts": len(conflicts), "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], "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], "played_not_planned": [p for p in played if p not in planned],
"post_set_loads": post, "post_set_loads": post,
...@@ -303,6 +316,10 @@ def main() -> int: ...@@ -303,6 +316,10 @@ def main() -> int:
print(f" head lost: {out['head_lost_s']//60}m{out['head_lost_s']%60:02d}s") print(f" head lost: {out['head_lost_s']//60}m{out['head_lost_s']%60:02d}s")
if out["orbits_missing_from_take"]: if out["orbits_missing_from_take"]:
print(f" orbits with NO stem: {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()
print(table(out)) print(table(out))
if out["played_not_planned"]: if out["played_not_planned"]:
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
8 8
], ],
"rec_lens_conflicts": 4579, "rec_lens_conflicts": 4579,
"midi_cc_in_window": 0, "midi_events_in_window": 0,
"planned_not_played": [], "planned_not_played": [],
"played_not_planned": [ "played_not_planned": [
"sunny_side_up" "sunny_side_up"
...@@ -147,6 +147,9 @@ ...@@ -147,6 +147,9 @@
"heard_off_map": [ "heard_off_map": [
12 12
], ],
"ghost_of_previous": [
12
],
"peak_db": -4.1, "peak_db": -4.1,
"loudest_orbit": 1, "loudest_orbit": 1,
"levels": { "levels": {
...@@ -271,6 +274,10 @@ ...@@ -271,6 +274,10 @@
4, 4,
9 9
], ],
"ghost_of_previous": [
4,
9
],
"peak_db": 7.7, "peak_db": 7.7,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -399,6 +406,10 @@ ...@@ -399,6 +406,10 @@
5, 5,
12 12
], ],
"ghost_of_previous": [
5,
12
],
"peak_db": 5.3, "peak_db": 5.3,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -523,6 +534,9 @@ ...@@ -523,6 +534,9 @@
"heard_off_map": [ "heard_off_map": [
9 9
], ],
"ghost_of_previous": [
9
],
"peak_db": 1.4, "peak_db": 1.4,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -650,6 +664,9 @@ ...@@ -650,6 +664,9 @@
"heard_off_map": [ "heard_off_map": [
4 4
], ],
"ghost_of_previous": [
4
],
"peak_db": 5.1, "peak_db": 5.1,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -769,6 +786,9 @@ ...@@ -769,6 +786,9 @@
"heard_off_map": [ "heard_off_map": [
7 7
], ],
"ghost_of_previous": [
7
],
"peak_db": 4.2, "peak_db": 4.2,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -897,6 +917,7 @@ ...@@ -897,6 +917,7 @@
12 12
], ],
"heard_off_map": [], "heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 5.3, "peak_db": 5.3,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -1021,6 +1042,7 @@ ...@@ -1021,6 +1042,7 @@
12 12
], ],
"heard_off_map": [], "heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 6.7, "peak_db": 6.7,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -1139,6 +1161,7 @@ ...@@ -1139,6 +1161,7 @@
11 11
], ],
"heard_off_map": [], "heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 7.6, "peak_db": 7.6,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -1260,6 +1283,7 @@ ...@@ -1260,6 +1283,7 @@
12 12
], ],
"heard_off_map": [], "heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 2.6, "peak_db": 2.6,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -1388,6 +1412,9 @@ ...@@ -1388,6 +1412,9 @@
"heard_off_map": [ "heard_off_map": [
1 1
], ],
"ghost_of_previous": [
1
],
"peak_db": 4.7, "peak_db": 4.7,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -1503,6 +1530,7 @@ ...@@ -1503,6 +1530,7 @@
7 7
], ],
"heard_off_map": [], "heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 3.5, "peak_db": 3.5,
"loudest_orbit": 4, "loudest_orbit": 4,
"levels": { "levels": {
...@@ -1627,6 +1655,7 @@ ...@@ -1627,6 +1655,7 @@
10 10
], ],
"heard_off_map": [], "heard_off_map": [],
"ghost_of_previous": [],
"peak_db": 5.8, "peak_db": 5.8,
"loudest_orbit": 5, "loudest_orbit": 5,
"levels": { "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