Render one track once in the background and play that print in its place, so a slow machine spends its CPU only on the tracks you are still changing.
Hear it and change it#
Listen for: nothing. A frozen track sounds exactly like the live one — the fader, mute, sends, inserts and anything that taps or ducks to it stay live. What changes is the CPU meter in the header.
tempo = 120bpm
tone = patch {
source = saw (freq pitch),
ampEnv = adsr 2ms 20ms 0.6 120ms,
gain = vel * 0.6
}
lead = play tone !"c4 e4 g4 e4 a4 g4 e4 d4" |> delay 0.25 0.3
bass = play tone !"c2 ~ g2 ~"
Make it yours: open the Mixer, click ❄ on lead, then move its fader and the delay's feedback while it plays — both still work. Edit the |> delay line and Run: still frozen, because the delay runs after the print. Now edit the lead pattern and Run: the chip goes dark by itself, because the track no longer matches its print.
Where the chip is#
- Mixer strip — the ❄ button beside
MandSat the foot of every strip. - Bench track cell — after the
▶/■andMchips on a track's transport row.
States: dark = live; dimmed ❄ = rendering, with a progress bar along the chip's foot and the percentage in its hover (the header's background-work readout shows FREEZE <TRACK> 42% meanwhile); lit ❄ = frozen, hover shows the print's length and whether it loops. Clicking a rendering chip cancels it: the render stops at its next progress check instead of finishing for nothing. Click a lit chip to thaw. The chip is absent in the browser workbench for now (the wasm shell has no off-thread renderer yet, Freeze a track to save CPU §6).
What a freeze is#
The engine renders the track offline from song beat 0 — with the sources it reads, so a tap "bass" or a duck inside the frozen patch hears what it hears live — and captures the track's bus before its channel strip. Live, that print is written into the same place every block instead of the track's voices being scheduled and rendered. Everything downstream is untouched and live:
| Stays live | Frozen into the print |
|---|---|
fader, mixer { } level / pan / width / mute / polarity, group VCAs | the patch: oscillators, envelopes, per-voice effects, unison, grains, chaos |
| pre- and post-fader sends, aux buses, the master section | the pattern and its transforms |
the track's insert chain (|> delay, |> reverb, hosted plugin inserts) | song automation (macro ramps, scene with { }) on the patch |
tap / tapLive / follower / duck readers of this track | live knob turns on the patch (the value at freeze time is baked) |
scene membership, not_before / stop_at quantized starts and stops, pause, stop |
Freeze snapshots macro base values from the accepted audio revision at a block/message boundary, including macros outside the visualization limit. It replays modulation and song automation during the offline render; it does not bake an effective value and then modulate it twice. An unacknowledged module or busy snapshot asks for a retry. Knob turns after the request do not alter its captured values or refuse the finished print. This snapshot does not capture oscillator phase, smoothing, or a live ramp's future trajectory.
Length. A song with no arrange freezes 16 cycles and loops them (grid-exact song samples; a master varispeed re-times the replay). An arranged song freezes the whole form — the print follows scene starts and stops — plus a two second release tail, and is silent past the end of the form. The engine resolves a fixed scene arrangement from the accepted module when it captures the job; the desktop does not supply a separate editor revision's schedule. API callers may supply a longer finite horizon, but a supplied schedule that disagrees on capture dependencies is refused for retry.
Position. The print is read at the transport's song position, so seek, transport loop and tempo curves all land where the live track would be. A track started by hand mid-song reads the print from that position, not from its beginning.
Edits. After every Run the shell compares each frozen track's recipe — its pattern, timing, patch, voice-allocation policy and global render context (sample rate, seed, tempo/meter, key/tuning and varispeed) — with the new song. Unchanged: the freeze survives (any number of Runs, comment edits included). Changed: the track thaws at once, so the edit is heard live. Moving event highlights, argument highlights, playback anchors, nested graph editor metadata or EQ argument spans preserves the recipe, including alternative patterns. The frozen track's OWN insert chain is not part of the recipe — the print is taken before it, so editing |> reverb, |> delay or an insert's parameter lane on a frozen track keeps the print and is heard live at once. (An insert an upstream voice reads through — a postFx tapLive — is inside the capture and does thaw it.) The frozen track's mixer changes and unrelated track edits preserve it. Prepared plans use the same typed, float-bit-preserving encoding as bounce recipes; diagnostic formatting cannot change a key. Jobs also fingerprint captured sample PCM/channels/rates, source tempo declarations, variants, zones and wavetable contents — each buffer through a content digest computed once per buffer and memoized, so the check costs the same on a zone-mapped instrument as on a one-shot. Replacing an input while its job runs refuses installation; an already frozen print holds until Run, which thaws it if those input contents changed. Content-equal reloads and unrelated banks keep it frozen. The prepared routing graph scopes resources to the pre-strip capture: a source tapped before its inserts excludes those insert resources; a post-FX tap includes them. The frozen track's own downstream insert resources remain live. A zone-only bank retains its tempo declaration in the offline snapshot. External model/plugin dependencies upstream of the capture cannot freeze. The structural key (version 9) also follows prepared routing dependencies for upstream voices, consumed macro defaults/modulation/contracts, shared controls, and the strips, sends and inserts before the read stage. These program changes refuse pending jobs and thaw prints on Run; unused controls and inserts after a pre-fader tap preserve them. Written timelines include their extent and loop policy, plus automation lanes for macros consumed anywhere upstream of the capture. Curve timing, interpolation, values, tangents, gap and composition policy participate; unused lanes and editor origins preserve the print. Fixed scene arrangements include resolved membership, timing, song-position brackets and consumed automation, including transitions across the actual capture horizon's loop seams. Scene renames, unused scenes, unused automation and unrelated track edits preserve the print. Complete graph-song/score scheduling, generated-program and implicit global dependency identity remains open, so this is not a guarantee for every upstream edit.
Freeze and thaw are click-free. A running track note-offs its voices and crossfades into the print over 10 ms; thawing re-seats the scheduler at the current beat and crossfades the print out. Notes already sounding at the thaw instant are not re-created (the same rule as a scene start).
Controls and musical uses#
- CPU on a slow laptop. Freeze the pads, the granular beds, the convolution-heavy tracks; keep the part you are writing live. Combine with a larger device buffer (io panel ▸ AUDIO OUT ▸ buffer) and Display ▸ low power; see Production tools in Studio.
- Commit a sound. A frozen track is also a "this is done" marker: it cannot drift when you turn knobs, only when you edit its source.
- A/B a change. Thaw, edit, Run, listen, then freeze again — the chip's state tells you which tracks are the old render and which are live.
Notes and limits#
- Refused with a toast: a track that plays a hosted plugin instrument (nothing hosts it offline), a track whose dependency closure reads live
input, and the hiddenbounce:render tracks. - Live knobs.
@knobsand mixer-independent macro turns on a frozen patch do not reach it until it thaws; song automation does (it is part of the print). - Loop seam. A looped print is rendered from a cold start: its first cycle lacks the tails of the cycles "before" it and the wrap cuts the last note's release. Per-note randomness (drift, salted random) is seeded by the absolute cycle, so a looped print replays cycle 1's variations every time rather than varying as the live track would.
- Memory. A print is stereo float in RAM (about 23 MB per minute at 48 kHz); there is no on-disk cache yet, so reopening a song starts with every track live.
- Keys hash content, never addresses. A buffer's digest is computed once and memoized behind a witness of its buffers' addresses and lengths (
SampleData::content_digest,engine/src/sample.rs). PCM is finished before it is wrapped and never rewritten in place — a trimmed region or a re-decoded take is a new buffer — so the memo cannot describe stale audio; anything that ever writes into a held buffer must clear the memo with it. The synth-template tables a key walks are enumerated in one place,graph::template_sites, which the recipe checks against (engine/src/recipe/resources.rs). - Not persisted. Which tracks are frozen is per session.
- Browser. No chip yet; the engine seam exists on both targets.
- Bounce vs freeze.
bounceOf(Resample your own sounds) is a value in the language you can chop, stretch and resample, and it rewrites nothing. Freeze is a shell gesture with no source effect. The Bench Bay's olderfreeze ❄island verb (The live notebook) rewrites the source into abounceOfprint plus a sampler; the ❄ chip does not touch the source.
Next steps#
Push CPU further with Understand audio processing cost (what each node costs) and Resample your own sounds (commit a generation to a sample you can re-chop). Design and the remaining stages: Freeze a track to save CPU.