Skip to content

Your First Project

So far you’ve been evaluating code line by line in VSCode — perfect for exploring and live coding. But when you want to save a piece, share it, or run it straight from the command line, you wrap it in a project. Let’s make one.

Scaffold a project with resonon new:

Terminal window
resonon new my_song

You’ll see exactly what it created:

Created resonon.toml
Created src/
Created src/main.non
Created README.md
Created LICENSE
Created .gitignore
Initialized git repository
Project 'my_song' initialized.

That’s a complete, ready-to-run project in a my_song/ directory.

my_song/
├── resonon.toml # Project manifest
├── src/
│ └── main.non # Entry point
├── README.md
├── LICENSE
└── .gitignore

The manifest describes your project:

[package]
name = "my_song"
version = "0.1.0"
authors = ["Your Name <email>"]
resonon = "0.10.0" # filled in with your installed resonon version
[dependencies]
# example = { source = "gh:user/repo", version = "v1.0" }
FieldDescription
nameProject name
versionYour project’s version — informational
authorsList of authors — informational
resononThe resonon version this project was written against
[dependencies]External packages (empty by default)

resonon is checked when you run the project. Because resonon is still pre-1.0, each minor version can change the language, so a project asking for a newer resonon than you have installed refuses to run rather than failing later with a confusing parse error; running a newer resonon than the project targets only prints a warning. Patch releases are interchangeable.

This is the entry point — the file resonon run executes. The scaffolded template sets up the project and prints a greeting:

// Entry point — run with `resonon run`
// Which interface this rig uses, at what rate and block size, and how far its
// converters lag are facts about *this machine*, not about the music. They live
// in ~/.resonon/preferences.toml under [audio], are applied before this file
// runs, and never travel with a project.
//
// Channel numbers do belong here: every rig has a channel 0.
fn setup() {
project_title("my_song");
project_bpm(120);
// audio_output_channels(0, 1); // master out, 0-based
}
setup();
fn greet(name) {
print(f"Hello from {name}!");
}
greet("my_song");

project_title and project_bpm set metadata for the piece. Everything else is yours to replace with music.

setup() is a convention, not a keyword — resonon knows nothing about the name. It is just a habit worth keeping: one function, called first, holding everything that configures the session. Audio settings live in code rather than in a config file, and gathering them here means there is one place to look.

The audio lines are commented out because the defaults already work — resonon uses your system’s default devices. Uncomment what you need. Device names are specific to your machine, though, so they are better kept in a separate module you use; see Configuration.

From inside the project directory (or any subdirectory), run:

Terminal window
cd my_song
resonon run

Resonon searches upward for resonon.toml, then executes src/main.non. You’ll see the greeting print in your terminal.

Or name a file directly, to run that one and exit:

Terminal window
resonon my_script.non

The file has to sit inside a project too — resonon walks up from the file, not from the directory you are standing in, so resonon ~/songs/my_song/src/main.non finds my_song from anywhere. A file with no resonon.toml above it is refused by name:

No resonon.toml in /Users/you/scratch or above it.
A piece belongs to a project — start one with `resonon new <name>`, or `resonon init` in the folder it should live in.

That is the same answer resonon install, resonon collect and resonon build give, and the same one the editor gives when you evaluate a selection: what a piece can load is what its resonon.toml declares, so there has to be one.

Now swap the template for something that actually plays. Here’s a starting point using what you built in the previous guides — drums and a clap, all from the bundled CR-78 kit:

project_title("my_song");
project_bpm(120);
use "std/instruments" { Sampler, Kit };
// Drums
let drums = AudioTrack("drums");
drums.instrument(Sampler(Kit("CR-78")));
drums << [bd _ sd _, hh hh hh hh];
// Clap on the off-beats
let perc = AudioTrack("perc");
perc.instrument(Sampler(Kit("CR-78")));
perc << [_ cp _ cp];
PLAY;

Drop that into src/main.non and resonon run will play it.

resonon new takes flags for different kinds of projects:

FlagDescription
--libLibrary project (src/lib.non instead of src/main.non)
--kitSample kit project (adds a kits/ directory)
--nativeNative Rust extension project (adds a native/ crate)
Terminal window
resonon new my_library --lib # Importable library
resonon new my_drums --kit # Sample kit with kits/ directory
resonon new my_plugin --native # Rust extension with native/ crate

Already inside a directory? Scaffold in place with resonon init:

Terminal window
mkdir my_project && cd my_project
resonon init my_project

Continue the quickstart or jump into the reference docs:

  • Custom DSP — write your own effects and synthesizers
  • MIDI I/O — MIDI output, input, and learn mapping
  • Pattern Basics — deep dive into time division, pattern types, and looping
  • Samplers — drum kits, melodic samplers, and sample manipulation
  • VSCode Extension — full editor reference with shortcuts and features