Read a chain from its starting pattern through each transformation, and use named arguments when a call needs more clarity.
As built in Read and write pattern pipes / Language Studio Consolidation Stage 4A. Put the pattern before |>; omit it in a transform slot:
main = play "saw" ("c3 e3 g3" |> every 4 (transpose 12) |> off 0.25 rev)
Pipes work for every, off, jux, superimpose, transpose, chop, slice, arp, within, inside, outside, firstOf, lastOf, sampleAdd, inScale, struct, mask and squeeze, alongside existing pattern pipes. Their prefix form puts the pattern last, in Tidal's order: every 4 rev p, struct "t ~ t t" p.
These operations accept named arguments and transform sections:
turn = every
main = play "saw" ("c3 e3 g3" |> turn { n = 4, f = transpose { n = 12 } })
Bare local, top-level and imported aliases and alias chains preserve these calling rules, including rev, fast and slow in transform slots.
You can also name a section or a lambda, then call it or pass it as a transform:
up = transpose { n = 12 }
rush = \p -> p |> fast 2 |> up
main = play "saw" (!"c3 e3 g3" |> every 4 rush)
Sections supply all fixed arguments and leave one pattern open. The eighteen operations above, plus fast, slow, ply, degradeBy and sometimesBy, support these bindings, forward references and imported alias chains. up p and p |> up apply the same section; an optional annotation is up : Pattern Pitch -> Pattern Pitch. Lambdas keep their authored parameter order. Named pattern captures reuse their already-baked events; random operations inside a transform use its calling binding's draw sequence. Both timing versions keep their inline behavior, including structural fast/slow in transform slots.
Naming does not broaden an operation's input contract: inScale still needs an unparsed literal/generator, so its section is useful as a direct call, not as a transform of an already-resolved pattern.
Factories can return captured lambdas. Local bindings keep the values visible where they were defined, including when an outer name is later shadowed:
make = \n -> \p -> p |> transpose { n = n }
up = make 12
main = play "saw" (!"c3 e3 g3" |> every 4 up)
Known pattern units specialize at the call. Both named results and inline calls work in rate lanes:
double = fast 2
rates = !"2 4"Hz |> double
p = patch { source = saw (freq pitch), gain = vel * (lfoSine @ rates) }
main = play p !"c3"
An explicit Pattern Hz -> Pattern Hz annotation remains useful when passing an unknown higher-order callback. If its result unit cannot be established, the compiler diagnoses before a rate lane can read Hz or milliseconds as cycle periods. Specialization follows bounded lexical structure; it does not run random generators or DSP during checking.
Supply each required argument once, positional arguments before the record. Local, forward and imported bundles, record factories, projections, static choices and with overrides work; inherited fields keep their defining scope, overrides the caller's. Hover, completion and named-field help share these slots (Named options and parameter values).
Full direct calls may put the subject first when fixed slots rule out legacy order: every p 4 rev, transpose p 12, arp !"c3:maj7" "up", slice !"0 2" 4 "amen". This includes known nested/bound subjects. Named arguments use a pipe or an omitted-subject section.
If both positional orders remain possible, legacy meaning wins. transpose !"0 12" !"c3 e3" remains equivalent to !"c3 e3" |> transpose !"0 12"; arp "up" "c3:maj7" keeps the mode first. String/pattern contents never select an order, so struct a b always reads a as the booleans. When LITERALS prove the roles swapped — booleans where the pattern belongs, notes where the booleans do (struct "c3 e3" "t ~ t t", or "t ~ t t" |> struct "c3 e3") — the checker refuses the call and names the pipe spelling; through bindings the lowerer refuses it from the resolved events (struct mel bools). Multi-pattern operations (sew, stitch, wedge) retain their positional signatures, booleans first.
An unnamed transpose/chop pipe with two potentially numeric patterns diagnoses ambiguity: older compilers could accept the opposite subject. Name the numeric slot to choose explicitly: p |> transpose { n = amounts } or p |> chop { n = counts }. Unknown shapes stay conservative; scalar annotations alone cannot exclude numeric patterns.
sample "amen" |> chop 4 / |> slice 4 remain sample-voice modifiers and also accept { n = 4 }. A known pattern/string selects pattern chop; pattern slice needs a sample name too: "0 2" |> slice 4 "amen". An unknown chop receiver keeps the sample reading. inScale needs a literal or supported generator; named patterns have already been parsed under the outer key.
Studio/LSP hints cover full calls, aliases, inline named fields and shared options. A shared bundle's definition never supplies editable byte offsets in the caller. Incomplete calls use the current source's pipe and fixed-slot evidence; unresolved positional ambiguity keeps the legacy hint. Stale snapshots discard semantic facts. Navigation and rename retain both local aliases and specialized functions. Applied sections and lambdas use ordinary function hints.
volta fmt --modernize --check song.volta previews rewrites and exits nonzero for proposals; omit --check to apply them. Either direct order can become a pipe with a known name/literal subject, retaining alias names. Comments, multiline calls, parenthesized subjects, unknown receivers, shreds, proofs and interpolation bodies are left alone. Imports verify the entry; only the entry is edited.
Every proposal must preserve full IR except source positions, including units, diagnostics, IDs and seeded events; --force cannot bypass that proof. See Format and modernize source. Timing compatibility is separate (Pattern Timing).
The editor marks each legacy call the proof would rewrite with a hint (LegacyArgumentOrder): "legacy argument order: write (p |> every 4 rev) for every 4 rev p — the subject comes first". It is advisory — an LSP Hint, a workbench Info note, a level: "hint" row in volta --diagnostics-json — and never a warning, so the legacy order stays accepted everywhere. A call the proof refuses shows no hint. The other legacy spellings --modernize retires are hinted the same way (Format and modernize source § --modernize).