SynthDef Builder¶
nanosynth.synthdef ¶
SynthDef builder and SCgf compiler for nanosynth.
Ported from supriya's ugens/core.py -- minimal subset for defining UGen graphs in Python and compiling them to SuperCollider's SCgf binary format.
ServerProtocol ¶
Bases: Protocol
Structural type for servers that can receive SynthDefs and create synths.
Missing ¶
Sentinel for required parameters (no default).
Default ¶
Sentinel for parameters whose default is computed from other parameters.
UGenSerializable ¶
Protocol for objects that can be serialized into a UGen graph (e.g. Envelope).
PseudoUGen ¶
Base class for virtual UGens that compose other UGens.
UGenOperable ¶
Mixin providing arithmetic and signal-processing operators on UGen signals.
All UGen outputs, constants, and vectors inherit these operators.
Standard Python operators (+, -, *, /, **, %,
//, <, >, <=, >=, &, |, ^, <<,
>>) produce BinaryOpUGen nodes in the graph. Named methods provide
SuperCollider-specific operations: pitch conversion (midicps,
cpsmidi), amplitude conversion (dbamp, ampdb), waveshaping
(distort, softclip, tanh_), clipping (clip2, fold2,
wrap2), ring modulation (ring1--ring4), and more.
When both operands are constants, the operation is folded at compile time (no UGen is emitted).
equal ¶
equal(expr: UGenRecursiveInput) -> UGenOperable
Signal equality test. Returns 1.0 when equal, 0.0 otherwise.
Uses an explicit method instead of __eq__ to preserve Python
object identity semantics and hash stability.
not_equal ¶
not_equal(expr: UGenRecursiveInput) -> UGenOperable
Signal inequality test. Returns 1.0 when not equal, 0.0 otherwise.
round_ ¶
round_(expr: UGenRecursiveInput) -> UGenOperable
Round self to the nearest multiple of expr.
round_up ¶
round_up(expr: UGenRecursiveInput) -> UGenOperable
Round self up to the next multiple of expr.
atan2 ¶
atan2(expr: UGenRecursiveInput) -> UGenOperable
Two-argument arctangent: atan2(self, expr) in radians.
hypot ¶
hypot(expr: UGenRecursiveInput) -> UGenOperable
Euclidean distance: sqrt(self**2 + expr**2).
hypotx ¶
hypotx(expr: UGenRecursiveInput) -> UGenOperable
Approximate hypotenuse: abs(self) + abs(expr) - min(abs(self), abs(expr)) / sqrt(2).
ring1 ¶
ring1(expr: UGenRecursiveInput) -> UGenOperable
Ring modulation variant: self * expr + self.
ring2 ¶
ring2(expr: UGenRecursiveInput) -> UGenOperable
Ring modulation variant: self * expr + self + expr.
ring3 ¶
ring3(expr: UGenRecursiveInput) -> UGenOperable
Ring modulation variant: self * self * expr.
ring4 ¶
ring4(expr: UGenRecursiveInput) -> UGenOperable
Ring modulation variant: self * self * expr - self * expr * expr.
thresh ¶
thresh(expr: UGenRecursiveInput) -> UGenOperable
Threshold gate: self if self >= expr else 0.
amclip ¶
amclip(expr: UGenRecursiveInput) -> UGenOperable
Amplitude clipping: self * expr if expr > 0 else 0.
scaleneg ¶
scaleneg(expr: UGenRecursiveInput) -> UGenOperable
Scale negative part: self * expr if self < 0 else self.
clip2 ¶
clip2(expr: UGenRecursiveInput) -> UGenOperable
Bilateral clipping: clamp self to [-expr, +expr].
excess ¶
excess(expr: UGenRecursiveInput) -> UGenOperable
Residual after clip2: self - clip2(self, expr).
fold2 ¶
fold2(expr: UGenRecursiveInput) -> UGenOperable
Bilateral folding: fold self into the range [-expr, +expr].
wrap2 ¶
wrap2(expr: UGenRecursiveInput) -> UGenOperable
Bilateral wrapping: wrap self into the range [-expr, +expr).
midiratio ¶
midiratio() -> UGenOperable
Convert MIDI interval (semitones) to frequency ratio (e.g. 12 -> 2.0).
ratiomidi ¶
ratiomidi() -> UGenOperable
Convert frequency ratio to MIDI interval in semitones (e.g. 2.0 -> 12).
softclip ¶
softclip() -> UGenOperable
Soft clipping: linear below 0.5, asymptotic above. Keeps signal in approximately [-1, 1].
UGenScalar ¶
OutputProxy ¶
ConstantProxy ¶
UGenVector ¶
UGen ¶
Bases: UGenOperable, Sequence['UGenOperable']
Base class for all unit generators.
A UGen represents a single signal-processing node in a SynthDef graph.
Subclasses are declared with the @ugen decorator, which generates
__init__, rate constructors (.ar, .kr, .ir, .dr),
and parameter accessors.
UGens are instantiated inside a SynthDefBuilder context manager and
automatically register themselves with the active builder. They support
multi-channel expansion: passing a list to any parameter produces
parallel UGen instances (one per list element), returned as a
UGenVector.
Indexing a UGen (ugen[0]) returns an OutputProxy referencing a
specific output channel.
UnaryOpUGen ¶
Bases: UGen
Applies a unary operator to a single input signal.
Created implicitly by named unary methods on UGenOperable (e.g.
sig.midicps(), sig.tanh_()). The special_index selects
which UnaryOperator to apply.
BinaryOpUGen ¶
Bases: UGen
Applies a binary operator to two input signals.
Created implicitly by Python operators (+, -, *, /,
etc.) and named binary methods (clip2, ring1, etc.) on
UGenOperable. The special_index selects which
BinaryOperator to apply. Includes compile-time algebraic
optimizations (e.g. x * 0 = 0, x + 0 = x, x ** 1 = x).
Parameter ¶
Bases: UGen
A named SynthDef parameter with a default value, rate, and optional lag.
Parameters are created by SynthDefBuilder.add_parameter() or the
SynthDefBuilder(**kwargs) constructor. During build(), they are
collected, sorted, and mapped to the appropriate Control UGen type
based on their rate (CONTROL -> Control, AUDIO -> AudioControl,
TRIGGER -> TrigControl, CONTROL+lag -> LagControl).
Control ¶
Bases: UGen
A group of parameters exposed as control-rate (or scalar-rate) inputs.
Created internally by SynthDefBuilder.build() to aggregate
Parameter instances by rate. Subclasses AudioControl,
LagControl, and TrigControl handle audio-rate, lagged, and
trigger-rate parameters respectively.
UGenInput ¶
Bases: NamedTuple
A single input to a UGen node in the graph.
UGenNode ¶
Bases: NamedTuple
A UGen in the graph with its connections.
SynthDefGraph ¶
Bases: NamedTuple
Structured representation of a SynthDef's UGen graph.
SynthDef ¶
A compiled UGen graph, ready for binary serialization and server dispatch.
Produced by SynthDefBuilder.build() or the @synthdef decorator.
Contains the topologically sorted UGen list, constant table, control
mapping, and parameter index.
Key methods:
compile()-- serialize to SuperCollider's SCgf binary format.send(server)-- send the compiled bytes to a running server.play(server, **params)-- send and immediately create a synth.dump_ugens()-- return a human-readable graph representation.graph()-- return a structuredSynthDefGraphfor introspection.to_dot()-- export the graph as a Graphviz DOT string.
to_dot ¶
to_dot(*, rankdir: str = 'TB', label: bool = True) -> str
Export the UGen graph as a Graphviz DOT string.
save ¶
save(
path: str | Path, *, use_anonymous_name: bool = False
) -> None
Write this SynthDef to a .scsyndef file.
Args: path: Destination file path. use_anonymous_name: If True, use the anonymous name in the binary.
play ¶
play(
server: ServerProtocol,
target: int = 1,
action: int = 0,
**params: float,
) -> SupportsInt
Send this SynthDef (if needed) and create a synth. Returns a Synth proxy.
SynthDefBuilder ¶
Context manager for constructing SynthDef UGen graphs.
Usage::
with SynthDefBuilder(frequency=440.0, amplitude=0.3) as builder:
sig = SinOsc.ar(frequency=builder["frequency"])
Out.ar(bus=0, source=sig * builder["amplitude"])
synthdef = builder.build(name="my_synth")
Parameters are declared as keyword arguments (name=default_value) or
via add_parameter(). Inside the context, UGens instantiated with
a matching _uuid are automatically added to the graph. On
build(), the graph is sorted topologically, controls are mapped,
unused pure UGens are eliminated, and a SynthDef is returned.
__getitem__ ¶
__getitem__(item: str) -> OutputProxy | Parameter
Look up a parameter by name.
Returns an OutputProxy for scalar parameters, or the Parameter itself for multi-channel parameters (sequence values).
Raises: KeyError: If the parameter name does not exist.
add_parameter ¶
add_parameter(
*,
name: str,
value: float | Sequence[float],
rate: ParameterRate | None = ParameterRate.CONTROL,
lag: float | None = None,
) -> OutputProxy | Parameter
Add a named parameter to the SynthDef.
Args: name: Parameter name (must be unique within this builder). value: Default value. A sequence creates a multi-channel parameter. rate: Parameter rate (CONTROL, AUDIO, TRIGGER, or SCALAR). lag: Lag time in seconds. Produces a LagControl when set.
Returns: OutputProxy for scalar parameters, or the Parameter for multi-channel parameters.
Raises: ValueError: If a parameter with this name already exists.
build ¶
build(
name: str | None = None, optimize: bool = True
) -> SynthDef
Compile the UGen graph into a SynthDef.
Performs control mapping, topological sorting, and optional dead code elimination. The builder can be reused after calling build().
Args: name: SynthDef name. If None, an anonymous MD5 hash is used. optimize: If True, eliminate unused pure UGens from the graph.
Returns: A compiled SynthDef ready for sending to a server.
param ¶
param(
default: Missing | Default | float | None = MISSING,
*,
unexpanded: bool = False,
) -> Param
Define a UGen parameter. Akin to dataclasses.field.
ugen ¶
ugen(
*,
ar: bool = False,
kr: bool = False,
ir: bool = False,
dr: bool = False,
new: bool = False,
has_done_flag: bool = False,
is_multichannel: bool = False,
is_output: bool = False,
is_pure: bool = False,
is_width_first: bool = False,
channel_count: int = 1,
fixed_channel_count: bool = False,
) -> Callable[[type[UGen]], type[UGen]]
Decorate a UGen class. Akin to dataclasses.dataclass.
control ¶
control(
value: float | Sequence[float] = 0.0,
rate: str | ParameterRate = "kr",
lag: float | None = None,
) -> Parameter
Define a SynthDef parameter with rate and lag metadata.
Returns a Parameter instance suitable for passing to
SynthDefBuilder as a keyword argument::
SynthDefBuilder(
freq=control(440.0, rate="ar"), # audio rate
amp=control(0.3, lag=0.1), # control rate + lag
bus=control(0, rate="ir"), # scalar rate
)
Args:
value: Default parameter value (float or sequence for multi-channel).
rate: Parameter rate -- "ar", "kr", "ir", "tr",
or a ParameterRate enum member. Defaults to "kr".
lag: Lag time in seconds. Produces a LagControl when set.
synthdef ¶
synthdef(
*args: str | tuple[str, float],
) -> Callable[..., SynthDef]
Decorator for constructing SynthDefs from functions.
Parameter rates and lags can be specified positionally::
@synthdef("ar", ("kr", 0.5))
def my_synth(freq=440, amp=0.1):
...
Without arguments, all parameters default to control rate::
@synthdef()
def my_synth(freq=440, amp=0.1):
...