Modules
This content is for v0.7. Switch to the latest version for up-to-date documentation.
The use statement
Section titled “The use statement”Import a module with use. The imported module is bound to a namespace variable.
use "../lib_example/lib" as lib;
// Access top-level exportsPRINT lib.default_bpm; // 120
// Access sub-module functionsPRINT lib.patterns.kick(); // [C1 C1 C1 C1]PRINT lib.patterns.arp(); // [C4 E4 G4 C5]If no as alias is given, the alias is derived automatically:
- For regular files, the alias is the file stem (filename without
.non):use "./patterns"binds topatterns. - For
lib.nonfiles, the alias is the parent directory name:use "./drums/lib"binds todrums.
The .non extension is appended automatically when missing, so use "./patterns" and use "./patterns.non" are equivalent.
use "./scales"; // binds to `scales`use "./drums/lib"; // binds to `drums`use "./utils" as helpers; // explicit alias overrides derivationModule files
Section titled “Module files”Any .non file loaded via use becomes a module. Its public definitions form the module’s exports:
letbindings (including computed expressions)fndefinitionsclassdefinitions- Nested
useimports (re-exported as named fields)
use "./scales"; // re-exported as theory.scales
let middle_c = C4; // exportedlet default_vel = 100; // exportedlet doubled = 21 * 2; // exported (computed at import time)
fn octave_up(note) { // exported return note + 12;}
class Interval { // exported let semitones;
fn new(s) { this.semitones = s; }}Visibility (private)
Section titled “Visibility (private)”Mark variables, functions, and classes as private to prevent them from being exported. Private members are only accessible within the module that defines them.
private let BASE_VEL = 0.8; // internal onlyprivate fn humanize(pattern) { // internal only return pattern * vel(BASE_VEL);}private class InternalState { // internal only let value;}
let default_bpm = 120; // public
/// Four-on-the-floor kick pattern.fn kick() { // public return humanize([C1 C1 C1 C1]);}Attempting to access a private member from outside the module produces an error:
Cannot access private 'BASE_VEL' in module 'drums'The show() function displays private items in a separate section, so you can inspect a module’s full contents without accessing them. See Inspecting modules in the REPL.
Library resolution
Section titled “Library resolution”Resonon resolves use paths in the following order:
- Relative paths — paths starting with
./or../, resolved from the current file - Absolute paths — paths starting with
/ - Library search paths — checked in order from the configured
lib_paths
At each step, Resonon first tries the path as a directory (looking for <dir>/lib.non), then as a file (appending .non if needed).
use "./patterns"; // 1. relativeuse "/opt/resonon/utils"; // 2. absoluteuse "my_library/lib"; // 3. library search pathsLibrary path configuration
Section titled “Library path configuration”Library search paths are configured in ~/.config/resonon/config.toml:
lib_paths = [ "~/resonon-libs", "/shared/team-libs",]When lib_paths is not set (or empty), two defaults are used:
./lib— alib/directory relative to the working directory~/.config/resonon/lib— the user-level library directory
Tilde (~) is expanded to your home directory in all paths.
See also: Configuration reference and Package management guide.
Library packages
Section titled “Library packages”A library is a directory with a lib.non entry point. Importing the directory loads lib.non automatically.
drums/ lib.non ← entry point patterns.non ← sub-module fills.non ← sub-moduleuse "./patterns";use "./fills";
let default_vel = 100;// Consumer codeuse "drums";
drums.patterns.kick();drums.fills.intro();PRINT drums.default_vel; // 100Nested modules
Section titled “Nested modules”A use statement inside a module re-exports the imported module as a named field. This lets you build multi-level namespaces.
use "./scales";use "./chords";use "theory";
let mode = theory.scales.dorian(C4);let triad = theory.chords.major(C4);Each nested module is a separate .non file that follows the same export rules — let bindings, fn definitions, class definitions, and its own nested use imports are all available through dot access.
Standard library
Section titled “Standard library”Resonon ships with a standard library compiled into the binary. It is split into a prelude (auto-loaded, always available) and modules (imported on demand with use).
Prelude (auto-loaded)
Section titled “Prelude (auto-loaded)”The prelude is loaded automatically — no import needed. Everything available in a fresh REPL comes from the prelude.
| Area | Exports |
|---|---|
| Core | Array, String, Dict, Iterator, clock, reset, type, show, range, map, filter, fold |
| Patterns | Pattern, Sequence, Stack, Alternating, euclid, viz |
| MIDI | MidiTrack, midi_connect, midi_ports, midi_routing, midi_clock_* |
| Theory | Scale, Key, scale, chord, interval |
| Audio | AudioTrack, Master, Event, setbpm, render, audio_devices, routing, project_* |
| Cycle callbacks | on_cycle, off_cycle, prime_cycles |
Modules (require import)
Section titled “Modules (require import)”Modules are imported with use "std/...". Use destructuring to import specific names:
use "std/effects" { Delay, Lowpass, Reverb };use "std/instruments" { Sampler, Kit, SamplerMelodic };use "std/signals" { Sine, Saw, automation };use "std/random" { rand, choose, choose_weighted };use "std/generative" { stream, markov };| Module | Exports |
|---|---|
| std/effects | Delay, Lowpass, Highpass, Bandpass, Notch, Allpass, Peak, Reverb, PlateReverb, Overdrive, Distortion, Effect (CLAP), Vst3Effect |
| std/instruments | Sample, Kit, Sampler, SamplerMelodic, ClapInstrument, Vst3Instrument, Instrument, plugin_scan, plugin_list |
| std/signals | Signal, Sine, Saw, Tri, Square, Rand, Perlin (+ bipolar variants Sine2, Saw2, Tri2, Square2), hz, signal, automation, Cc, Cc_learn |
| std/random | rand, choose, choose_weighted, rand_true, choose_true |
| std/generative | stream, markov |
Example
Section titled “Example”use "std/effects" { Delay, Lowpass };use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.load_instrument(Sampler(Kit("cr78")));drums << [bd sd bd sd];drums.load_effect(Delay(0.25, 0.5));drums.load_effect(Lowpass(800));PLAY;Inspecting modules in the REPL
Section titled “Inspecting modules in the REPL”Use show() to inspect a module’s contents.
use "../lib_example/lib" as lib;show(lib);Output:
┌────────────────────────────────────────┐ Module: lib (from /path/to/lib.non) Library entry point
Exports: patterns: Module default_bpm: Number fn rest(beats) - Generate rests for a number of beats
Private: INTERNAL_VEL: Number└────────────────────────────────────────┘The output shows:
- Header — module name and file path
- Module doc — first line of the module-level
///comment (if present) - Exports — functions (with signatures and doc summaries), variables (with types), and nested modules
- Private — private items with their types, visible for inspection but not accessible in code
Documentation comments
Section titled “Documentation comments”Use /// comments to document modules and their exports. These are preserved at parse time and displayed by show().
Module-level docs
Section titled “Module-level docs”Place /// comments at the top of the file, before any use, let, or fn statements:
/// Drum pattern library./// Provides kick, snare, and hi-hat patterns.
use "./fills";
let default_vel = 100;Per-export docs
Section titled “Per-export docs”Place /// comments directly above a fn or let binding:
/// Base velocity for all drum hits.let default_vel = 100;
/// Four-on-the-floor kick pattern.fn kick() { return [C1 C1 C1 C1];}Association rules
Section titled “Association rules”- A
///comment attaches to the nextfnorletstatement. - A blank line between a
///block and the next statement breaks the attachment — the orphaned comment becomes the module doc (if no module doc exists yet) or is discarded. - Doc comments above
usestatements are not attached to the import; they become the module doc if eligible.
Circular import protection
Section titled “Circular import protection”If two modules import each other, Resonon detects the cycle and returns an empty module (no exports) for the already-loaded file rather than looping forever.
use "./b"; // loads b, which tries to load a againPRINT b.value; // b has exports
// b.nonuse "./a"; // a is already being loaded → empty modulePRINT a.value; // ERROR: a has no exports hereNaming conventions
Section titled “Naming conventions”- Module files:
snake_case.non(e.g.,drum_patterns.non) - Library entry points: always
lib.non - Imports: use descriptive aliases (
use "drums/lib" as drums;)
Practical examples
Section titled “Practical examples”Drum kit library
Section titled “Drum kit library”A self-contained drum library with private helpers and documented exports.
/// Acoustic drum kit patterns./// Velocity-humanized with configurable intensity.
use "./fills";
private let BASE_VEL = 0.75;
/// Applies velocity humanization to a pattern.private fn humanize(pat) { return pat * vel(BASE_VEL + rand(0.1));}
/// Standard four-on-the-floor kick.fn kick() { return humanize([C1 C1 C1 C1]);}
/// Offbeat hi-hat pattern.fn hihat() { return humanize([_ F#1 _ F#1]);}
/// Backbeat snare on 2 and 4.fn snare() { return humanize([_ D1 _ D1]);}/// Drum fill for transitions.fn crash_fill() { return [C1 D1 F#1 C#2];}Consumer code:
use "drums";
Track("Drums", 10) >> drums.kick() >> drums.snare() >> drums.hihat();Multi-file composition
Section titled “Multi-file composition”A project with shared utilities and multiple performance files.
my_project/ lib/ shared/ lib.non ← shared scales and utilities scales.non songs/ verse.non chorus.non main.non ← entry point/// Shared music theory utilities.
use "./scales";
let root = C4;let bpm = 128;/// Minor pentatonic from a given root.fn minor_penta(root) { return [root, root+3, root+5, root+7, root+10];}use "./lib/shared" as shared;
set_bpm(shared.bpm);
let notes = shared.scales.minor_penta(shared.root);PRINT notes; // [C4 Eb4 F4 G4 Bb4]