Skip to content

Publish an Audio Sample Pack

Assemble the palette an sfx-sample run mixes over or the instrument bank a music run plays. A clip is ingested into the Test Cabinet object store once, a pack manifest collects clip ids and gives each one this pack’s presentation, a publish uploads the normalized bytes that pack’s profile needs, and staging the audio store puts the pack where a run can be given it. Publishing an Audio Sample Pack is the full walkthrough, including the bucket, token and Freesound setup.

  • A source checkout with a working Node toolchain, and ffmpeg on PATH to normalize at publish time and to detect pitch when curating a bank.
  • The R2 credentials in the repo-root .env. Ingest and publish use the write pair, staging the store uses the read-only presign pair, and both need CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_AUDIO_R2_BUCKET. The guide’s environment table lists them.
  • FREESOUND_API_KEY in the repo-root .env for ingest. No other step contacts Freesound.
Terminal window
# Fetch, verify, upload sources/<clip-id>, and record the clip in clips.toml.
node scripts/curate-instrument-bank.mjs --ingest <freesound-url> --publish
# Or curate a whole instrument bank: CC0 search, pitch detection, ingest.
node scripts/curate-instrument-bank.mjs --bank gm-lite

A clip’s id is the sha256 of its original bytes. Ingest runs once per clip; a clip already in containers/sample-packs/clips.toml is left alone.

Add or edit [[entry]] blocks in containers/sample-packs/<pack>.toml, each naming a clip id plus this pack’s name, tags and description. Bump version, since a test case pins a palette as name@version.

Terminal window
# Parse and validate the manifest, its clip ids and its lock coverage offline.
node scripts/build-sample-pack.mjs gm-lite --check
# Normalize and upload only what is missing, recording objects.lock.json.
node scripts/build-sample-pack.mjs gm-lite --publish
# Commit the registry, the manifest, and the lock.
git add containers/sample-packs/clips.toml \
containers/sample-packs/gm-lite.toml \
containers/sample-packs/objects.lock.json

Publishing is per clip and per normalize profile, so editing one entry uploads one object and leaves the rest of the pack untouched.

scripts/stage-audio-store.mjs downloads each object through a presigned GET, verifies it against objects.lock.json, and lays out a shared clip tree under dist/audio-store/tree with a copy of that lock beside it. A missing lock entry, a failed presign, or a digest mismatch fails staging, and staging never contacts Freesound.

./containers/build.sh audio-store runs the stager and builds the data-only image over its output. The Azure pipeline builds and pushes the same image to testcabinet.azurecr.io on every push to master and staging.

Terminal window
./containers/build.sh audio-store

The driver image copies that store in, and scripts/fetch-audio-store.sh pulls it onto a local checkout. A run container is then given the packs its test case declares in [audio] packs; no run image is rebuilt for a new pack version.

The pipeline pushes that image once the pack reaches staging or master, so it is not something to wait for before trying the pack. make -C deployments/local audio-store builds the store the local driver image carries from this checkout, and scripts/fetch-audio-store.sh --stage does the same for a host-side tcab run — both straight out of the object store, with no registry involved.

Terminal window
cat containers/sample-packs/objects.lock.json
node scripts/stage-audio-store.mjs [email protected]

The lock lists every published key with its bucket, digest and size. The stager writes packs/[email protected]/pack.toml plus the clips it names, and needs the presign credentials in .env.