Patterns¶
Pattern-based sequencing: value patterns (Pseq, Prand, Pwhite, ...), the
event pattern Pbind and its composites (Ppar, Pmono, Pdef, ...), and the
Clock/Player scheduling pair. See the Patterns guide for
the event model, the pitch chain, and quantization.
nanosynth.patterns ¶
Pattern-based sequencing system for musical event scheduling.
Patterns are reusable templates that produce fresh iterators each time
(standard Python Iterable[T] protocol). This mirrors SuperCollider's
Pattern/Stream split mapped to Python idioms: Pattern.__iter__()
returns a generator.
Basic usage::
from nanosynth.patterns import Pseq, Pbind, Clock
pattern = Pbind(
instrument="default",
freq=Pseq([440, 550, 660], repeats=2),
dur=0.5,
amp=0.3,
)
clock = Clock(bpm=120)
player = pattern.play(clock, server)
# ... later ...
player.stop()
clock.stop()
Rest ¶
Silence marker.
When dur in an event is a Rest instance, the Player advances
time by rest.dur beats but does not create a synth.
Pattern ¶
Bases: ABC, Generic[T]
Abstract base class for all patterns.
Subclasses must implement __iter__ which returns a fresh iterator
each time it is called.
play ¶
play(
clock: Clock,
server: Any,
latency: float | None = None,
quant: float | None = None,
offset: float = 0.0,
) -> Player
Start playing this pattern on the given clock and server.
Defined here rather than on :class:EventPattern so that the generic
wrappers -- Pn(Pbind(...)), Pseq([...]), Pfin(...) -- stay
playable. Only patterns that yield events are meaningful to play; a
value pattern will produce nonsense.
Args:
clock: The Clock providing tempo.
server: A Server instance for synth creation.
latency: Scheduling latency override in seconds; defaults to the
clock's latency.
quant: Quantization in beats. Playback starts on the next
quant-beat boundary of the clock's grid instead of
immediately, so patterns launched at different moments stay
phase-aligned. None (the default) starts at once.
offset: Beats past the quantization boundary at which to start.
Returns: A Player that can be stopped.
Pseq ¶
Bases: Pattern[T]
Sequential playback of a sequence.
If an element is itself a Pattern, it is flattened (yielded from).
Args: sequence: Items to yield. repeats: Number of times to cycle through the sequence.
Prand ¶
Bases: Pattern[T]
Random selection from a sequence.
Args:
sequence: Pool of items to choose from.
repeats: Number of values to produce.
seed: Optional RNG seed. When given, each iteration restarts from this
seed, so the pattern is reproducible (e.g. for NRT rendering). When
None (default) a fresh per-instance RNG is used -- still
independent of the global random state, so unrelated random
calls elsewhere cannot perturb the sequence.
Pwhite ¶
Bases: Pattern[float]
Uniform random float between lo and hi.
Args:
lo: Lower bound (inclusive).
hi: Upper bound (inclusive).
repeats: Number of values to produce.
seed: Optional RNG seed (see :class:Prand for the seeding semantics).
Pseries ¶
Bases: Pattern[float]
Arithmetic series: start, start+step, start+2*step, ...
Args: start: Initial value. step: Increment per step. repeats: Number of values to produce.
Pgeom ¶
Bases: Pattern[float]
Geometric series: start, start*grow, start*grow^2, ...
Args: start: Initial value. grow: Multiplier per step. repeats: Number of values to produce.
Pchoose ¶
Bases: Pattern[T]
Weighted random selection from items.
Args:
items: Pool of items to choose from.
weights: Relative weights for each item (must sum to > 0).
repeats: Number of values to produce.
seed: Optional RNG seed (see :class:Prand for the seeding semantics).
Pn ¶
Bases: Pattern[T]
Repeat a pattern N times.
Each repetition creates a fresh iterator from the wrapped pattern.
Args: pattern: The pattern to repeat. repeats: Number of full repetitions.
Pconst ¶
Bases: Pattern[float]
Yield values from pattern until their sum reaches total.
The last value is clipped so the sum equals total exactly.
Args: total: Target sum. pattern: Source pattern for values.
Pkey ¶
Bases: Pattern[Any]
Reference another key of the event currently being built.
Resolved by :class:Pbind alongside its other bindings, so it sees their
values for this event::
Pbind(freq=Pseq([440, 660]), amp=Pkey("freq", lambda f: 100.0 / f))
Ordering follows from what the bound key is. A Pkey bound to an input
of the derivation chain (degree, dur, db, ...) resolves before
the chain runs, so it can drive it. A Pkey bound to anything else
resolves after, so it can read the chain's output::
# amp follows the derived freq, not the raw degree
Pbind(degree=Pseq([0, 4]), amp=Pkey("freq", lambda f: 40.0 / f))
Args: key: Name of the event key to read. transform: Optional callable applied to the referenced value. default: Value used when the referenced key is absent.
Note that patterns do not overload arithmetic operators, so combine values
with transform rather than writing Pkey("freq") * 2.
EventPattern ¶
Bases: Pattern[Event]
Base class for patterns that yield events rather than bare values.
A marker for the event layer -- Pbind and the composites built on it.
:meth:Pattern.play lives on the base class, so generic wrappers such as
Pn(Pbind(...)) are playable too.
Pbind ¶
Bases: EventPattern
Bind keys to patterns/values to produce a stream of events.
Stops when any bound pattern is exhausted. Scalar values repeat
forever. Events are merged with _EVENT_DEFAULTS.
Args: **bindings: Key-value pairs where values can be floats, strings, Rest instances, or Pattern instances.
Ppar ¶
Bases: EventPattern
Play several event patterns in parallel, merged into one stream.
Events from all sub-patterns are interleaved in time order. Each yielded
event's delta is rewritten to the gap until the next event in the
merged stream, while its sustain (and every other key) is left alone,
so each voice keeps its own note lengths. Simultaneous events land in the
same bundle timestamp and therefore start on the same sample.
The merged stream ends when every sub-pattern is exhausted.
Args: patterns: Event patterns to run concurrently.
Ptpar ¶
Bases: Ppar
Like :class:Ppar, but each pattern starts at its own beat offset.
Args:
pairs: (offset_in_beats, pattern) tuples.
Pmono ¶
Bases: EventPattern
One persistent synth whose parameters are updated per event.
Where :class:Pbind creates a synth per event, Pmono creates a single
synth on its first event and sends /n_set for every event after that,
releasing it when the pattern ends. This is how sclang models a
monophonic, continuously-gliding line (portamento, filter sweeps) that a
stream of separate synths cannot produce.
Accepts the same bindings as :class:Pbind, including the pitch chain.
sustain is ignored: the synth is held for the whole pattern rather than
released per note.
Args:
instrument: SynthDef name for the persistent synth.
**bindings: As :class:Pbind.
Pdef ¶
Bases: EventPattern
A named, hot-swappable event pattern.
Pdef(name, pattern) registers or replaces the pattern stored under
name; Pdef(name) looks up the existing one. A player iterating a
Pdef picks up a replacement at the next event boundary, so a running
part can be redefined without stopping playback -- the pattern analogue of
:class:~nanosynth.proxy.Ndef.
The stream ends when the current source is exhausted; wrap the source in
:class:Pn to loop it.
Args:
name: Registry key.
pattern: New source pattern, or None to look up an existing entry.
Pfin ¶
Bases: Pattern[T]
Yield at most count values from a pattern.
Args: count: Maximum number of values. pattern: Source pattern.
Pfindur ¶
Bases: EventPattern
Yield events until their accumulated duration reaches duration.
The final event's delta is clipped so the total is exact, which is what
makes a bounded pattern line up with a bar boundary.
Args: duration: Total duration in beats. pattern: Source event pattern.
Clock ¶
Tempo clock that drives pattern playback.
Runs a background daemon thread. Uses time.monotonic() for
drift-free absolute scheduling. Multiple players share one clock
for synchronized timing.
Call :meth:stop when done: the running thread holds a reference back to
the clock (and its players), so a clock that is never stopped lives -- with
its thread -- for the rest of the process. The thread is a daemon, so this
does not block interpreter exit, but it is a leak within a long-running
process.
Args:
bpm: Beats per minute (default 120).
latency: Scheduling latency in seconds (default
:data:DEFAULT_LATENCY). Events are sent as OSC bundles stamped
this far ahead, so onset accuracy is set by the engine rather than
by when the Python thread woke. Raise it if playback stutters
under load; lower it for tighter response to live input.
latency
property
writable
¶
latency: float
Scheduling latency in seconds. Settable; applies to later events.
beat_duration
property
¶
beat_duration: float
Duration of one beat in seconds (read-only: 60 / bpm).
elapsed_beats
property
¶
elapsed_beats: float
Beats since this clock's grid origin.
Measured from the origin at the current tempo, so changing bpm
mid-session redefines where past beats fall. Set the tempo before
starting quantized players if you need the grid to be stable.
next_boundary ¶
next_boundary(quant: float, offset: float = 0.0) -> float
Monotonic time of the next quant-beat boundary.
With quant=4 this is the downbeat of the next bar in 4/4. A
non-positive quant means "no quantization" and returns now.
Args: quant: Grid size in beats. offset: Beats past the boundary to return.
stop ¶
stop() -> None
Stop the clock and all its players.
Mirrors :meth:Player.stop for every player: held Pmono synths are
gated off, not just marked stopped. Without this a live Pmono voice
(held with gate=1) would ring until the server quits, since only
per-event Pbind synths have their gate-release bundles already queued
in the engine.
Player ¶
Drives event playback from a pattern on a clock.
Created by Pbind.play() or directly.
Args: pattern: An event pattern to play. clock: The tempo clock. server: A Server instance for synth creation. latency: Scheduling latency override in seconds. Defaults to the clock's latency, so players sharing a clock stay phase-aligned.
latency
property
¶
latency: float
Effective scheduling latency: this player's override, or the clock's.
play ¶
play(
quant: float | None = None, offset: float = 0.0
) -> Player
Start playback. Returns self for chaining.
Args:
quant: Quantization in beats -- start on the next quant-beat
boundary of the clock's grid rather than immediately. None
starts at once.
offset: Beats past the quantization boundary at which to start.