VOLTAreference

Reference / Samples and recording

Remote samples: a streaming track as a sample

Samples and recording

Open in the workbench →
On this page · 8 sections

Name eight seconds of a track on Spotify in your song, and each desktop that plays the song captures that span locally and plays it like any sample.

What it is#

hook = remoteSample "spotify:track:4uLU6hMCjMI75M1A2tKUQC" 64s 8s
flip = play (hook |> pitched ~C3 |> chop 8) !"c3 ~ g2 c3"

remoteSample uri start length is a sample source with the full sample surface — pitched, speed, loop, warp, trim, reverse, chop, chopAt, stretch all compose — because it lowers to an ordinary sample node. The song text holds only the reference. Each machine resolves it on its own:

  1. The capture cache (~/.volta/captures/<key>.wav + <key>.json). A hit touches no other app, and the same source gives the same audio on that machine every time.
  2. A capture from the Spotify desktop app on macOS 14.4+, when the cache misses. Spotify plays the span muted (a process tap with CATapMutedWhenTapped, so you hear nothing). The capture is trimmed to the span, written to the cache, and installed while the song plays. Spotify's track, position, play/pause state and volume are put back afterwards.

Until a reference resolves, its slot plays silence and audio never stops. Exports refuse an unresolved reference by name instead of baking silence.

Surface#

PortMeaning
uriA string literal: "spotify:track:<id>" or "https://open.spotify.com/track/<id>" (any ?si= query or intl-xx/ segment). Both spellings normalise to the URI, so they share one capture. Anything else is a compile error.
startA constant duration into the track (64s; a bare number is seconds). Rounded to the millisecond; at most one hour.
lengthA constant duration, greater than 0 and at most 60 s. The capture runs in real time, so this is also roughly how long the first resolve takes, plus about 3 s.

The same reference written twice is one bank entry and one capture. A different span of the same track is a different capture.

How it's implemented#

  • IR. Module.remoteSamples: [{key, uri, startMs, lenMs}] (RemoteSampleDef, ir/src/remote.rs). The node names remote:<key>, where key is 16 hex digits of FNV-1a/64 over (canonical URI, start, length, CAPTURE_VERSION). Bumping CAPTURE_VERSION re-keys every capture on every machine. remote: is a reserved handle (Handle::Remote): manifest fetches skip it (ui/src/intel.rs, runtime/src/samples.ts).
  • Doctor. UnresolvedRemoteSample names the URI and span at the call site. It is Silent when the host's cache says the capture is missing (CLI volta doctor, MCP doctor) and Suspect when no host was asked.
  • Resolver seam (capture/src/remote/). RemoteResolver is the trait. RemoteDriver is the background worker: it answers every cache hit before any capture, runs one capture at a time and reports queued / capturing / ready / failed. A failure stays failed until you retry, so recompiles don't trigger a retry storm. The Spotify pipeline (spotify.rs) works over three seams: Transport (the player's script interface), TapFactory/Tap (the process tap) and Clock (host time). fake.rs simulates all three for tests; macos.rs holds the real ones (feature remote-macos, macOS-only dependencies).
  • Capture sequence. The capture:

    1. Snapshots the player.
    2. Opens the muting tap. If Spotify has no audio process yet, it plays the target at volume 0 and taps it as soon as the process appears.
    3. Pins Spotify's volume to 100 and plays the target.
    4. Waits until the player reports the target URI (ads play first on a free account).
    5. Seeks to start − 1.5 s.
    6. Polls (host time, position) while the tap records, until end + 0.5 s.
    7. Checks with a Theil–Sen fit that playback ran at 1×, then takes the median offset at slope 1.
    8. Cuts exactly length of audio from the tap's timeline, starting at the host time of start.
    9. Restores the player.

    The capture is refused, never corrupted, when:

    • the item changes during the span (an ad, autoplay, a skip);
    • the span runs past the track's end;
    • playback is not at 1×, or a poll jumps more than 150 ms inside the span;
    • the tap drops audio inside the span;
    • the tap delivers only silence (the usual sign of a missing System Audio Recording grant).
  • Install (app-native/src/remote.rs). Each frame, volta-studio's bridge follows the engine's module, submits its references and installs finished captures through EngineHandle::load_samples. That late-arrival path hot-swaps a capture into playing voices and into readers already bound at load (stretch/warp, reresolve_stretch). A module with bounces re-bakes them, so a bounceOf over a remote sample prints the real audio. Captures are stereo at the tap's device rate; the engine repitches per buffer.
  • Offline (Stage 4). Every desktop render fills remote: entries from the cache, or refuses with volta_ir::remote::refusal, which names each reference and says to run volta capture. In the CLI that covers export stems, export video and the shared render seam; the manifest-aware render-manifest engine example reads the cache too (it then reports an uncached reference as a missing key). In volta-studio it covers export, MCP export_song/measure_audio, span renders, A/B pairs, history auditions and disk-song renders. The Compose preview refuses remote samples outright. A plugin export warns that a remote source is silent there.

Using it from the CLI#

volta capture song.volta            # resolve every reference (cache, then Spotify)
volta capture --recapture song.volta
volta capture --list                # key, size, span, track — artist
volta capture --remove <key>
volta capture --clear
volta export stems song.volta -o out/   # refuses if a reference is not cached

volta capture exits nonzero if any reference failed or timed out (--timeout <seconds>, default 600).

In the workbench#

At the top of the asset drawer, Remote samples lists every reference of the loaded song. Opening a song never launches Spotify on its own: a reference already in the capture cache installs as before, but an uncached one waits as not captured with a capture button, because capturing opens the app and plays the track on your account — not something a song's author should be able to do to you (RemoteDriver::requiring_approval; the headless volta capture command, run on purpose, still captures directly). Each row has its state (not captured, queued, capturing 42%, ready · cached, ready · captured, failed with the reason) and the track name once known. A ready row has re-capture; a failed row has retry (after you fix the permission or app that the reason names). A footer gives the cache's size, with clear cache.

The browser cannot tap another app. Its drawer lists the song's references as desktop-only, with the explanation, so a silent slot is never unexplained. This is by design (an owner decision), not a pending feature.

Posture: captures stay on this machine#

Capturing a stream you are entitled to play, on your own machine, for your own use, is the same category as Audio Hijack. Volta keeps it there:

  • the cache lives in ~/.volta/captures and refuses a root under iCloud Drive, ~/Documents/~/Desktop (iCloud Desktop & Documents, the song workspace), Dropbox, Google Drive or OneDrive;
  • take/history archives skip remote: entries (app-native/src/takestore.rs) and re-resolve them from the cache;
  • publishing, rooms and sharing carry source text only, so each listener's client captures from their own Spotify session;
  • nothing in the resolver talks to a network.

What you do with an exported stem is your own act, as with any sample. Spotify's loudness normalisation changes capture level. Turn it off (Settings ▸ Playback) for level-stable captures. Captures stay deterministic per machine configuration either way.

Field test#

Automated tests never drive Spotify or raise a permission prompt. Run this once on a Mac with macOS 14.4+ and the Spotify desktop app (logged in).

  1. Probe without permissions (optional): cargo run -p volta-capture --features remote-macos --example remote_probe lists Core Audio's process objects with their bundle IDs and checks the host clock. It creates no tap and sends no AppleScript. With Spotify playing, its processes show <- spotify; that match is what the tap records.
  2. Build the CLI with the real seams: cargo build --profile fast -p volta-cli. Its volta-capture dependency enables remote-macos.
  3. Write a test song /tmp/rs.volta:

    tempo = 120bpm
    hook = remoteSample "spotify:track:4uLU6hMCjMI75M1A2tKUQC" 64s 4s
    p = patch { source = hook, gain = const 0.8 }
    lead = play p !"c4 ~ ~ ~"

    Before running, put Spotify on another track, paused at a position you note, with Spotify's volume at about 50, so the restore is visible.

  4. Run target/fast/volta capture /tmp/rs.volta from Terminal. macOS attributes both prompts to the terminal app:
    • Automation: "Terminal wants access to control Spotify". Choose Allow. If you missed it: System Settings ▸ Privacy & Security ▸ Automation ▸ Terminal ▸ Spotify.
    • System Audio Recording: the first tap creation asks. Allow it under System Settings ▸ Privacy & Security ▸ Screen & System Audio Recording ▸ System Audio Recording Only ▸ add Terminal. A run before the grant reports the capture was silent …. Grant, then run again.
  5. Expect. Spotify starts the target without you hearing it, and stderr prints queued → capturing → ready … (captured) about 6 s later. Spotify then returns to your track, position, paused state and volume 50. The track's playlist/queue context is not restored: AppleScript cannot read it.
  6. Check the audio. Run volta capture --list and look for the key, ~1.4 MB, 1:04.000–1:08.000 and the track name. Then afplay ~/.volta/captures/<key>.wav. It should be 4.000 s, stereo, and start at 1:04 of the track.
  7. Check alignment (optional). Add hook2 = remoteSample "…same uri…" 65s 4s and capture again. The overlap of the two WAVs should line up within a few ms (cross-correlate them). If every capture starts consistently early or late against a reference copy of the track, set VOLTA_SPOTIFY_LATENCY_MS=<ms> (positive = Spotify's position leads its audio) and recapture.
  8. Check the workbench. Run cargo run --profile fast -p volta-studio -- /tmp/rs.volta. Change the span to 70s 4s and Run. The drawer row goes queued → capturing → ready · captured, and the note sounds once the capture lands, with no reload. clear cache, then re-capture, should work.
  9. Check exports. volta export stems /tmp/rs.volta -o /tmp/rs-stems/ succeeds. After volta capture --clear it fails with refusing to render: 1 remote sample is not captured ….
  10. Free account (if you have one). An ad before the target is waited out (up to 75 s). An ad inside the span fails with Spotify switched from … and leaves nothing in the cache.

If the tap records silence even with the grant, Spotify's audio may come from a process the bundle-ID match missed. Report the output of ps -axo pid,comm | grep -i spotify.

Notes & limits#

  • Spotify on macOS only, desktop only. Other services and platforms are ideas (Ideas § Remote samples).
  • Unbundled binaries. The TCC prompts name the terminal (or the IDE) that launched volta-studio. A .app bundle would give Volta its own entry. That is open.
  • Timing accuracy is set by the transport round trip. Against the simulator, with 30 ms polls, the cut lands within 3 ms, and within 1 ms with 4 ms polls (capture/src/remote/tests.rs). An unknown player output latency shows up as a constant offset, which VOLTA_SPOTIFY_LATENCY_MS corrects. These numbers come from tests against the simulator; real-player numbers come from the field test.
  • No mini-notation names. remote: keys cannot be played from mini-notation (sound "…") yet; bind the reference and play it.
  • Re-capturing replaces the cached file; songs already playing it keep the old buffer until the new one lands.