Commit 5e5a37ad by PLN (Algolia)

feat(set): a note is not a track — and the dead buttons PLN asked about

THE PHANTOM. PLN drafts in backlog.md, and he drafts in LIST ITEMS. Mid-run he
wrote himself a deliberation:

  -- Q: This intro is quite raptech. jazz intro? quand on decolle opening? reflect

and quand_on_decolle silently joined the OPAL set. The resolver's "codename
carries extra words" branch is a subset test, so {quand, on, decolle} being 3 of
those 13 words was a match. It then flowed downstream exactly as designed — into
the .txt, the preload plan, the remap scope and the gig gate. The pipe worked
perfectly, on garbage.

Two guards, because either alone is too clever:
  * _NOTE_RE skips items marked Q:/NB:/NOTE:/TODO:/FIXME:/IDEA:, and PRINTS what
    it skipped. A note dropped silently and a track dropped silently look
    identical from inside the parser, and only one of them is survivable.
  * the extra-words branch is bounded to 4 decoration words. Real entries spend
    at most 4 ("[129] Desire [TODO BASS ETC!]"); that note spent 10.

An UNMARKED prose line now RAISES instead of resolving. That is deliberate and
tested: red gate, PLN adds "Q:" or deletes the line. A phantom track goes to the
venue. Loud beats clever.

(He has since re-added quand_on_decolle under an explicit ## SOUNDCHECK heading,
as a real entry. It arrived carrying the full off-by-one-column corpus pattern —
11 moves — now migrated. That is the pipe working on something real.)

DEAD BUTTONS. PLN, playing: "not seeing effects on button 44 nor 43?" on
do_it_right, "no buttons 42 43?" on ouais_je_funk. They were not broken, they
were never mapped. Now:
  do_it_right   ^43  d3 hats — HIS OWN TODO implemented verbatim: "an opening
                     legato or att to make it slowly go from hard dry h to an
                     open ho? as in take 5 drops". Held, legato walks 0.4->2.5
                     and hpf 7k->2.5k over 8 cycles; released, it snaps back.
  do_it_right   ^44  d4 bass — octave down, DROP TO THE CELLAR
  ouais_je_funk ^42  d2 clap — the clap had no gate at all. Handclap roll.

d4's crush/octersub land on ^52/^32 exactly as PLN asked. That required
REORDERING the two lines, not renumbering them: migrate-columns assigns knobs in
order of declaration, so the file now carries a comment saying the order is
load-bearing. Fighting the tool by hand would just be undone next run.

Set: 15 tracks, 0 moves pending, silent-eval --seeded 15/15, pvlint 0 errors,
setlist tests all green (now pinning lime_tacos OUT and the phantom absent).
parent b8344ac1
......@@ -1917,17 +1917,26 @@ ParVagues et Shipow
## Livecoding Techno DNB Nu-jazz
> Sunset Forest
1h30 - 20h30-22h
## SOUNDCHECK
-- Quand on decolle
### _Ouverture_
-- [lightT][124] Ceci n'est pas Une Bombe
-- [lightT][133] WAP
-- Q: This intro is quite raptech. jazz intro? quand on decolle opening? reflect
## SUNSET
-- [lightT][89*] Am i _Doing it Right_ ?
### _We call it NuJazz_
-- [jazzTech][124] Take five Drops
-- [highTech][124] Piment Bresilien
-- [highTech][120] Eh ouais je Funk?
-- [justTech][128] Perfect <3
-- [dnb][160] Gimme Acid??!?
## NUIT
-- [dnb][160] Gimme Acid?!!
-- [lightT][120] Vague de CRIME
??TRANSITION???
-- [Hdnb][166] Sunshine
......
......@@ -51,6 +51,13 @@ d5 $ gF3 $ gM3 -- LE PIMENT BRESILIEN
# octerbus 51 (range 0 1.4 "^33")
# octersubbus 52 (range 0 4 "^53")
d7 $ gF3 $ gM3
-- PLN: "on 59 a different progression, maybe going updowndown rather than
-- upupup?". E7, d7's own gate. The octave line below climbs 0 +12 +24 +36 over
-- 16 cycles — three steps UP, always. Held, ^59 adds 0 0 -24 -48 on top, which
-- lands the same 16 cycles on 0 +12 0 -12: up, then down, then down. Written as
-- an OFFSET rather than a second progression so the two can never drift apart
-- if you edit the notes. TODO @PLN verify.
$ midiOn "^59" (|+ note "<0!4 0!4 -24!4 -48!4>")
$ midiOn "^91" (ply 2)
$ note ("[f3 cs3 c3 cs3 f3 cs3 <c3 f3> <cs3 fs3>]"
-- + "[0,12]"
......
......@@ -4,23 +4,23 @@ do
-- resetCycles
setcps (120/60/4)
d1 $ gF1 $ gM1
$ midiOn "^42" (<| "k k . k(<2 2 [2 4] <3 4 3 5>>,8)")
$ midiOff "^42" (<| "k . ~ k ~ <~!3 k*2>")
$ midiOn "^41" (<| "k k . k(<2 2 [2 4] <3 4 3 5>>,8)")
$ midiOff "^41" (<| "k . ~ k ~ <~!3 k*2>")
$ fix ((|* gain 0.9) . (# lpf 1000)) "jazz"
-- $ fix ((# att 0.02) . (# rel 0.5) . (# lpf 400)) "kick:4"
$ "[jazz,kick:4]"
# gain 1.4
# lpf 300
d2 $ gF1 $ gM2
$ midiOff "^43" (<| "~ . s@3 <~ s*<1 <2 [4 2]>>>")
$ midiOn "^43" (<| "~ s ~ <s!3 s*<2 [4 2]>>")
$ midiOff "^42" (<| "~ . s@3 <~ s*<1 <2 [4 2]>>>")
$ midiOn "^42" (<| "~ s ~ <s!3 s*<2 [4 2]>>")
$ fix (# lpf 4000) "snare:30"
$ "[snare:30]"
# lpf 2800
# gain 1.1
# cut 2
d3 $ gF1 $ gM2
$ midiOn "^44" (ply "2 <2!3 4>")
$ midiOn "^43" (ply "2 <2!3 4>")
$ "~ h ~ h ~ h*<1 2 1 <1 [4 2]>> ~ h*<1 <1 1 0 2> 1 <2 4>>"
# "hh"
# att (slow 32 $ range 0.4 0.04 saw)
......@@ -28,28 +28,28 @@ d3 $ gF1 $ gM2
# room 0.2 # dry 1.3
# gain 1.9
d4 $ gF2 $ gM3
$ midiOn "^57" (sometimesBy 0.5 ((|- note 12) . (# cut 41)))
$ midiOn "^89" (ply 2)
$ midiOn "^44" (sometimesBy 0.5 ((|- note 12) . (# cut 41)))
$ midiOn "^76" (ply 2)
-- $ note ("d3" + scale "mixolydian" ("[<0!12 3!4> <4!12 6!4>]*4")) -- ORIGINAL.
$ note ("d3" + scale "mixolydian" ( -- NICE VARIATIONS
"[0 4 <0 [0 <5 6>] 0> 4 <0!3 2> 4 <0 2> 4]" + "<0!3 [4 6]*2!1>")
)
# "bassWarsaw"
-- # "bass3:3" |+ note 24
# octersubbus 41 (range 0 2.5 "^33")
# crushbus 42 (range 16 2.5 "^53")
# roombus 43 (range 0 0.5 "^33")
# octersubbus 41 (range 0 2.5 "^32")
# crushbus 42 (range 16 2.5 "^52")
# roombus 43 (range 0 0.5 "^32")
# gain 1.3
# pan 0.3
# cut 4
d5 $ gF3 $ gM3
$ midiOn "^58" (striate "4 <8 <16 32>>")
$ midiOn "^90" (ply 2)
$ midiOn "^89" (striate "4 <8 <16 32>>")
$ midiOn "^57" (ply 2)
$ slow 16 $ chop 16
$ "airports" # cut 5
# pan 0.3
# delaybus 51 (range 0 0.8 "^54")
# delaytime "^34"
# delaybus 51 (range 0 0.8 "^33")
# delaytime "^53"
# room 0.4 # sz 0.8 # dry 1.1
-- # crushbus 51 (range 16 3.5 "^54")
d7 $ gF3 $ gM3
......
......@@ -25,15 +25,19 @@ d3 $ gF1 $ gM2 $ dMask
# hpf (slow 32 $ range 200 8000 sine)
# gain 1.5
d4 $ gF2 $ gM3 -- La Funky Bass
$ midiOn "^44" (ply 2) -- E4: a GATE, freed when d3's snare moved to ^43
$ midiOn "^76" (slice 8 "<6>*<2 2 2 4 2 2 4 8 2 8 8 16 8 16 16 16>")
$ midiOn "^76" (ply 2) -- F4: a GESTURE row, per button_roles
$ midiOn "^44" (slice 8 "<6>*<2 2 2 4 2 2 4 8 2 8 8 16 8 16 16 16>") -- E4, was dead
$ chop (8 * 8) -- 8 chops times 8 loops
$ loopAt 8
$ "gfunk_bass:1"
# cut 4
# room 0.8 # sz 0.5 # dry 1.2
# crushbus 41 (range 16 3.5 "^52") -- C4, PLN's ask: "d4 52 a crush?"
-- ORDER IS LOAD-BEARING: migrate-columns assigns an orbit's knobs in order of
-- DECLARATION — first to row B, second to row C. PLN asked for "d4 52 a crush?
-- 32 a octersub maybe?", i.e. octersub on B4 and crush on C4, so octersub is
-- declared first. Swap these two lines and the tool will swap the CCs back.
# octersubbus 42 (range 0 1.5 "^32") -- B4, PLN's ask: "32 a octersub maybe?"
# crushbus 41 (range 16 3.5 "^52") -- C4, PLN's ask: "d4 52 a crush?"
# gain 1.3
d9 $ gF3 $ gM3
$ midiOn "^20" (superimpose (
......
......@@ -10,7 +10,13 @@ d1 $ fast 2
$ "[popkick:2,kick:5]"
# lpf 300 -- TODO Sound design this kick <3
-- # cut 1
# gain 2
-- PLN 2026-08-02: "definitely the kicks too saturate". Measured, not guessed.
-- SuperDirt amplitude is gain^4, so `gain 2` is +24.1 dB — and this line stacks
-- TWO samples at it (popkick + kick), so ~+30 dB into the orbit. Every other
-- orbit in this track sits between 0 and +14.1 dB: the kick was a 10 dB outlier
-- against its own bassline. 1.5 = +14.1 dB, still 2.4 dB proud of d4. If it now
-- reads thin, raise the OTHERS rather than coming back here. TODO @PLN verify.
# gain 1.5
-- # midiG' "^78" 0 1.5
d2 $ fast 2 $ gF1 $ gM2
$ midiOn "^42" (<| "~ s ~ s*<1!3 <2 [4 2]>>")
......@@ -19,14 +25,25 @@ d2 $ fast 2 $ gF1 $ gM2
-- # "h2ogmcp"
-- # gain (1.0 * "<[1]!16 [1 <1 <1 [1 0.93] 1 [0.9]>>]!16>")
# gain 1.2
d3 $ gM2 $ gF1 -- Todo: buttons and variations? e.g. an opening legato or att to make ti slowly go from hard dry h to an open ho? as in take 5 drops, would make for a good transition imo?
d3 $ gM2 $ gF1 -- E3 (^43) was dead. PLN's own TODO, implemented: "an opening
-- legato or att to make it slowly go from hard dry h to an open
-- ho? as in take 5 drops, would make for a good transition imo".
-- Held, it opens over 8 cycles — legato lets the sample ring out
-- while the hpf walks down from 7k to 2.5k, so a tight closed hat
-- becomes a wide one. Release and it snaps back. TODO @PLN verify.
$ midiOn "^43" (
(# legato (slow 8 $ range 0.4 2.5 saw))
. (# hpf (slow 8 $ range 7000 2500 saw))
. (# room 0.5) . (# sz 0.7)
)
$ "~ d ~ d ~ d ~ d ~ d*<1 2 2 1> ~ d ~ d ~ d"
# "h2ogmhh"
# hpf 7000
# gain 1.4
# room 0.3 # sz 0.5 # dry 0.9
# pan "0.8 0.8 0.8 <0.2 0.2 0.8 [0.8 0.2]>"
d4 $ gF2 $ gM3
d4 $ gF2 $ gM3
$ midiOn "^44" (|- note 12) -- E4, was dead: DROP TO THE CELLAR, an octave down
$ midiOn "^76" (ply "1 <1 2 1 4>")
$ note "[<as2 cs3 f3 cs3> <b2 ef3 fs3 b2>@7]"
# "bassWarsaw" # cut 4
......
......@@ -95,6 +95,17 @@ class SetlistError(RuntimeError):
exactly the failure mode this module retires."""
# A list item PLN wrote to think out loud, not to name a track. He drafts in this
# file, so notes and entries share the "- " prefix; these are the markers he uses.
# Skipped LOUDLY (reported on stderr) — never silently, or the set could lose a
# real track to a typo'd marker.
_NOTE_RE = re.compile(r"^\s*(?:Q|N\.?B|NOTE|TODO|FIXME|IDEA)\s*[:?]", re.I)
# How many words of decoration a real entry may carry around its track name —
# "[lightT][120] Vague de CRIME" spends 2, "[129] Desire [TODO BASS ETC!]" spends 4.
_MAX_DECORATION = 4
def _norm(s: str) -> str:
"""Fold to plain lowercase words: accents, markdown emphasis and punctuation out."""
s = unicodedata.normalize("NFKD", s)
......@@ -135,7 +146,17 @@ def _resolve(codename: str, index: dict[str, list[pathlib.Path]]) -> pathlib.Pat
scored = []
for cand in index:
toks = set(_norm(cand).split())
if toks <= want or want <= toks:
# `toks <= want` is the "codename carries extra words" direction —
# tags and bpm, "[129] Desire [TODO BASS ETC!]". Bounded, because
# unbounded it matches a track name mentioned in PROSE. On
# 2026-08-02 PLN wrote a deliberation note as a list item —
# "Q: This intro is quite raptech. jazz intro? quand on decolle
# opening? reflect" — and {quand,on,decolle} being a subset of
# those 13 words silently put quand_on_decolle in the set. The
# real entries carry at most 4 decoration words; that note carried
# 10. See _NOTE_RE for the other half of this guard.
if (toks <= want and len(want - toks) <= _MAX_DECORATION) \
or want <= toks:
scored.append((len(toks & want), -len(toks ^ want), cand))
if not scored:
raise SetlistError(
......@@ -203,6 +224,12 @@ def entries(gig: str = GIG, backlog: pathlib.Path | None = None) -> list[Entry]:
# A markdown link is a reference, not a track ("- [MathMusic](https://...)").
if not raw or re.match(r"^\[[^\]]*\]\(", raw) or raw.startswith(("http", "url:")):
continue
# PLN thinks out loud in this file, in list items. A marked note is not a
# track — but say so on stderr, because a note silently dropped and a track
# silently dropped look identical from here.
if _NOTE_RE.match(raw):
print(f"setlist: note, not a track — skipped: {raw}", file=sys.stderr)
continue
tags = tuple(t.strip() for t in BRACKET.findall(raw))
name = BRACKET.sub(" ", raw)
bpm = next((int(BPM.match(t).group(1)) for t in tags if BPM.match(t)), None)
......
......@@ -114,13 +114,41 @@ try:
except S.SetlistError:
check("missing gig section raises SetlistError", True)
print("\na note is not a track (2026-08-02)")
# PLN drafts in backlog.md, and he drafts in list items. This one cost a phantom:
# {quand, on, decolle} is a subset of the note's 13 words, so the resolver's
# "codename carries extra words" branch matched it and quand_on_decolle joined the
# set — flowing straight into preload, the remap and the gig gate.
NOTE = ("-- Q: This intro is quite raptech. jazz intro? "
"quand on decolle opening? reflect\n")
noted = paths(BASE + NOTE)
check("a marked note is skipped, not resolved", noted == base, f"{noted}")
try:
paths(BASE + "-- honestly the quand on decolle opening might work better here\n")
check("UNMARKED prose cannot resolve to a phantom track", False)
except S.SetlistError:
# Loud, not silent, and that is the right end of the trade: an unmarked note
# turns the gig gate red and PLN adds "Q:" or deletes the line. A phantom
# track goes to the venue.
check("UNMARKED prose cannot resolve to a phantom track", True)
check("but decoration still resolves — 4 extra words is a real entry",
paths("-- [129] Desire [TODO BASS ETC!]\n") == [DESIRE])
try:
paths("-- [124] Definitely Not A Track Here\n")
check("an UNRESOLVABLE plain name still raises — notes must not silence it", False)
except S.SetlistError:
check("an UNRESOLVABLE plain name still raises — notes must not silence it", True)
print("\nthe real backlog")
real = S.entries()
check("parses backlog.md", len(real) >= 13, f"{len(real)} tracks")
check("every track file exists", all((ROOT / e.path).exists() for e in real))
check("ouais_je_funk is in the set (was missing from all 8 tools)",
any(e.path.name == "ouais_je_funk.tidal" for e in real))
check("lime_tacos is in the set", any(e.path.name == "lime_tacos.tidal" for e in real))
check("lime_tacos is OUT (PLN 2026-08-02: 'actually weak, removed from set')",
not any(e.path.name == "lime_tacos.tidal" for e in real))
check("a deliberation note is not a track (the quand_on_decolle phantom)",
not any(e.path.name == "quand_on_decolle.tidal" for e in real))
names = [e.path.stem for e in real]
check("you_my_sunshine precedes mafia_sans_serif (PLN 2026-08-01)",
names.index("you_my_sunshine") < names.index("mafia_sans_serif"))
......
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