URI Schemes
Every asset loaded by nkido — sample banks, SoundFonts, wavetables, single audio files — is identified by a URI. The same scheme syntax works in akkado source code (samples("...")), on the CLI (nkido --bank ...), and in the web app. A single resolver dispatches each URI to the right backend based on its scheme prefix.
Supported schemes
| Scheme | Example | Native | Web | Notes |
|---|---|---|---|---|
file:// | file:///abs/path.wav | ✓ | — | Absolute or relative filesystem paths. Bare paths (no scheme) are treated as file://. |
http:// | http://example.com/x.json | ✓ | ✓ | Plain HTTP. Cached on disk natively; in IndexedDB on the web. |
https:// | https://example.com/x.sf2 | ✓ | ✓ | TLS via system cert store (native uses OpenSSL). |
github: | github:tidalcycles/Dirt-Samples | ✓ | ✓ | Sugar for raw.githubusercontent.com. See below. |
bundled:// | bundled://default-808 | ✓ | ✓ | Looks up an in-process table populated at host startup. Used for shipping default kits with the binary. |
blob:nkido:<id> | blob:nkido:abc123 | — | ✓ | Web only. Transient handle for File / ArrayBuffer uploads. Register via uriResolver.registerBlob(file). |
idb:<key> | idb:my-bank | — | ✓ | Web only. IndexedDB-stored asset (currently a stub; reserved). |
Bare paths like ./song.akkado or /etc/foo.wav are treated as file:// on native; on the web they have no handler and fail loudly. Windows drive letters (C:\foo) are detected and routed to file:// rather than parsed as a c: scheme.
The github: scheme
A shorthand for https://raw.githubusercontent.com/.... The resolver does the URL transform and recurses through the https handler, so caching and certificate handling are shared between the two paths.
github:user/repo → main branch, root strudel.json
github:user/repo/branch → branch's root strudel.json
github:user/repo/branch/sub/dir → branch's sub/dir/strudel.json
github:user/repo/branch/file.wav → branch's file.wav (audio extension fetched as-is) Audio-extension heuristic: .wav .ogg .flac .mp3 .aiff .sf2 .sf3 .json are fetched as files; anything else is treated as a directory and /strudel.json is appended.
Default branch is main. Specify a different branch as the third path segment.
In akkado source: samples("...")
The samples() directive declares a sample-bank URI for the host to fetch before the program runs. Combine with .bank("Name") on a sample pattern to route events to that bank instead of the bundled default kit:
samples("github:tidalcycles/Dirt-Samples")
s"amencutup:0 amencutup:1 amencutup:2 amencutup:3"
.bank("Dirt-Samples")
.out() Bank names come from the manifest’s _name field, falling back to the last URL segment (so github:tidalcycles/Dirt-Samples → Dirt-Samples). Live demo: dnb-amen in the patch browser.
Multiple samples() calls are allowed; they’re resolved in source order. Identical URIs are deduplicated. Each call must take exactly one string-literal argument (variables are not resolved at compile time).
The compiler emits no audio-time instruction for samples() — it’s a compile-time directive that adds a UriRequest{kind=SampleBank} entry to CompileResult.required_uris. The host (web app, CLI) drains this list before swapping bytecode.
Built-in drum machines: .bank("<Machine>")
The 70+ vintage drum machines of geikha/tidal-drum-machines (TR-808/909/606, LinnDrum, MPC60, Oberheim DMX, …) ship as a built-in catalog — no samples() directive, no UI step. Naming a machine with .bank() auto-resolves it:
// TR-808 kit — samples stream from GitHub on demand
s"bd sd hh hh".bank("RolandTR808").out()
// Mix machines per pattern
s"bd ~ bd ~".bank("RolandTR909").out()
s"~ cp ~ cp".bank("LinnDrum").out()
// Variant selection works as usual
s"bd:0 bd:2 bd:5".bank("OberheimDMX").out() A committed catalog (web/static/samples/tidal-drum-machines/catalog.json, generated by scripts/generate-tdm-catalog.sh) maps every machine’s drum names to files, pinned to an upstream commit SHA. The audio is never bundled — each sample streams from raw.githubusercontent.com on first use and is cached (IndexedDB on the web, the native file cache for the CLI). A failed fetch is a soft failure: a warning is logged, that one voice is silent, the rest of the program keeps playing. Unknown machine names fall back to the normal unknown-bank behavior.
Browse the machines in the web app’s Files panel → Drum Machines section; per-machine Load prefetches a whole kit into the cache for offline use. For the CLI, scripts/download-tdm.sh <Machine> … (or --all) populates ~/.cache/nkido/tidal-drum-machines/, which nkido discovers automatically.
On the CLI
nkido accepts URI-keyed flags for assets supplied outside the program:
# Sample bank from GitHub
nkido render --bank github:tidalcycles/Dirt-Samples
--seconds 5 -o out.wav --source 'sin(440) |> out(@)'
# SoundFont from a local path
nkido render --soundfont ~/Music/gm.sf2
--seconds 4 -o out.wav song.akkado
# Single sample from HTTPS, with explicit registry name
nkido render --sample 'kick=https://example.com/kick.wav'
--seconds 1 -o out.wav --source '0 |> out(@)' Every flag accepts any registered scheme. Bare paths are file://. Multiple --bank / --soundfont / --sample flags may be combined; banks accumulate in declaration order and are searched first-hit-wins for default-bank RequiredSample lookups.
samples() directives in source code are resolved alongside --bank flags (CLI flags first, source declarations after).
.mid files
.mid files use the same scheme table — there is no dedicated midi:// scheme. The midi({file: "..."}) call accepts bare paths, file://, https://, and github: URIs, all resolved through the same cedar::UriResolver as samples and SoundFonts.
midi({file: "drums.mid"}) // bundled or web-registered
midi({file: "file:///home/me/songs/intro.mid"}) // absolute native path
midi({file: "https://example.com/groove.mid"}) // remote, cached after first fetch
midi({file: "github:nkido/example-mids/twinkle.mid"}) // GitHub raw fetch On the web, dragging a .mid onto the Files panel registers it as a transient handle (the bare filename), so the same string works whether the file ships in the bundle or you just dropped it in.
Caching
Native runs cache HTTP responses under the platform-default user cache directory:
- Linux:
$XDG_CACHE_HOME/nkido/(fallback~/.cache/nkido/) - macOS:
~/Library/Caches/nkido/ - Windows:
%LOCALAPPDATA%/nkido/cache/
500 MB cap, evicted by mtime (least-recently-touched first). Cold fetch + parse runs in ~300 ms for the Dirt-Samples manifest; cached re-runs complete in ~30 ms.
Web runs cache in IndexedDB via the existing FileCache middleware around the https handler. The same URI is fetched once across the page session and then served from IDB.
See also
- Mini-notation reference — sample patterns (
sample,seqwith sample IDs) docs/prd-uri-resolver.md— design + history