Introduction
Conchordal is a research-composer scripting surface. The central idea is not note scheduling. The central idea is shaping a perceptual consonance field, then letting populations of voices move, survive, and reorganize inside it.
A scenario script defines Materials (voice templates), places them into the field as Participants, and shapes the terrain they live on. Harmony emerges from psychoacoustics (roughness and harmonicity); rhythm emerges from coupled oscillators on a shared meter the population itself drives. The script is a director, not a sequencer.
Conchordal v0.4.0 is aimed at research composers who want to work with these concepts directly. It is not trying to hide the model behind common music-production vocabulary.
How this book is organized
- Tutorial gets a first sound out and your editor wired up: Quick Start, Editor Setup.
- Concepts explains the three pillars of the model: the Consonance Field, Rhythm, and Routing and the Listener Twin.
- Reference is the complete, generated API Reference — it is produced from the engine’s registered scripting surface, so it cannot drift — and the Curated Samples listening path. The reference is split into three tiers: the Core API (enough for every curated sample), Mechanism Tuning, and Research Controls. Start with Core and ignore the rest until a piece demands it.
Every rhai code block in this book is executed against the real script
engine by the test suite, so the examples are guaranteed to run.
Quick Start
Run a scenario script with the real-time instrument (release mode is recommended for real-time DSP):
cargo run --release -- samples/01_a_single_voice.rhai
Minimal Sound
place(sine().amp(0.08).sustain(), at(440.0));
wait(2.0);
place(material, placement) stages a Participant at the current script time.
It is committed by wait(seconds) or flush(), then can be patched while it
is alive.
Basic Objects
- Materials are voice templates made with
sine(),harmonic(),modal(),saw(),square(), andnoise(). - Variants clone a material with
variant(material). - Placements decide where participants enter: field targets
consonance(),dissonance(),edge(),gap()(cloud by default,.peak()for the extremum), plusrandom(),at(), andline(). - Participants are the handles returned by
place(). Before the nextwait()orflush(), participant builder methods still shape the initial spawn; after that, patchable methods update running voices. - Sections scope participants and release them automatically.
let voice = harmonic()
.amp(0.08)
.sustain()
.brightness(0.35);
section("plain entry", || {
place(voice, line(220.0, 440.0).count(3));
wait(4.0);
});
Placing Into the Field
consonance(root_hz).peak() places voices at high Consonance Field positions
around a root. The field is shaped by what the system perceives — an anchor
changes where the peaks are.
let anchor = harmonic()
.brain("drone")
.amp(0.06)
.sustain()
.anchor();
let voice = harmonic()
.amp(0.04)
.sustain();
section("field placement", || {
place(anchor, at(110.0));
wait(1.0);
place(voice, consonance(110.0).peak().range(1.0, 4.0).count(6).spacing(0.9));
wait(6.0);
});
How the field works — and how voices move, survive, and respawn inside it — is the subject of The Consonance Field.
Live Patching
Some participant methods patch running voices; others only shape the draft and must be set before the group is committed. The API Reference tags every method as live-patchable or draft-only.
let g = place(
harmonic().amp(0.04).sustain(),
consonance(220.0).peak().count(3)
);
wait(2.0); // commit: the group is now live
g.amp(0.02); // live patch on running voices
g.glide(0.8);
wait(3.0);
release(g);
A Complete Miniature
seed(7);
let anchor = harmonic()
.brain("drone")
.amp(0.05)
.sustain();
let colony = harmonic()
.amp(0.035)
.sustain()
.seek_consonance()
.glide(0.4)
.avoid_neighbors(0.6);
section("emergence", || {
place(anchor, at(110.0));
wait(2.0);
place(colony, consonance(90.0, 900.0).count(8).spacing(0.8));
wait(8.0);
});
Where to go next
- Editor Setup — completion, hover docs, and diagnostics for the whole scripting surface.
- The Consonance Field — field, density, movement, viability, respawn.
- Rhythm — the coupling continuum and the director’s rhythmic terrain.
- Curated Samples — the guided listening path.
Editor Setup (LSP)
Conchordal ships a Rhai LSP definition file describing the entire scripting
surface, including hover documentation for every function. Hooking your editor
up to it gives you completion, hover, go-to-def, and inline diagnostics for
every conchordal function — place, harmonic, .brain(),
.send(habitat_bus), and so on.
The two files that drive this are committed at the repo root:
Rhai.toml— workspace config picked up byrhai-lsprhai-defs/conchordal.d.rhai— auto-generated type/fn declarations with doc comments
Install the rhai-lsp server once (it is not on crates.io; install directly from the git repo):
cargo install --git https://github.com/rhaiscript/lsp rhai-cli
This builds a binary named rhai with the lsp subcommand.
Then wire your editor:
VS Code
The official Rhai
extension currently provides syntax highlighting only. It does not launch
rhai-lsp. For LSP features in VS Code, use an LSP client/extension that can
launch this command from the conchordal workspace:
rhai lsp stdio --config Rhai.toml
Neovim (nvim-lspconfig)
require("lspconfig").rhai.setup({
cmd = { "rhai", "lsp", "stdio" },
filetypes = { "rhai" },
root_dir = require("lspconfig.util").root_pattern("Rhai.toml", ".git"),
})
Helix
In ~/.config/helix/languages.toml:
[[language]]
name = "rhai"
scope = "source.rhai"
file-types = ["rhai"]
language-servers = ["rhai-lsp"]
[language-server.rhai-lsp]
command = "rhai"
args = ["lsp", "stdio"]
Emacs (eglot)
(add-to-list 'eglot-server-programs
'(rhai-mode . ("rhai" "lsp" "stdio")))
(add-hook 'rhai-mode-hook #'eglot-ensure)
Regenerating the definition file
The definition file and the API Reference are both
generated from the engine’s register_fn surface joined with the
documentation registry (src/scripting/docs.rs). If you pull a new conchordal
version and miss diagnostics, regenerate both:
cargo run --bin gen_rhai_defs
CI tests fail whenever the committed artifacts are stale, so in a clean checkout they are always in sync with the engine.
The Consonance Field
Conchordal’s perception core (the Landscape) listens to the habitat bus, transforms it into log-frequency space, and computes two potentials: roughness (sensory dissonance from amplitude fluctuations within critical bands) and harmonicity (periodicity and template matching). Their combination is the Consonance Field: an evaluation terrain over frequency that placement, movement, prediction, and survival all read from.
Because the field is computed from what the system actually hears, every voice deforms the terrain for every other voice. That feedback loop — not a chord chart — is where harmony comes from.
Placing into the field: consonance, dissonance, edge, gap
A field-relative placement names a target — a region of the field — and is
realized either as a cloud (the default) or as a deterministic extremum with
.peak(). The targets are:
consonance— high-consonance positions (harmonic centers, fusion).dissonance— low-consonance positions (tension, clusters, color).edge— the consonance/dissonance boundary (the metastable middle).gap— empty registers (fill the room, avoid masking).
consonance(root) takes a harmonic window around a root (multiples via
range()); every target also takes an absolute (min_hz, max_hz) range.
let anchor = harmonic()
.brain("drone")
.amp(0.06)
.sustain()
.anchor();
let voice = harmonic()
.amp(0.04)
.sustain();
section("field placement", || {
place(anchor, at(110.0));
wait(1.0);
place(voice, consonance(110.0).peak().range(1.0, 4.0).count(6).spacing(0.9));
wait(6.0);
});
A target with no modifier is a density cloud: not “random but harmonic” but
a normalized distribution derived from the consonance model, well-defined inside
the range. Placement is independent of behavior — enter at dissonance and
anchor() for a held cluster, or enter at dissonance and seek_consonance()
for a resolution gesture.
let cloud = harmonic().amp(0.035).sustain();
place(cloud, consonance(90.0, 1200.0).count(10).spacing(0.8));
wait(8.0);
Placement tension: tension(τ)
consonance aims at the strongest peak. tension(τ) aims a step below it:
τ ∈ [0, 1] is the tension degree, where 0 keeps the resolved peak and larger
values target progressively weaker, metastable steps
(target = L_max − τ·(L_max − L_min) over the range, in field score). It is the
placement twin of movement’s search temperature — the dial for how resolved a
spawn should sit — and it reads the field’s score directly, so the degree rides
the terrain’s own scale rather than the count of peaks that happen to be
sounding. With .peak() it snaps to the nearest step; as a cloud it concentrates
the distribution around the target.
let tense = harmonic().amp(0.035).sustain();
// A metastable step below the strongest peak — placed, not resolved.
place(tense, consonance(110.0, 1200.0).peak().tension(0.4).count(6).spacing(0.8));
wait(6.0);
The field-agnostic placements are random(min_hz, max_hz) (log-uniform) and the
geometric at(hz) and line(start_hz, end_hz).
Consonance Movement: seek_consonance
Use seek_consonance() when voices should actively seek better field
positions. It sets free hill-climb movement with glide defaults. Use
glide(tau_sec) when the musical thought is “same movement idea, slower or
faster pitch motion”.
let mover = harmonic()
.amp(0.045)
.sustain()
.seek_consonance()
.glide(0.35)
.avoid_neighbors(0.6)
.global_peaks(8, 70.0)
.ratio_candidates(5);
place(mover, consonance(80.0, 900.0).count(8));
wait(12.0);
avoid_neighbors(strength) adds crowding repulsion so movers spread out
instead of collapsing onto the same peak.
The opposite of movement is anchor(): an anchored voice holds its pitch and
only deforms the terrain for others. Voices placed with at() or given
freq() are anchored implicitly; use anchor() to freeze strategy-placed
voices at their settled position.
How movement lands is resolved from phonation: sustained movers glide,
re-attacking movers (pulse(), metric(), entrained(), flow()) snap to
their new pitch at each onset. Override with pitch_apply_mode() when a
script needs the other behavior. Mechanism-level controls (pitch_core() and
the hill-climb / peak-sampler tuning in the
API Reference) remain available for research scripts;
prefer seek_consonance() and glide() in curated work.
Consonance Viability and Respawn
Viability makes field fit matter over time. consonance_viability(low, high)
defines the consonance window, and viability_rate(rate) controls continuous
recharge: a voice in a well-fitting place is sustained, a voice in a poor
place starves.
By default viability uses environment-relative scoring: a voice is
evaluated against the field with its own footprint approximately removed. Use
viability_scope("total") only when the compositional question is explicitly
total-field viability.
Respawn closes the loop into an ecology: when voices die, replacements appear
according to a respawn policy. respawn_consonance() draws them from
consonance-biased parental peaks; respawn_capacity(count) keeps the
population bounded; respawn_settle(placement) decides where replacements
settle.
let settle = consonance(70.0, 1100.0).spacing(0.8);
let ecology = harmonic()
.amp(0.04)
.repeat()
.pulse(1.5)
.cycles(3)
.seek_consonance()
.glide(0.45)
.initial_energy(0.7)
.energy_cap(1.0)
.metabolism(0.09)
.action_cost(0.012)
.viability_rate(0.18)
.consonance_viability(0.32, 0.82)
.respawn_consonance()
.respawn_capacity(14)
.respawn_settle(settle);
place(ecology, consonance(70.0, 1100.0).count(14));
wait(30.0);
The full lifecycle surface (energy, metabolism, costs) and the respawn policies are documented in the API Reference.
Landscape-aware timbre
The field can shape timbre as well as pitch. The modal() body takes a mode
pattern, and landscape-aware patterns sample the live field, so a bell’s
partials can sit where the terrain already supports them.
let shimmer_modes = landscape_density_modes()
.count(10)
.range(1.0, 5.5)
.gamma(1.6)
.spacing(0.7);
let shimmer = modal()
.amp(0.025)
.sustain()
.seek_consonance()
.modes(shimmer_modes)
.brightness(0.7);
place(shimmer, consonance(200.0, 1600.0).count(4));
wait(8.0);
Mode constructors include harmonic_modes(), odd_modes(),
power_modes(beta), stiff_string_modes(stiffness),
custom_modes([ratios]), modal_table(name), landscape_density_modes(),
and landscape_peaks_modes() — see the
API Reference.
Rhythm: One Coupling Continuum
Rhythm in conchordal is one coupling continuum on a shared emergent meter, not a set of independent clocks. The population drives a single production meter (a coupled-oscillator beat); each voice is a phase oscillator that entrains its onset phase to that emergent beat with a coupling strength. There is no externally imposed grid — coherence (or its absence) emerges from how tightly each voice locks to the meter the population itself drives.
The three rhythm “families” are just three regions of the continuum:
- metric: high coupling — a deep attractor, reads as a stable pulse.
- entrained: medium coupling — synchronization emerges over time, still drifts.
- flow: near-zero coupling — a free renewal process, non-metric texture.
Rhythm is part of the same ecology as consonance, viability, movement, and respawn: timing can affect survival, and survival reorganizes timing.
Director-level terrain
The director shapes the rhythmic terrain, symmetric to the consonance-field operations. These are soft priors, never a schedule — emergence still does the work:
meter_stability(value)— attractor depth in[0,1]: how readily a pulse forms. It only deepens the basin for a real periodicity; it never fabricates a beat from non-metric input.temporal_basin(min_hz, max_hz)— the tempo region the emergent beat gravitates toward (the time-axis analogue ofconsonance(min, max)). It shapes the terrain; it does not place a beat, and it never forces a measure.
Per-voice presets and modifiers
The Tier-1 presets take no rate argument: metric(), entrained(), and
flow(). The tempo region is a property of the terrain, set once at the
director level, not per voice. They work on both a Material and a draft
Participant.
Per-voice modifiers refine where on the continuum a voice sits:
entrainment(strength)— coupling in[0,1], free (0) .. locked (1).rhythm_role("beat"|"subdivision"|"accent"|"texture")— the voice’s metrical job.accentemits a stronger onset that drives the shared meter harder, so a recurring downbeat can seed an emergent measure.microtiming(amount)— a signed beat-phase offset in[-0.5, 0.5].0.5places a voice a half-beat off, reading as syncopation.
meter_stability(0.85); // attractor depth: how readily a pulse forms
temporal_basin(1.8, 2.2); // tempo region the emergent beat gravitates toward
let beat = harmonic()
.metric()
.rhythm_role("accent") // a strong onset that drives the shared beat
.cycles(2);
let entrained = harmonic()
.entrained()
.cycles(2);
let drift = harmonic()
.flow()
.cycles(1);
let offbeat = harmonic()
.metric()
.microtiming(0.5) // a half-beat offset reads as syncopation
.cycles(2);
place(beat, at(110.0));
place(entrained, consonance(110.0).peak().count(3));
place(drift, consonance(300.0, 1200.0).count(4));
place(offbeat, at(220.0));
wait(12.0);
Calls on the same axis are last-write-wins: the last timing mode and the last
duration mode determine the final behavior. Modifiers are remembered and
applied when their matching preset is selected, so entrainment(0.8).metric()
and metric().entrainment(0.8) are equivalent. The same applies to
duration_range(...).adaptive_duration() and the reverse order.
Explicit when/duration (Tier 2)
Below the presets sit explicit controls: once(), pulse(rate_hz),
while_alive(), cycles(n), and adaptive_duration() (with
duration_range, duration_curve, and shorten_on_drop for tuning).
Timing as survival (Tier 3)
Use rhythm_coupling_vitality(lambda_v, v_floor) and
rhythm_reward(rho_t, "attack_phase_match") when timing should affect
survival and reorganization, and rhythm_freq(freq_hz) to set the internal
oscillator directly:
let pulse_voice = harmonic()
.repeat()
.pulse(2.0)
.cycles(2)
.rhythm_freq(2.0)
.rhythm_coupling_vitality(0.8, 0.4)
.rhythm_reward(0.4, "attack_phase_match");
place(pulse_voice, at(165.0));
wait(8.0);
Scaffolds (research controls)
The scaffold functions impose an external pulse for comparison assays:
set_scaffold_off();
set_scaffold_shared(2.0);
set_scaffold_scrambled(2.0, 17);
They are useful for demos and assays. They are not the rhythm-composition abstraction: composed rhythm should come from the continuum and the terrain.
Routing and the Listener Twin
Two buses
Each voice contributes to two independent mono buses:
- presentation bus → cpal output / offline render / UI metering (the work as presented)
- habitat bus → NSGT analysis → landscape (what the ALife ecology responds to)
By default both buses receive the voice. Use send() when a voice should feed
only one side, or combine buses with |:
// Reference anchor: sensed by the ecology, absent from the presented sound.
let anchor = harmonic().brain("drone").send(habitat_bus);
// Presented decor that does not influence the ecology.
let decor = sine().send(presentation_bus);
// Explicitly both (the default).
let normal = harmonic().send(habitat_bus | presentation_bus);
place(anchor, at(110.0));
place(decor, at(880.0));
place(normal, consonance(110.0).peak().count(3));
wait(4.0);
Keeping the buses separate is a composition tool. A hidden anchor on
send(habitat_bus) can shape how the population organizes without ever
becoming audible, and presented decor on send(presentation_bus) can be heard
without perturbing the ecology.
The Listener Twin
conchordal keeps a ListenerTwin: a listener-side model of the presented
sound only. It never reads the habitat bus, so hidden scaffolds cannot create
fake listener tension. It reports five state values:
stability_level: how stable / consonant the current audible sound is.resolvability_level: whether a nearby audible state offers a plausible, more stable continuation.tension_level:(1 - stability) * resolvability— unstable now, but with a reachable path toward improvement.attention_level: presentation-derived onset / spectral-flux salience.neural_rhythms: presentation-derived listener-side rhythm (delta/theta).
There is no scripting verb for the twin. It is observed, not commanded: when
you run with reporting enabled it emits listener_state records, and the GUI
shows the same state. Use it to check whether the tension you hear matches
what the twin reports before coupling it back into generation.
DCC: coupling the twin back
That optional coupling is DCC, configured in conchordal.toml, not in
script:
[dcc]
# Listener pressure is report/UI-only by default.
# coupling_strength = 0.0
# max_exploration_bonus = 0.10
coupling_strength(0.0–1.0, default0.0): at0.0the twin is report/UI-only and generation is unchanged. Above0.0it appliestension_pressure = tension_level * resolvability_level * coupling_strengthas a transient pitch-exploration bonus only. It never sets target pitches or changes rhythm synchronization.max_exploration_bonus(default0.10): ceiling on that transient bonus.
Raise coupling_strength gradually, and only after the reported
listener_state looks musically legible.
API Reference
This page is generated from the engine’s registered scripting surface joined with the documentation registry (src/scripting/docs.rs). A CI test fails whenever this page drifts from the engine. Regenerate with:
cargo run --bin gen_rhai_defs
Builder methods return their receiver and are chainable. Integer and float literals are interchangeable wherever both overloads are registered; the generated LSP definitions (rhai-defs/conchordal.d.rhai) list the exact overloads.
The surface is split into three tiers. Core API is the curated composing surface — it is enough for every curated sample. Mechanism Tuning adjusts the mechanisms behind the core verbs when a piece needs a behavior the core surface does not express. Research Controls exist for studying the instrument, not composing with it.
Types
| Type | Description |
|---|---|
Material | Voice template built from a constructor such as sine() or harmonic(); all builder methods are chainable. |
Participant | Handle to a placed voice group returned by place(); draft until the next wait()/flush(), then live. |
Placement | Where voices enter the field: built by at(), consonance(), dissonance(), edge(), gap(), random(), or line(). |
ModePattern | Frequency pattern for modal synthesis bodies; built by *_modes() constructors. |
Bus | One of the two mono output buses; combine with ` |
BusSet | Combination of buses produced by `bus |
Built-in Constants
| Constant | Type | Description |
|---|---|---|
habitat_bus | Bus | Analysis bus: NSGT -> landscape; what the ecology senses. |
presentation_bus | Bus | Presentation bus: cpal output, recording, UI metering; what the listener hears. |
Core API
The curated composing surface. These verbs are enough for every curated sample.
Materials
Materials are voice templates. A constructor returns a Material; builder methods refine it; place() turns it into living voices.
sine
sine() -> Material
Material with a pure sine body.
harmonic
harmonic() -> Material
Material with a harmonic-series body.
modal
modal() -> Material
Material with a resonator-based modal body; shape it with modes().
saw
saw() -> Material
Harmonic-body preset with brightness 0.85.
square
square() -> Material
Harmonic-body preset with brightness 0.65.
noise
noise() -> Material
Harmonic-body preset with brightness 1.0 and motion 1.0.
variant
variant(material) -> Material
Clone a material so the copy can be modified independently.
Placement
Placements decide where voices enter the frequency field. Constructors return a Placement; modifiers refine it before it is passed to place().
at
at(freq_hz) -> Placement
Place at a fixed frequency in Hz.
consonance
consonance(root_hz) -> Placement
consonance(min_hz, max_hz) -> Placement
Target consonance maxima. Density cloud by default; .peak() for the extremum. consonance(root) takes a harmonic window around a root (default 1x-4x, set multiples with range()); consonance(min, max) takes an absolute range. Default spacing is 1.0 ERB.
dissonance
dissonance(min_hz, max_hz) -> Placement
Target consonance minima (tension, clusters). Density cloud by default; .peak() for the most dissonant point.
edge
edge(min_hz, max_hz) -> Placement
Target the consonance/dissonance boundary (C near its midpoint). The metastable region between fusion and beating. Density band by default; .peak() for the point closest to the boundary.
gap
gap(min_hz, max_hz) -> Placement
Target empty registers (low subjective intensity); fill the room. Density cloud by default; .peak() for the emptiest position.
peak
peak()
Applies to: Placement.
Realize a field target as its deterministic extremum.
density
density()
Applies to: Placement.
Realize a field target as a stochastic cloud (the default).
tension
tension(degree)
Applies to: Placement.
Place at a metastable consonance below the strongest (degree 0..1). Consonance placement only. 0 targets the strongest consonance (resolved); higher targets a weaker, more tense step (target = L_max - degree*(L_max - L_min) over the range, in field_score). Pairs with peak() (nearest step, sharp) or density (a broader cloud around it).
random
random(min_hz, max_hz) -> Placement
Log-uniform random placement inside a frequency range.
line
line(start_hz, end_hz) -> Placement
Linear interpolation of positions between two frequencies.
count
count(n)
Applies to: Placement.
Number of voices to place (default 1).
range
range(min_mul, max_mul)
Applies to: Placement.
Multiplier range relative to the root; only valid on consonance(root).
spacing
spacing(min_erb)
Applies to: Placement.
Minimum ERB distance between placed voices; valid on field placements.
Timeline & Staging
Staging verbs commit voices and move script time. place() stages a draft Participant; wait()/flush() commit drafts; scopes release groups automatically.
place
place(material, placement) -> Participant
Stage a Participant at the current script time. Committed by the next wait() or flush(). Until then, builder methods on the returned Participant shape the initial spawn; afterwards, live-patchable methods update running voices. Calling place(participant, placement) on a draft re-places it (sets frequency, count, and strategy).
wait
wait(seconds)
Commit pending drafts, then advance the timeline cursor.
flush
flush()
Commit pending drafts without advancing time.
release
release(participant)
Release a live group; its voices enter their release phase and fade out.
section
section(name, callback)
Named scope; groups placed inside are released when the callback returns.
play
play(callback)
play(callback, arg1)
play(callback, arg1, arg2)
play(callback, arg1, arg2, arg3)
play(callback, [args])
Scoped callback execution with automatic group release. Accepts 0-3 positional arguments, or an array of arguments.
parallel
parallel(callbacks)
Run an array of closures on parallel timelines from the current cursor. Each branch starts at the current cursor; the cursor advances to the latest branch end.
seed
seed(value)
Set the random seed for reproducible scenarios.
Body & Timbre
Sound body parameters of a voice: level, spectrum, detuning, and envelope.
amp
amp(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Amplitude in 0.0-1.0.
freq
freq(hz)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Frequency lock in Hz; implies an anchored pitch (see anchor()).
brightness
brightness(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Spectral brightness in 0.0-1.0 (harmonic/modal bodies).
spread
spread(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Detuning spread.
unison
unison(count)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Number of unison detuning copies.
modes
modes(pattern)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Set the mode pattern of a modal body. See the Mode Patterns section for constructors and modifiers.
adsr
adsr(attack_sec, decay_sec, sustain_level, release_sec)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
ADSR amplitude envelope.
Phonation & Rhythm
When and how long a voice sounds. Tier 1 picks a region on the rhythm coupling continuum (metric(), entrained(), flow()); Tier 2 sets explicit when/duration; Tier 3 is expert tuning. Calls on the same axis are last-write-wins, and modifiers are remembered and applied when their matching preset is selected.
brain
brain(name)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Articulation brain: "entrain" (default), "seq", or "drone". entrain synchronizes with detected rhythms in the field, seq does fixed-duration note sequencing, drone sustains with slow frequency sway.
sustain
sustain()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Sustain phonation mode (default).
repeat
repeat()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Repeated/pulsed phonation mode.
metric
metric()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
High coupling to the shared emergent meter: deep attractor, stable pulse. Takes no rate argument: the tempo region is director-level terrain (temporal_basin).
entrained
entrained()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Medium coupling: synchronization emerges over time, still drifts.
flow
flow()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Near-zero coupling: free renewal process, non-metric texture.
entrainment
entrainment(strength)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Override coupling strength in 0-1 (free .. locked). Order-independent with presets: entrainment(0.8).metric() and metric().entrainment(0.8) are equivalent.
rhythm_role
rhythm_role(name)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Metrical job: "beat", "subdivision", "accent", or "texture". accent emits a stronger onset that drives the shared meter harder, so a recurring downbeat can seed an emergent measure.
microtiming
microtiming(amount)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Signed beat-phase offset in -0.5..0.5; 0.5 reads as syncopation.
cycles
cycles(n)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Duration of n rhythm cycles.
Pitch Movement
How a voice moves through the consonance field. seek_consonance() plus glide() is the curated surface; the rest tunes the hill-climb and peak-sampler mechanisms.
anchor
anchor()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Hold the voice at its pitch: an anchored voice never moves. Voices placed with at() or given freq() are anchored implicitly; use anchor() to hold strategy-placed voices (consonance(), dissonance(), …) at their settled position, or to state the intent explicitly.
seek_consonance
seek_consonance()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Free hill-climb movement toward better field positions, with glide defaults. How pitch decisions land is resolved at commit unless pitch_apply_mode() was called: sustained voices glide, re-attacking voices (pulse(), metric(), entrained(), flow()) snap at onsets.
glide
glide(tau_sec)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Pitch glide time constant in seconds.
Neighbor Awareness
How a voice perceives other voices and its own spectral footprint when evaluating the field.
avoid_neighbors
avoid_neighbors(strength)
avoid_neighbors(strength, sigma_cents)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Crowding repulsion from neighboring voices. With one argument the repulsion width uses the default; the two-argument form sets it explicitly in cents.
Lifecycle & Viability
Energy budget and survival. Viability makes field fit matter over time: consonance_viability() defines the consonance window and viability_rate() controls continuous recharge, with environment-relative scoring by default.
metabolism
metabolism(rate)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Energy consumption rate.
initial_energy
initial_energy(value)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Starting energy.
energy_cap
energy_cap(value)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Maximum energy after recharge/reward.
recharge_rate
recharge_rate(rate)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Energy gained per attack.
action_cost
action_cost(cost)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Energy cost per attack.
sustain_drive
sustain_drive(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Continuous drive level for sustained voices.
viability_rate
viability_rate(rate)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Continuous consonance-driven energy recharge rate.
consonance_viability
consonance_viability(low, high)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Consonance window used for viability scoring. Enables environment-relative scoring by default: a voice is evaluated against the field with its own footprint approximately removed (see viability_scope()).
dissonance_cost
dissonance_cost(cost)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Extra energy cost at low consonance.
Respawn
Population turnover. A respawn policy decides where replacements appear when voices die; capacity and acceptance thresholds shape ecology-scale behavior.
respawn_random
respawn_random()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Respawn at random locations.
respawn_hereditary
respawn_hereditary(sigma_oct)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Hereditary respawn with frequency variance in octaves.
respawn_consonance
respawn_consonance()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Respawn from consonance-biased parental peaks.
respawn_capacity
respawn_capacity(count)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Maintain population up to a capacity.
respawn_settle
respawn_settle(placement)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Placement used for replacements. Requires a strategy-bearing placement: consonance(), dissonance(), edge(), gap(), random(), or line() (not at()).
respawn_min_c_level
respawn_min_c_level(level)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Minimum consonance level for respawn acceptance.
respawn_background_death_rate
respawn_background_death_rate(rate)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Background turnover rate per second.
Mode Patterns
Frequency relationships for modal() bodies. Constructors return a ModePattern; modifiers are chainable. Landscape-aware patterns sample the live field.
harmonic_modes
harmonic_modes() -> ModePattern
Harmonic series: f, 2f, 3f, …
odd_modes
odd_modes() -> ModePattern
Odd harmonics: f, 3f, 5f, …
power_modes
power_modes(beta) -> ModePattern
Power law: f * n^beta.
stiff_string_modes
stiff_string_modes(stiffness) -> ModePattern
Stiffness-adjusted harmonics.
custom_modes
custom_modes(ratios) -> ModePattern
Custom frequency ratios from an array.
modal_table
modal_table(name) -> ModePattern
Named mode table lookup. Falls back to harmonic_modes() with a warning if the name is unknown.
landscape_density_modes
landscape_density_modes() -> ModePattern
Modes sampled from the live landscape density.
landscape_peaks_modes
landscape_peaks_modes() -> ModePattern
Modes sampled from live landscape peaks.
count
count(n)
Applies to: ModePattern.
Number of modes.
range
range(min_mul, max_mul)
Applies to: ModePattern.
Frequency range; only valid on landscape_*_modes().
spacing
spacing(min_erb)
Applies to: ModePattern.
Minimum ERB distance between modes; only valid on landscape_*_modes().
gamma
gamma(g)
Applies to: ModePattern.
Density sharpening exponent; only valid on landscape_density_modes().
jitter
jitter(cents)
Applies to: ModePattern.
Randomize mode frequencies by up to the given cents.
seed
seed(value)
Applies to: ModePattern.
Random seed for jittered patterns (>= 0).
Routing
Each voice contributes to two independent mono buses: the presentation bus (the work as heard) and the habitat bus (what the ecology senses through NSGT analysis). By default a voice feeds both.
send
send(bus)
Applies to: Material only.
Route the voice to specific buses; accepts a Bus or a BusSet. Material only. send(habitat_bus) makes a voice sensed by the ecology but absent from the presented sound; send(presentation_bus) is heard without perturbing the ecology; send(habitat_bus | presentation_bus) feeds both (the default).
Director & Global Parameters
Scene-global terrain shaping and research controls. Director verbs are soft priors: they shape the terrain and never schedule a beat or force a measure.
meter_stability
meter_stability(value)
Attractor depth in 0-1: how readily a pulse forms. A soft prior: it only deepens the basin for a real periodicity; it never fabricates a beat from non-metric input.
temporal_basin
temporal_basin(min_hz, max_hz)
Tempo region the emergent beat gravitates toward. The time-axis analogue of consonance(min, max): it shapes the terrain, does not place a beat, and never forces a measure.
Experimental
Candidate core verbs under audition: composing surface by intent, but with research-grade stability until validated.
Empty right now.
Mechanism Tuning
Fine-grained control over the mechanisms behind the core verbs. Defaults are calibrated; reach for these when a piece needs a specific behavior the core surface does not express.
Placement
reject_targets
reject_targets(anchor_hz, targets_st, exclusion_st, max_tries)
Applies to: Placement.
Reject sampled positions near specified semitone targets. targets_st is an array of semitone offsets from anchor_hz, exclusion_st is the exclusion zone width in semitones, and max_tries is the retry limit. Wraps any strategy-bearing placement (consonance(), dissonance(), random(), line(), …).
Phonation & Rhythm
once
once()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Single trigger.
pulse
pulse(rate_hz)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Pulse at an explicit rate in Hz.
while_alive
while_alive()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Hold/sustain until release.
adaptive_duration
adaptive_duration()
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Duration follows field support.
pulse_lock
pulse_lock(depth)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Low-level pulse phase weighting in 0-1.
social
social(coupling)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Social coupling for entrained() or pulse(), in 0-1.
duration_range
duration_range(min_cycles, max_cycles)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Adaptive duration range in rhythm cycles.
duration_curve
duration_curve(k, x0)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Adaptive duration curve parameters.
shorten_on_drop
shorten_on_drop(gain)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Shorten adaptive duration when field support drops.
rhythm_freq
rhythm_freq(freq_hz)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Internal theta/rhythm oscillator frequency.
rhythm_coupling_vitality
rhythm_coupling_vitality(lambda_v, v_floor)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Vitality-modulated rhythm coupling.
rhythm_reward
rhythm_reward(rho_t, metric)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
Energy reward for timing fit; metric is "attack_phase_match" or "none".
Pitch Movement
pitch_smooth
pitch_smooth(tau_sec)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Pitch smoothing time constant in seconds.
pitch_apply_mode
pitch_apply_mode(name)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
"gate_snap" or "glide": override how pitch decisions are applied. Without an explicit call, moving voices resolve this at commit from their phonation: sustained voices glide, re-attacking voices snap at onsets.
landscape_weight
landscape_weight(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Weight of the landscape objective.
temperature
temperature(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Search temperature shared by both pitch cores: 0 settles greedily, higher is more exploratory. The single stochastic-search knob. At 0 the hill-climb is greedy (move only on a clear improvement, otherwise stay) and the peak sampler takes the argmax candidate. Higher values let the hill-climb accept downhill moves (Metropolis) and soften the peak sampler’s candidate choice.
neighbor_step_cents
neighbor_step_cents(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Step size for neighbor exploration in cents.
move_cost
move_cost(coeff)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Cost multiplier for pitch changes.
move_cost_exp
move_cost_exp(exp)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Exponent for the move cost.
proposal_interval
proposal_interval(seconds)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Proposal generation interval in seconds.
tessitura_gravity
tessitura_gravity(value)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Gravity toward the tessitura center.
window_cents
window_cents(width)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Peak-sampler search window width in cents.
top_k
top_k(count)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Number of top candidates kept by the peak sampler.
sigma_cents
sigma_cents(spread)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Gaussian spread of the peak sampler in cents.
random_candidates
random_candidates(count)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Number of random candidates considered.
global_peaks
global_peaks(count)
global_peaks(count, min_sep_cents)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Global field peaks as movement candidates, with optional minimum separation.
ratio_candidates
ratio_candidates(count)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Ratio-based movement candidates; 0 disables.
Neighbor Awareness
crowding_target
crowding_target(same_visible, other_visible)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Which voices are visible to crowding: own group, other groups (booleans).
leave_self_out
leave_self_out(enabled)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Subtract the voice’s own spectral contribution when evaluating the field.
leave_self_out_harmonics
leave_self_out_harmonics(count)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
Number of harmonics used for approximate self-subtraction.
Lifecycle & Viability
viability_scope
viability_scope(name)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
"environment" (default) or "total" viability scoring scope. Use "total" only when the selection question should include the voice’s own contribution.
Director & Global Parameters
set_roughness_k
set_roughness_k(value)
Roughness tolerance of the landscape.
set_global_coupling
set_global_coupling(value)
Voice interaction strength.
Research Controls
For studying the instrument, not composing with it. Normal composing never touches this tier, and it has the weakest stability guarantee: entries may change or disappear as their research questions settle.
Pitch Movement
pitch_core
pitch_core(name)
Applies to: Material and Participant. Draft-only: ignored with a warning on a live Participant.
"hill_climb" or "peak_sampler". Research control.
move_cost_time_scale
move_cost_time_scale(name)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
"legacy"/"integration_window" or "proposal"/"proposal_interval".
Neighbor Awareness
leave_self_out_mode
leave_self_out_mode(name)
Applies to: Material and Participant. Live-patchable: updates running voices on a live Participant.
"approx"/"approx_harmonics" or "exact"/"exact_scan".
Lifecycle & Viability
selection_approx_loo
selection_approx_loo(enabled)
Applies to: Material only.
Override environment-relative viability scoring; research/reference control. Material only. Use only for older reference assays that need the previous implementation-level control.
Director & Global Parameters
set_pitch_objective
set_pitch_objective(name)
"consonance"/"positive" or "dissonance"/"negative". Research control.
set_control_update_mode
set_control_update_mode(name)
"snapshot_phased"/"snapshot" (default) or "sequential_rotating"/"sequential". Research control.
set_scaffold_off
set_scaffold_off()
Disable the external rhythm scaffold. Scaffolds are external comparison controls for demos and assays, not the rhythm-composition abstraction.
set_scaffold_shared
set_scaffold_shared(freq_hz)
Shared external scaffold pulse.
set_scaffold_scrambled
set_scaffold_scrambled(freq_hz, seed)
Per-voice scrambled scaffold pulse.
Études
The samples are a book of twelve études — small pieces, in order. Played and read one after another, they are the instrument: each is written around one of its capacities, and the script itself is the score.
cargo run --release -- samples/01_a_single_voice.rhai
- A Single Voice — one voice appears, holds its breath, and leaves.
- Constellation — four ways to enter: a line, the peaks, the density, chance.
- Gravity — the same root under two suns; the peaks listen to what is sounding, not to a chart.
- Tension — the director leans on the terrain until it strains, then lets the gravity come home.
- Settling — scattered voices glide to where the field can hold them.
- Bells — struck bodies; the last bell lets the field choose its partials.
- Heartbeat — no external scaffold is imposed; the population locks into a shared pulse.
- Murmuration — a flock drifts into step, never commanded.
- Rain — time without a beat, falling along the field.
- Generations — voices live, starve, and are reborn where harmony can hold them.
- Autumn Cycle — a directed harmony; the season turns and comes home.
- Emergence and Resolution — everything at once, bent into a single arc.
Études 1–6 walk the consonance terrain (placement, gravity, tension, movement, timbre); 7–9 walk the rhythm continuum one region at a time; 10 closes the loop into life; 11–12 are directed by the composer. All études are compile-checked by the test suite, so they always match the current API.
One craft rule holds across the path: scaffolding is inaudible or embodied. Terrain anchors sing to the habitat bus, not to the audience, unless the drone is itself the subject, as with the suns of Gravity. Pulse carriers get resonant bodies and lives of their own, or the pulse is left to condense from the colony.
Research assays
samples/research/ holds comparison fixtures — heredity/selection ablations,
external-scaffold rhythm controls, and mechanism studies. They study the
instrument rather than play it, and are not part of the path.
Offline rendering
The conchordal instrument never writes audio to disk — performances are
ephemeral by design. For offline WAV rendering use the separate
conchordal-render binary, which shares the core engine but is not the
instrument.