drawbar
drawbar reads, edits and moves the sounds on a Nord keyboard. It comes as an app
that runs in your browser or on your desktop, and as nord, a command for your
terminal.
Alpha software. Back up your instrument and your files before you use it. The file formats and the USB protocol were worked out by studying real instruments, and What is supported says exactly what has been tested on hardware.
Open drawbar at drawbar.app in Chrome or Edge.
Install covers the desktop app and nord.
In this guide
- drawbar is the app. Start with The window.
- nord-cli is the
nordcommand. Start with its overview. - Reference is for developers: building from source, the file formats, the USB protocol, and how to contribute.
Both tools are built on two Rust libraries you can use in your own projects:
nord-format for files and nord-usb for the instrument. The source is on
GitHub.
Disclaimer
Not affiliated with, authorized, or endorsed by Clavia DMI AB. “Nord”, “Clavia”, and “Electro” are trademarks of Clavia DMI AB, used here only to identify the hardware these formats come from. Proprietary sound libraries and firmware are not distributed here.
Install
In the browser
Open drawbar.app. Nothing to install, and your files stay in the browser’s own storage.
Only Chrome and Edge can connect to an instrument, because Firefox and Safari do not support WebUSB. Files work in any browser.
Close Nord Sound Manager before connecting. It keeps the USB connection to itself, so nothing else can reach the instrument while it is running.
On the desktop
With Nix and flakes enabled:
nix run github:jmoo/drawbar#drawbar
The nord command
cargo install nord-cli # installs `nord`
nix run github:jmoo/drawbar#nord-cli -- --help # or run it with Nix
There are no packaged downloads yet. To build either from a source checkout, see Building from source.
What is supported
drawbar was developed against a Nord Electro 5, and that is where its claims have been tested. Files from other instruments are supported from documentation and sample files. Connecting other instruments over USB has not been tried.
Files
| Files | What drawbar does | Tested on an instrument |
|---|---|---|
| Electro 5 programs, live slots, set lists and settings | View, edit, transfer | Yes |
| Stage 2, 3 and 4 programs and presets | View, edit | No |
Sample instruments (.nsmp, .nsmp3, .nsmp4) | Decode, edit, encode, audition, transfer | Playback of v2 files. Files encoded as v3 or v4 have not been played |
Piano libraries (.npno) | Decode, trim, split, rename, retune, remap, build from WAVs, transfer | Trimmed, built and re-encoded libraries play, mono and stereo, across every key they cover. Renames, retunes, remaps and a narrowed key range have not been played |
| Other Nord files | Recognised and kept byte for byte, without editing |
USB
Reading and writing programs, set lists, live slots, settings, samples and pianos works on the Electro 5 from macOS, Linux and the browser. Windows builds pass the protocol tests but have not been run against an instrument. No other instrument has been connected, so USB support for other models cannot be guaranteed.
What “tested” means
Every file drawbar writes is read back and checked to be identical, byte for byte. That proves the bytes survive. It does not prove that every value means what drawbar says, or that every new sound plays as intended. Where a claim has been confirmed by playing it on an instrument, this page says so.
Developers can read how the checks work in Testing and File formats.
The window
drawbar is one window over two places: the files on your computer and the sounds on your instrument. Open it at drawbar.app, or run the desktop app.
| Part | What it is for |
|---|---|
| Browser (left) | PLACES lists this computer and, once connected, the instrument’s folders. KINDS and TAGS narrow the list. |
| Library (centre) | One table over both places, with a Search… box. Sort by any column. |
| Documents (centre) | Every sound you open gets a tab beside the Library. |
| Keyboard (centre) | The instrument’s folders drawn as banks of slots, once connected. |
| Inspector (right) | What is picked, and while connected, how full each folder is. |
| Bottom dock | The send queue and the activity log. |
| Status bar | The last thing that happened. Click it to open the log. |
The toolbar holds Open, New and Save, and once connected, Read and Send. Each dock collapses and resizes, and the layout is kept between sessions.
Picking and acting
Click a row to pick it, ⌘-click to add more, ⇧-click to pick a run, and double-click to open. Right-click for a menu that acts on everything picked. In the Library, tick the checkboxes to act on many rows at once from the footer. F2 renames.
Reading the Library
The where column says where a sound lives: on this computer, on the keyboard,
or both, with = when the two copies match and ≠ when they differ. A name in
italics with a * has unsaved edits. The dot at the end of a row is green when
the slot holds what you saved, yellow when it holds something else or a send is
waiting, and grey while that is still unknown. Hover any of them for an
explanation.
Folders and tags
Folders group sounds on this computer; the instrument never sees them. Tags label sounds without moving them, and a sound can carry several. Both come from a row’s menu or the New menu. Removing a folder or a tag deletes no sounds.
Theme
The button at the top right cycles between following your system, light, and dark.
Your files
This computer is drawbar’s own list: what you open, what you make, and what you copy off an instrument.
Opening and making
Drop files on the window, or use File ▸ Open…. Every file is decoded and immediately re-encoded to check that its bytes come back identical, and the activity log tells you if one does not. A file drawbar cannot read still gets a row, so you can see what went wrong.
New makes a fresh program, live slot, set list, settings file or preset for each supported instrument, a sample instrument or Sample Editor project from WAVs, a piano library from WAVs, or a folder. A fresh Stage file has every control at zero. It is not a factory program.
Views
Opening a slot on the instrument shows a view: the instrument’s own copy, in place. It is not on this computer until you click Keep on this computer. If you edit a view, it is kept when its tab closes, so the edits are not lost.
Saving and reverting
Every edit lands at once, and the name turns italic with a * until you save or
revert. Save (⌘S) marks the current state as saved. If the sound belongs to a
slot on the connected instrument, Save also queues it for sending. Revert goes
back to the last save, and is the only undo.
What is kept
The list, with its folders, tags, edits and layout, is stored in the browser, or beside the desktop app, and comes back next time. Two limits apply, and the log says when they bite: a single sound over about a megabyte is not kept, and the whole list is capped at about 3 MB. Samples and piano libraries are usually larger, so export them.
Long-term storage is not guaranteed while drawbar is in alpha. Keep your own copies.
Exporting and names
Export… writes a copy of the file: a download in the browser, a save dialog on the desktop.
A sound’s name comes from the slot it was read from, the filename, or the New menu, and drawbar shows it without the extension. Rename with F2 or the name box in the document header. Where the file stores a name of its own, as samples and pianos do, that box edits the stored name.
Your instrument
Back up your instrument before you send anything. Nord Sound Manager makes a full backup. What is supported says which instruments have been tested.
Connecting
Close Nord Sound Manager first, since it keeps the USB connection to itself. Then click Connect an instrument… in the browser, or Instrument ▸ Connect…. The browser asks you to pick the device. The desktop app takes the first Nord it finds.
Once connected, drawbar reads every folder the instrument declares, a bank at a time, and the instrument’s controls appear: Read and Send in the toolbar, the Keyboard tab, the send queue, and the inspector’s room meters. Read rereads everything, and each folder has its own Read again.
Slots are labelled the way the panel shows them, 7:4 Africa Split. Empty slots
are listed too, as places to drop things.
Slots
Right-click a slot to Open, Copy to this computer, Load on instrument, Rename, Duplicate or Delete…. Rename happens straight away, because renaming back is its own undo. Delete asks first.
Drag to move things:
- a slot onto This computer copies it;
- a sound onto a slot queues it for sending;
- a slot onto another slot in the same folder swaps the two, losing nothing.
A slot that cannot take what you are dragging does not light up. Drop anyway and the log says why.
The send queue
Nothing is written until you send. Drops, Queue for sending, and Save on a sound that belongs to a slot all add to the queue in the bottom dock. Each row shows its destination: click it to change it, × to remove the row, and pick a row to see what would change on the keyboard.
Send all asks once, listing every destination and what it replaces, then writes folder by folder. If the instrument refuses an item, that folder’s batch stops there. What was written stays, and the rest stays queued. The queue also survives a disconnection.
A sound’s name goes with it, minus the file extension: Africa-Split.ne5p on
this computer becomes Africa-Split on the panel.
Safety
- drawbar never leaves a write session open. Each write opens one, finishes, and closes it, so an interrupted transfer cannot leave the instrument stuck on its progress screen.
- A move is a swap, never an overwrite.
- Writing into an occupied slot deletes the old sound first, because the instrument refuses to overwrite in place. drawbar reads the old sound into memory before deleting it, writes it back if the new write fails, and if that fails too, keeps its bytes on this computer as a rescued sound.
- Live slots and Settings are overwritten in place. Writing Settings reloads the selected program, so unsaved panel changes are lost. drawbar warns before it does this.
- Writing to the slot the panel is playing reloads it, when drawbar itself selected that slot.
These behaviours have been confirmed on an instrument. Progress shows on the instrument’s own display; drawbar shows a spinner and cannot know a percentage.
Disconnecting
Unplug, and the instrument’s rows and controls disappear. The send queue is kept, so plug back in, review it, and send.
Editing
There is no Apply. A control you move is set on the document at once, and the
name shows a * until you save. Nothing on the instrument changes until you
queue the document and send it.
The document header
Every document has the same strip across the top: its kind and name, a format
badge, where it lives (a slot, a folder, or this computer), its size, and its
state: edited, matches keyboard, differs from keyboard, waiting to send
or on the keyboard. Hover any of them for the detail.
To the right are the document’s faces, Revert, Export…, and the one
action the document is for. That is usually Queue send. It is greyed when
there is nowhere to send to, and becomes a warning such as Won't fit · 70 MB over when the send cannot happen yet.
The faces
- Edit is the sound’s controls, in the instrument’s own words.
- Metadata is what the file says about itself, and changes nothing.
- Advanced is every field in the file as a table, for when you need a value the Edit face does not draw. Type into the Writes column to set one. A value the field cannot hold is refused, with the reason.
Programs, live slots, settings and presets
These open on a panel divided into sections the way the instrument’s is, with a
strip of chips at the top to jump between them. Each field is drawn as the
control the panel uses: a lamp for a switch, a menu for a selector, a knob with
the panel’s own reading, drawbars you pull down, a grid for a pattern. A value
drawbar has no name for reads unknown (6), and stays in its menu so you can
change back.
Every control answers the keyboard. Tab reaches it, the arrow keys step a knob, Page Up and Page Down jump it, Home and End take it to its stops, and Space flips a lamp. Double-click a knob to type a value.
Where a program refers to a piano or sample by id, drawbar asks the connected instrument for its name and shows it. Sections the program stores but is not using are folded away, with a line saying so.
A control with a morph shows three dots. Pick a morph source from the MORPH chips and every morphed control shows that source’s target instead. Editing then writes the morph.
Set lists
A set list opens as the programs it plays, one row each, with its bank and slot, the program’s name where drawbar knows it, and whether the entry resolves. Drag rows to reorder them.
Files with nothing to edit
A file drawbar recognises but cannot yet edit opens with what the container says and a look at its bytes. It can still be sent, copied and tagged, and goes up byte for byte as it came down.
Sample instruments and piano libraries have editors of their own. See Samples and Pianos.
Samples
drawbar edits sample instruments (.nsmp) and Nord Sample Editor projects
(.nsmpproj) in the same editor. An instrument carries its audio. A project
points at WAV files.
The key map
The key map stays at the top. Each zone is a band over the keys it answers, and keys nothing answers are hatched. Drag a band’s edge to move it. The older v2 layout stores only each zone’s top note, so dragging one moves its neighbour too. The v3 and v4 layouts let you pull zones apart and leave keys silent.
Click a key to hear it. The line under the keyboard says which zone answered and by how much it was shifted, or why the key is silent.
Zones
One row per zone: the keys it answers, its length and channels, and its size. Open a row to edit its root and top note, see its waveform with Show audio, play it, or Save WAV…. Velocity windows are shown but cannot be edited in an instrument.
A v2 instrument also has a gain and a detune for every key. Per key draws them as two lanes you paint across, or as a table for one key at a time.
Projects
A project opens in the same editor with everything editable: both ends of each zone, velocity windows, trims, loops, crossfades, source files and the sound parameters. It is saved back as the text file the Sample Editor reads. drawbar cannot build a project into an instrument yet.
From WAVs
Drop a WAV on the window and its document can Encode it into a one-zone instrument. New ▸ Sample instrument… takes several WAVs, one zone each, with a root key for each. New ▸ Sample Editor project… makes a project from them instead, and the Sample Editor expects the WAVs to stay beside it.
Instruments encoded as v2 have been played on an instrument. v3 and v4 are offered but unverified. See What is supported.
Sending
Queue an instrument from its header like anything else. Samples are usually larger than what drawbar keeps between sessions, so export the ones you want to keep.
Pianos
A piano library (.npno) holds one recording, called a stroke, per root
note, bank and velocity layer. The editor is for choosing which strokes go to the
instrument, so that a library fits the memory it has free, and for setting how it
plays.
Edits are a plan
An edit does not rewrite the library. It is a plan over the saved file, shown at
once, and every switch can be turned back on. The file is laid out only when it
has to be: on Save, Export, or Queue send. The header reads applying… while
that runs, and the action waits for it.
The key map
Each root has a cell over the keys it answers, showing the megabytes it keeps. Drag the boundary between two roots to move keys, and the outer ends to cover or uncover keys. Click a key to hear which root answers it. Keys above the damper limit are shaded.
Trim to fit
A list of switches, each with the size it keeps: one per velocity layer, Pedal resonance, Release samples, and Keys, which narrows the range to the middle of the keyboard. Beside them, a meter compares the library with the free piano memory the instrument reports, and a sentence names the cheapest cut that would make it fit. A library that does not fit cannot be queued.
Velocity layers goes finer: one lane per layer, one segment per root. Click a segment to drop that layer for that root only.
Playback
Instrument gain, the damper limit (Keys ring on above), and Kind, which is what the instrument files the library under. Kind changes nothing about the sound.
Roots lists each root with its strokes. There you can trim a stroke in dB, audition the root, save it as a WAV, or drop it. Per key paints a fine tune across the keyboard.
A new library
New ▸ Piano library… takes one WAV per stroke. A file named like
060-b0-l00.wav fills in its root (MIDI note 60), bank and layer for you.
Otherwise set them in the dialog. Template builds on a library already on
this computer, and the default builds from drawbar’s own rules. Set the kind,
gain and damper limit in the new document afterwards.
Libraries drawbar has built or trimmed play on an instrument across every key. Renames, retunes and remaps have not been played. See What is supported.
Sending
Queue a library from its header. It is checked against the instrument and its free space first. Libraries are far larger than what drawbar keeps between sessions, so export what you want to keep.
Help and About
Help ▸ User guide opens this guide.
Help ▸ What’s new shows, in the browser, the notice that opens on the first run of each version: the alpha warning, what to expect of this build, and the release notes. drawbar remembers which version you have dismissed. On the desktop, the item opens the release page instead.
Help ▸ Copy activity log puts the whole log on the clipboard, for a bug report.
Help ▸ About drawbar shows the version, links to the source, the guide and the releases, the trademark disclaimer, and every licence a copy of drawbar has to carry: drawbar’s own, the bundled fonts and icons, the Stage field maps it decodes with, and the Rust crates compiled in. Click a row to read it.
Overview
nord works on Nord files and on a connected instrument from the terminal. It
prints data to stdout and everything else to stderr, so its output pipes
cleanly, and every command that changes the instrument says what it is about to
replace and refuses without --yes.
cargo install nord-cli # or: nix run github:jmoo/drawbar#nord-cli
nord --help
Commands
| Command | Works on |
|---|---|
inspect | Files: print what is in them |
verify | Files: check that they re-encode byte for byte |
edit | Files: change fields in any editable file |
device | The instrument: what is attached and what it holds |
program, setlist, live, settings | Programs, set lists, live slots and settings on the instrument |
sample, piano | Sample instruments and piano libraries, on the instrument or as files |
program, setlist, sample and piano share the same verbs: get and put
to transfer, move, rename, duplicate, delete and select to organise,
info, deps, list and focus to look, and edit. live and settings
keep only the verbs that make sense for them. The read-only verbs and edit also
take a file in place of a slot. raw --class N reaches an object class by
number, for anything without a command of its own.
Slots
Slots are written BANK:SLOT, counted from 1, the way the instrument shows
them. 7:4 is bank 7, slot 4.
Output
Colour and Unicode appear only on a terminal, and piped output is plain ASCII.
--color=always, --color=never and NO_COLOR override that. Off a terminal,
a command that would ask for confirmation fails instead, unless you pass
--yes.
Next: Files, The instrument, Editing, and Samples and pianos.
Files
nord inspect patch.ne5p # what is in a file
nord inspect *.ne5p # several at once
nord inspect --raw song.ne5t # everything, as decoded
nord verify *.ne5p # check each re-encodes byte for byte
inspect prints a summary in the instrument’s own terms: the parts and their
settings, the effects, and which piano and sample a program depends on. It exits
non-zero if any file fails to parse.
verify reads a file, writes it back, and checks that the bytes are identical,
reporting the offset of the first difference if not. Every supported format
passes, pianos and samples included. nord piano verify --deep and nord sample verify --deep also decode every recording inside.
A file where a slot goes
get, info and deps take a file wherever they take a slot, so you can look
at a file without an instrument:
nord program get patch.ne5p # the same summary as for a slot
nord program info patch.ne5p # format, version, checksum
nord program deps patch.ne5p # the piano and sample ids it refers to
A file stores ids, not names. deps on a slot asks the instrument for the
names. On a file, it prints the ids.
Changing what is inside a file is Editing.
The instrument
Back up first. Nord Sound Manager makes a full backup, and it must be closed
before nord can connect, since it keeps the USB connection to itself.
What is supported says which instruments have
been tested.
nord device status # what the instrument holds; --json for scripts
nord device info # what is attached
nord device recover # release a session an interrupted run left open
nord program list # every occupied slot
nord program focus # what the panel has loaded
nord program get 7:4 # print the summary
nord program get 7:4 -o patch.ne5p # or save the file
nord program put patch.ne5p 7:4 --yes # send a file to a slot
nord program move 8:13 7:16 --yes
nord program duplicate 7:2 7:3 --yes
nord program rename 6:13 "Warm Pad" --yes
nord program delete 7:50 7:49 --yes
nord program select 2:12 # load it on the panel
nord program info 7:4 # size, format, name, checksum
nord program deps 7:4 # the piano and sample it uses, by name
The same verbs work on setlist, sample and piano. live and settings
take get, info and edit.
Before anything changes
A command that changes the instrument reads the slot first, says what it is about to do, and stops:
$ nord program duplicate 7:2 7:3
duplicating "Africa Split" from bank 7 slot 2 to bank 7 slot 3 — OVERWRITING "Squabble B"
error: refusing to proceed without --yes
move reports a swap rather than an overwrite, because the instrument exchanges
the two slots and nothing is lost. It also lists the set lists that point at the
program, since the instrument updates them to follow it. put names the slot
after the file.
--yes skips the question. There is no --force, and nothing skips the read.
What a write does
The instrument does not overwrite an occupied slot in place, so a put into one
deletes the old sound first. nord reads the old sound before deleting it, and
puts it back if the write fails. If that fails too, the old bytes are saved in the
working directory as a file such as nord-rescued-7-50.ne5p, which put takes
straight back. Live slots and settings are the exception: the instrument
overwrites those in place.
Every command closes its session even when it fails, so an error cannot leave the
instrument stuck on its progress screen. If a run is interrupted, nord device recover releases the session.
Editing
edit changes fields inside a program, live slot, settings file, set list or
sample instrument, in a file or in a slot. Piano libraries have flags of their
own, covered in Samples and pianos.
nord program edit --fields # every field, and what it accepts
nord program edit patch.ne5p --set center_panel.gain=96 -o out.ne5p
nord program edit patch.ne5p --set effects_panel.fx1_rate=96 --yes # in place
nord program edit 7:4 --set center_panel.split=true --dry-run # on the instrument
nord program edit --set center_panel.gain=64 -o fresh.ne5p # a new program
Editing a slot reads it, changes it and writes it back, so it asks first. Editing
a file in place asks too. -o writes somewhere else instead, and --dry-run
shows which fields and bytes would change without writing anything.
Values
Spell a value the way inspect and --fields print it. A value the field cannot
hold is refused before anything is written:
$ nord program edit patch.ne5p --set center_panel.gain=200 --dry-run
error: "200" is not a value of gain (accepts 0 .. 127)
Some fields work in pairs. A transpose amount is ignored unless transpose is enabled, so setting one without the other gets a warning.
Live slots and settings
nord live edit 1:2 --set center_panel.gain=96 --yes
nord settings edit 1:1 --set fine_tune=0 --dry-run
Writing settings reloads the program on the panel, and unsaved panel changes are lost. Store them first.
Set lists and samples
A set list’s fields are the slots it plays, slot1 to slot4. A sample
instrument’s are its name and each zone’s root key and top note, plus its low
note in the layouts that store one. Notes are written as names (C4 is middle
C) or as numbers, and --fields lists exactly what a given file offers.
nord setlist edit song.ne5t --set slot1=2:5 --set slot4=8:50 -o out.ne5t
nord sample edit inst.nsmp --set name="My Piano" --set zone2.top_note=C4 -o out.nsmp
Any file
nord edit works out the format from the file itself, so it reaches everything
the commands above do, plus formats without a command of their own: Stage
programs and presets, and Sample Editor projects.
nord edit stage.ns3f --fields
nord edit stage.ns3f --set split_enabled=true -o out.ns3f
nord edit project.nsmpproj --set name=Marimba --set zone129.root_key=C3 --yes
Samples and pianos
Sample instruments (.nsmp) and piano libraries (.npno) hold encoded audio.
Both move to and from the instrument with get and put, like a program. The
verbs below reach the audio.
Samples
nord sample decode inst.nsmp -o out/ # every zone as a WAV
nord sample verify --deep inst.nsmp # decode every recording too
nord sample project new --zone a.wav=C3 --zone b.wav=C4 --name Marimba -o marimba.nsmpproj
nord sample build marimba.nsmpproj -o marimba.nsmp # render a Sample Editor project
encode turns a single WAV into an instrument, and build renders a whole
project, loops and stereo included. --generation 2, 3 or 4 picks the
layout. Only v2 has been played on an instrument, so v3 and v4 require
--unverified.
Pianos
nord piano inspect grand.npno # roots, layers, keys, tuning
nord piano inspect grand.npno --keys # every key, its root and fine tune
nord piano decode grand.npno --key C4 --layer 0 -o c4.wav
nord piano edit grand.npno --name "My Grand" --tune C4=-2 --map C8=C7 -o out.npno
nord piano trim grand.npno --drop-bank release --layers 3 -o small.npno
nord piano split grand.npno --at C4 -o halves/
nord piano verify --deep grand.npno
edit, trim and split rewrite the library without touching its audio:
rename it, retune or reroute a key, drop a bank or the quieter layers, narrow the
range, or cut it in two. trim and split never write over their input. edit
does only with --yes.
Building a piano library
build makes a library from a directory of WAVs, one per stroke, named
<root>-b<bank>-l<layer>.wav. 060-b0-l00.wav is MIDI note 60, the attack bank,
the loudest layer. Banks are 0 for attack, 1 for pedal resonance and 2 for
release. Any sample rate is accepted.
nord piano build strokes/ --kind mallet --name Marimba -o marimba.npno
nord piano build strokes/ --template grand.npno --name Marimba -o marimba.npno
nord piano rebuild grand.npno -o again.npno # re-encode a library's own strokes
Every key up to a semitone above the highest root plays the nearest root above
it. Keys beyond that are silent. Within a root, velocity picks the layer, with
the layers spread across the velocity range in order. Write -v12 instead of
-l00 to set a layer’s velocity value directly.
Whatever the audio does not decide, such as decay and per-note tables, comes from
--template when you give one, and from neutral defaults when you do not. Both
kinds of library have been played on an instrument and sound the same.
What has been played
Libraries drawbar has trimmed, built or rebuilt play on an instrument: mono and stereo, every key including the lowest and highest root, all three attack layers, the release stroke, and a vendor library re-encoded and indistinguishable from the original. Renames, retunes, remaps and a narrowed key range have not been played. See What is supported.
Building from source
Everything goes through Nix, so a checkout needs nothing else installed.
git clone https://github.com/jmoo/drawbar && cd drawbar
nix run .#drawbar # the desktop app
nix run .#drawbar-web # the browser build, served with this guide beside it
nix run .#nord-cli -- --help # the nord command
nix build .#site # the tree published at drawbar.app
nix build .#docs # this guide
nix run .#drawbar-web serves on http://127.0.0.1:8080/. Set DRAWBAR_PORT
for another port.
With Cargo
nix develop opens a shell with the toolchain. Run Cargo from crates/, because
crates/.cargo/config.toml carries a flag the wasm build needs, and Cargo finds
it by walking up from the working directory.
nix develop
cd crates
cargo run -p drawbar
cargo run -p nord-cli -- --help
cargo test --workspace
The browser build by hand
nix build .#drawbar-web does all of this in one step. By hand, from crates/:
cargo build -p drawbar --lib --target wasm32-unknown-unknown --release
nix run --inputs-from .. nixpkgs#wasm-bindgen-cli -- \
--target web --out-dir drawbar/pkg \
target/wasm32-unknown-unknown/release/drawbar.wasm
cd drawbar && python3 -m http.server 8000
Two things matter here. --lib is required, because the crate also has a binary
target of the same name, and if that one wins the wasm module exports nothing.
And wasm-bindgen-cli must match the wasm-bindgen version in Cargo.lock
exactly. --inputs-from .. takes it from the flake’s pinned nixpkgs, which does.
Serve over http://localhost, which counts as a secure context. WebUSB and the
module import both fail from file://. This plain server has no guide beside the
app, so Help ▸ User guide finds nothing there. nix run .#drawbar-web serves
both.
Checks
nix flake check runs formatting, Clippy with warnings denied, and the version
check. nix build .#nord.all builds every crate with its tests, the cross
targets, the browser build and this guide, which is what CI runs. nix fmt
formats everything. Testing describes the suites, and
Contributing the house rules.
File formats
nord-format reads and writes Nord files. It is a pure library: no USB, no I/O
beyond Read, Seek and Write, and it builds for the browser.
Round trips
Whatever the library reads, it writes back byte for byte. Regions it does not decode are kept as raw bytes, and decoded values are views over them, so a file survives a round trip even where its meaning is not fully known. Every fixture and every file in the private corpus is checked this way, and every editable field is set and read back to prove it moves no other bit.
The support map
The authoritative list is in the formats module documentation on
docs.rs, beside the
code. Each decoded body’s documentation says how far reading and writing go, what
a read validates, where the field placements came from, and shows the generated
byte map. There are three tiers:
- Decoded: every field named. Electro 5 programs, live slots, set lists and settings; Stage 2, 3 and 4 programs and live slots; the Stage 3 synth preset; the Stage 4 synth, piano and organ presets.
- Structurally decoded: the container and layout are understood, and the audio is decoded and encoded. Sample instruments in every layout, piano libraries, and Sample Editor projects.
- Container-verified: recognised, checksummed and carried verbatim. Every
other CBIN tag, the Lead SysEx banks, the
.cn3library, and ZIP backup bundles behind thebundlefeature.
Both generations of the CBIN container are read and written: the current one
with a CRC-32 over the body, and the older one with a CRC-16 over the whole file.
The field registry
Every #[bitbody] layout generates a registry. fields() lists each field with
its path, placement, current value and accepted values, and set_field(path, value) writes one back through the type’s own parser. That is what nord edit --fields prints and what drawbar’s Advanced table shows, so a field becomes
editable by being declared.
Each field carries its control kind: a knob with a unit, a bipolar knob, a
selector, a drawbar, a morph slot, a pattern grid, or a library reference.
panel::of adds the layout for formats that have one: which controls sit
together, in what order, and which the instrument is using for the state the file
holds.
#![allow(unused)]
fn main() {
let entity = nord_format::from_path("patch.ne5p")?;
if let Some(panel) = nord_format::panel::of(&entity) {
// ordered, nestable groups, each with a condition over the body's values
}
}
Features
bundle enables ZIP backup bundles and is off by default. corpus is for tests
only and points the sweep at the private corpus. See Testing.
To build the API documentation locally:
cd crates && nix develop -c cargo doc --no-deps --open
USB protocol
nord-usb speaks the protocol Nord Sound Manager uses, worked out from USB
captures. It moves bytes to and from the instrument. nord-format owns the
bytes.
What works
Verified on an instrument from macOS: inventory, object info, dependencies, geometry, focus, walking the occupied slots, reading and writing programs and set lists, moving, deleting, renaming, duplicating and selecting slots, reading and writing live slots and settings in place, and reading, deleting and writing sample and piano libraries. From Linux, reads and a multi-chunk sample write are verified, and every recorded request is byte-identical to its macOS counterpart. The WebUSB backend is verified for reads and writes from Chrome. Windows passes the replay tests but has not been run against an instrument.
Not implemented: backup bundles, firmware updates, and relink.
The wire
Every message is a length-prefixed frame of big-endian 32-bit words with a CRC-16 trailer:
┌────────┬─────────┬───────────┬─────────┬───────────────┬───────┐
│ length │ service │ subsystem │ command │ args… │ crc16 │
└────────┴─────────┴───────────┴─────────┴───────────────┴───────┘
The CRC is CRC-16/CCITT-FALSE. A response carries the request’s command plus
one, with a status word inserted before the echoed arguments. Two things bite.
Request codes are not reliably even, so direction is recorded at decode time
rather than inferred. And operations are generic primitives parameterised by
object class (1 piano, 3 sample, 4 program, 5 set list, 6 live, 7 settings), so
one rename or move command serves every class.
The instrument reads a message until a short packet ends it. A frame that is an exact multiple of the packet size needs a zero-length packet after it, or the device never answers.
The closing exchanges of a transaction clear the instrument’s progress display. Abandoning a transaction after a progress label has been sent leaves the device stuck until it is power-cycled, which is why every session closes on the error path.
Layering
| Module | Role |
|---|---|
wire | Framing and codec. No I/O. |
transport | The byte pipe, and the only code that touches a device. |
session | The transaction every operation runs inside. |
op | Typed operations. |
device | An instrument as a value: session brackets and its geometry. |
Features
| Feature | Default | Gives |
|---|---|---|
nusb | yes | Desktop backend for macOS, Linux and Windows, in pure Rust. |
web | Browser backend over WebUSB. Chrome and Edge only. | |
replay | Drive the protocol from captures, with no hardware. | |
blocking | Block on the async API from synchronous code. | |
corpus | Tests against the private capture corpus. Implies replay. | |
fault-injection | Deliberate protocol faults for research. A wrong value can stall the instrument’s endpoints. |
WebUSB handles are not Send, so neither is the Transport trait, which keeps
the crate free of any particular async runtime. Building web needs
--cfg=web_sys_unstable_apis, which crates/.cargo/config.toml supplies when
Cargo runs from crates/.
The API documentation is on docs.rs, and Testing covers the replay suite.
Testing
A failing test should say which behaviour or contract broke. The rules are in CONTRIBUTING.md. Two file-driven sweeps carry most of the evidence: a specimen joins the format sweep by being readable, and a capture joins the replay sweep by existing.
nord-format
cargo test -p nord-format runs the unit tests, a dispatch test that synthesises
a file for every registered tag and round-trips it through both container
generations, the Stage body tests, and the specimen sweep over tests/fixtures:
files this crate’s own writers produced, with sidecars recording what was set.
Each specimen is parsed, round-tripped byte for byte, checked for unnameable
values, and has every registry field set and read back without moving another.
With --features corpus and NORD_CORPUS_ROOT pointing at a checkout of the
private corpus, the same sweep runs over real files, plus format and codec
behaviour suites and a coverage ledger: every bit the instrument varies must
belong to a field or be listed as reviewed debt. nix build .#nord.nord-format-corpus runs it.
nord-usb
cargo test -p nord-usb --features replay
The replay tests drive the whole stack from recorded captures and check that the
bytes the crate emits are the bytes Nord Sound Manager sent. replay is not a
default feature. Without it, cargo test -p nord-usb verifies none of the wire
encoding. The Nix build enables it.
tests/replay runs one trial per script under tests/scripts, and under the
corpus with --features corpus. Every script is checked for framing, and one
that declares an intent is driven through an exact-match transport and judged
against what it said to expect:
# source: nord
# device: Nord Electro 5, firmware v2.04 build 592
# intent: program info 7:11
O 0000001200000006000000010000000006a1
nord … --record <path> writes a complete script. The header keys, the expect
values and the intent table are documented in
crates/nord-usb/tests/scripts/README.md.
Everything at once
nix flake check and nix build .#nord.all run what CI runs. See
Building from source.
Contributing
CONTRIBUTING.md is the authority on style, tests, tooling and releases. Issues and pull requests are on GitHub.
Two rules bear repeating. All reverse engineering is black-box work for interoperability, from files and USB traffic produced by instruments the researcher owns, with no decompiling of Clavia’s software or firmware. And nothing proprietary is committed: no factory presets, sound libraries, firmware, or files shipped with Clavia software. Fixtures are made by this project’s own tools.
This guide
The guide is an mdBook under docs/.
nix build .#docs renders it, and nix develop -c mdbook serve docs previews it
with live reload. Every push to master publishes it at
drawbar.app/docs, beside the app’s latest release.
Community
Other projects that work with Nord files and instruments. The first two are where drawbar’s Stage support comes from.
Used by drawbar
Chris55/nord-documentation · Christian Florentz · BSD-3-Clause
Byte maps for the Stage 2 and Stage 3 program files and the Lead A1, built by diffing saved files one control at a time, without decompiling anything. The first public decode of the Stage 2 and 3 formats, and the source of drawbar’s Stage 2 and 3 field placements. Read it at chris55.github.io/nord-documentation.
ns4decode · Randy · MIT
A Stage 4 file viewer that publishes its offset tables. The first public decode of the Stage 4 program and preset files, and the source of drawbar’s Stage 4 placements.
Other projects
Chris55/ns3-program-viewer · Christian Florentz · GPL-3.0-or-later
A read-only web viewer for Stage 2, 2EX and 3 programs, built on the byte maps above. Open it at chris55.github.io/ns3-program-viewer.
simonflore/opennord · AGPL-3.0
A browser companion for the Stage 4 and Stage 2 that reads, organises and transfers programs and samples, with a fully decoded Stage 4 program body and hardware-verified USB transfer in both directions. Its documentation is thorough, and marks what has been verified on hardware. Open it at opennord.gigmeister.app.
Adding to this list
If you maintain a project that works with Nord files or instruments, open a pull request against this page.