Steno, a little concatenative live coding language embedded in SuperCollider, makes code for combining synth graphs very short, so that writing endless chains is like writing a single long word. A word is a program. A letter is a synth.1
Programs look like this:
Syntax:
Steno has a minimal syntax:
"a"
one letter equals one synth
abc
>> three synths in series, one feeding into the next
"[]"
square brackets indicate a parallely nested structure:
[ab]c
>> a
and b
are in parallel to each other, their sum is fed into c
"()"
round brackets indicate serially nested structure
[(ab)(ab)]
>> both appearances of ab
are in series but parallel to each other
"{}"
curly brackets open a stack for operators in postfix syntax
{ab*}
>> a
and b
are fed into the operator *
{abc*+}
>> b
and c
are fed into the operator *
, its result is fed together with a
into +
"!"
an exclamation mark within the expression forces a full replacement at evaluation time
abc!
abc // this is a comment
Semantics:
diff
command.DiffString.tempFilePath = ...
in case the external diff
command fails to write a temporary file.To avoid live coding troubles, some optional simplifications are given (by the -preProcessor):
ab ab
is equivalent to [(ab)(ab)]
()
or []
), spaces determine either parallel or sequential structuring: [ab ab]
-> [(ab)(ab)]
, and (ab ab)
-> ([ab][ab])
."(ab (ab"
will become (ab (ab))
Return a new instance, ready to be specified. If push is used, it is immediately pushed (see -push).
numChannels |
The number of channels of the interconnecting busses (this is the same across the whole synth tree). |
expand |
If set to true, the synth functions are multichannel expanded to numChannels. |
maxBracketDepth |
The maximum depth of nested brackets. This determines the number of busses that need to be allocated. |
server |
Server to play on. |
The current Steno instance (like e.g. TempoClock: *default).
Only one instance of steno can be the current one. "push" make this current and allocate necessary busses.
pushSyntax |
If true, modify the sclang interpreter preprocessor to allow to write steno programs directly. Lines that are prefixed with |
Clears the busses and removes it.
popSyntax |
Reset interpreter to normal |
Free all ressources
Set and store synth arguments. All synths of that letter will be set to the same value. If you need varaiation between letters, either add some randomness or use the structural arguments passed as controls (see below under -filter and -quelle). You can add your own controls using NamedControls.
A short form is the method -setter, which generates a dummy synth with referenced settings.
Special values are:
fadeTime | cross fade time | default: 0.02 |
attack | ratio of fadeTime used as attack (for 1, it equals fadeTime) | default: 0 |
mix | sound level | default: 1 |
through | for filters: pre vs. post level | default: 0 |
hangTime | for filters, as a maximum release tail length, unless fadeTime is longer | default: 30 |
name |
Name of the synth definition |
... keyValuePairs |
Any number of parmeters and values. Values can be anything that can be converted to a synth argument. |
Dictionary of synth arguments for all synth functions (for Special values, see -set).
... keyValuePairs |
Any number of parmeters and values. Values can be anything that can be converted to a synth argument. NOTE: when the value is a function, it is called for each synth, and controls are passed in, as to allow arguments to depend on the graph
|
Instance of class StenoSettings
, which provides different levels of synth arguments for all synth functions:
globalSettings | parameters applied to each synth in the graph |
synthSettings | parameters applied only to the synths that have a given name |
If the value is a Function (or anything that responds to the message value
), it is called for each synth, passing in the following informations as a dictionary: synthIndex (the count for each synth), index (the count for each type of synth), depth (the current nesting depth), and the token (name of the synth).
The synthSettings have a special feature: if the value is a Ref (containing the value), the setting spills over into the subsequent and deeper nested synths (not to the next level up). This allows to uses synths to set parameters for other synths.
Set the number of channels of the system - if running, synths defs are rebuilt and synths are restarted. If expand is true, the functions will multichannel expand.
Set to true to make synth functions multichannel expand.
Free all synths and empty current cmdLine.
Free all synths that have been released but which still run as they have a filter input. This will cut long filter tails.
Specify the moment of changes relative to a temporal grid (see Quant).
These two methods take a Function and convert it into a SynthDef, represented by a letter.
quelle converts it to a synth def that produces sound without an input necessary (cross fade will envelope the output). It adds to the signal on the bus.
filter converts it to a synth def that filters a signal input (cross fade will envelope the input and thus maintain decaying signals). It replaces the signal on the bus.
name |
The letter which represents the synth def |
func |
A UGen function, it takes the arguments below. For more controls to be set by the -set method, use a NamedControl. Arguments passed to the function are:
|
multiChannelExpand |
Specify whether the ugen graph should be expanded o the full number of channels (see: -numChannels and -expand). |
update |
Specify whether synth should be updated immediately when synth def is changed (MAY CHANGE IN THE FUTURE). |
numChannels |
Specify a number of channels the function should have (by default, it uses -numChannels). |
\gate.kr
control or controls[\env]
to envelope it. There is a synth control input called hangTime
that removes hanging notes after some longer time (after 30 sec by default). You can manually release all potentially hanging synths by calling -releaseHanging.
Add a number of variable names that can be used to store and recall signals.
names |
An array of variable names, usually single letters (for exceptions, see: -preProcess). The leftmost appearance of a variable name means that the signal coming from its left is assigned to as well as passed through it. Subsequent appearances of the same name act like a quelle of the captured signal, i.e. the captured signal re-appears and is added to the signal coming form the left. You can set the following parameters (default values in brackets):
|
Define a new operator. Operators take operands (signals) from the stack and combine them. A stack is defined by enclosing an expression in curly brackets, like {ab*}
. If operands are left on the stack, they can be combined with the result by subsequent operators, like {abc+*}
.
\gate.kr
control or controls[\env]
to envelope it. See above under -filtername |
The letter which represents the synth def |
func |
A UGen function, which takes a specific number of arguments (given by its arity (see below)). Each argument is a signal of the full number of channels of the steno graph. |
arity |
The number of operands (e.g. binary, or ternary). |
multiChannelExpand |
Specify whether the ugen graph should be expanded o the full number of channels (see: -numChannels and -expand). |
update |
Specify whether synth should be updated immediately when synth def is changed (MAY CHANGE IN THE FUTURE). |
A convenience method that generates a dummy synth with a setting that spills over to subsequent synths (see comment at -set).
Returns a dictionary of variables, if defined.
Restart all synths and release hanging notes.
Generate new SynthDefs and restart all synths.
The output bus.
An array of contiguous bus indices used internally for signal routing
Returns the monitor synth which maps the last output to the output bus (default: 0).
Return most recently compiled code, after preprocessing.
Return most recently evaluated code.
Returns the most recent tokens (the cmdLine split into separate elements, by default letters, but this could also be otherwise, see -preProcessor).
Introspection: returns internal representations of busses, synthdefs, synths, and synth ressources.
Specify whether the internal preProcessor is used or not. In situation where efficiency is important, it can be omitted by just writing 'correct' code.
Set the preProcessor
Steno uses a DiffString parser to interpret code. You can change its tokenizer to fit your own language:
<letter> is any printable letter <synth> ::== <letter> <op> ::== <letter> <exp> ::== { <exp> | <synth> | <ser> | <par> | <app> } <ser> ::== `(` <exp> `)` <par> ::== `[` <exp> `]` <app> ::== `{` <exp> { <op> } `}`