Steno:
Filter:
Steno/Classes (extension) | Little Languages | Live Coding

Steno
ExtensionExtension

A little language for spinning long strings of synths

Description

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:

Semantics:

NOTE:

To avoid live coding troubles, some optional simplifications are given (by the -preProcessor):

Class Methods

.new

.push

Return a new instance, ready to be specified. If push is used, it is immediately pushed (see -push).

Arguments:

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.

.current

The current Steno instance (like e.g. TempoClock: *default).

Instance Methods

.value

Interpret a string of steno code.

Arguments:

string

The program to run (a String).

.push

Only one instance of steno can be the current one. "push" make this current and allocate necessary busses.

Arguments:

pushSyntax

If true, modify the sclang interpreter preprocessor to allow to write steno programs directly. Lines that are prefixed with "--" are interpreted as steno code, multiple lines are interpreted as parallel.

.pop

Clears the busses and removes it.

Arguments:

popSyntax

Reset interpreter to normal

.clear

Free all ressources

.set

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.

NOTE: when the value is a function, it is called for each synth, and controls are passed in as a dictionary, as to allow arguments to depend on the graph.
NOTE: 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.

A short form is the method -setter, which generates a dummy synth with referenced settings.

Special values are:

fadeTimecross fade timedefault: 0.02
attackratio of fadeTime used as attack (for 1, it equals fadeTime)default: 0
mixsound leveldefault: 1
throughfor filters: pre vs. post leveldefault: 0
hangTimefor filters, as a maximum release tail length, unless fadeTime is longerdefault: 30

Arguments:

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.

.setGlobal

Dictionary of synth arguments for all synth functions (for Special values, see -set).

Arguments:

... 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

.settings

Instance of class StenoSettings, which provides different levels of synth arguments for all synth functions:

globalSettingsparameters applied to each synth in the graph
synthSettingsparameters 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.

.numChannels

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.

.expand

Set to true to make synth functions multichannel expand.

.freeAll

Free all synths and empty current cmdLine.

.releaseHanging

Free all synths that have been released but which still run as they have a filter input. This will cut long filter tails.

.quant

Specify the moment of changes relative to a temporal grid (see Quant).

.quelle

.filter

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.

Arguments:

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:

input
The input signal for the filter
controls
A dictionary of further control inputs. It passes the following values:
gate
Optional gate trigger that goes to zero when the synth is freed

index
index of that specific synth (not counting internal synths needed for parentheses or square brackets).

depth
the nesting depth in the code

mix
the level control of the output signal
through (only: filter)
controls the ratio previous input to filtered output signal
env
the envelope that is used to fade in and fade out the input signal.
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).

Discussion:

WARNING: In the filter method, when the synth is replaced by a new one, only the input signal is faded out. So you have to take care that your processed output will become silent after some time. If you add a signal to the output, use the \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.

.declareVariables

Add a number of variable names that can be used to store and recall signals.

Arguments:

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):

mix (1)
How much of the stored signal is forwarded to the right
through (1)
How much of the signal to its left is forwarded to the right
feedback (0)
An attenuverter ranging between -1.0 and 1.0. Its absolute value determines the amount feedback from the right-most declaration to the left-most. If negative, the feedback is phase-inverted.
assignment (1)
The number of times a variable can be assigned in succession (left to right). If the number is reached, the signal is not altered anymore. Assigned signals are mixed down to one multichannel stream.

.operator

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+*}.

WARNING: You have to take care that your processed output will become silent after some time. If you add a signal to the output, use the \gate.kr control or controls[\env] to envelope it. See above under -filter

Arguments:

name

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).

.setter

A convenience method that generates a dummy synth with a setting that spills over to subsequent synths (see comment at -set).

NOTE: as the synths are kept running, in fact this doesn't work as well as it should. We'd need to reset the synth parameters to make them forget the values that have been passed in.

.variables

Returns a dictionary of variables, if defined.

.resendSynths

Restart all synths and release hanging notes.

.rebuild

Generate new SynthDefs and restart all synths.

.bus

The output bus.

.busIndices

An array of contiguous bus indices used internally for signal routing

.monitor

Returns the monitor synth which maps the last output to the output bus (default: 0).

.cmdLine

Return most recently compiled code, after preprocessing.

.rawCmdLine

Return most recently evaluated code.

.prevTokens

Returns the most recent tokens (the cmdLine split into separate elements, by default letters, but this could also be otherwise, see -preProcessor).

.argList

.synthList

.diff

.encyclopedia

.server

.synthList

.maxBracketDepth

Introspection: returns internal representations of busses, synthdefs, synths, and synth ressources.

.preProcess

Specify whether the internal preProcessor is used or not. In situation where efficiency is important, it can be omitted by just writing 'correct' code.

.preProcessor

Set the preProcessor

Steno uses a DiffString parser to interpret code. You can change its tokenizer to fit your own language:

Other things to do

BNF for standard Steno

<letter> is any printable letter
<synth> ::== <letter>
<op> ::== <letter>
<exp> ::== { <exp> | <synth> | <ser> | <par> | <app> }
<ser> ::== `(` <exp> `)`
<par> ::== `[` <exp> `]`
<app> ::== `{` <exp> { <op> } `}`
[1] - This little language was developed together with the students of the music informatics seminar 2013 at the IMM, in particular Armin Badde, Raffael Seyfried, and Florian Zeeh. It has been further developed together with Till Bovermann and Ron Kuivila. Special thanks also to Hans W. Koch, who moderated the seminar together with me.