Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 nord command. 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

FilesWhat drawbar doesTested on an instrument
Electro 5 programs, live slots, set lists and settingsView, edit, transferYes
Stage 2, 3 and 4 programs and presetsView, editNo
Sample instruments (.nsmp, .nsmp3, .nsmp4)Decode, edit, encode, audition, transferPlayback 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, transferTrimmed, 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 filesRecognised 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.

PartWhat 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 dockThe send queue and the activity log.
Status barThe 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

CommandWorks on
inspectFiles: print what is in them
verifyFiles: check that they re-encode byte for byte
editFiles: change fields in any editable file
deviceThe instrument: what is attached and what it holds
program, setlist, live, settingsPrograms, set lists, live slots and settings on the instrument
sample, pianoSample 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 .cn3 library, and ZIP backup bundles behind the bundle feature.

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

ModuleRole
wireFraming and codec. No I/O.
transportThe byte pipe, and the only code that touches a device.
sessionThe transaction every operation runs inside.
opTyped operations.
deviceAn instrument as a value: session brackets and its geometry.

Features

FeatureDefaultGives
nusbyesDesktop backend for macOS, Linux and Windows, in pure Rust.
webBrowser backend over WebUSB. Chrome and Edge only.
replayDrive the protocol from captures, with no hardware.
blockingBlock on the async API from synchronous code.
corpusTests against the private capture corpus. Implies replay.
fault-injectionDeliberate 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.