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.