Capytalk is a Functional Reactive Programming Language that you can use to define interactions between internal or external data streams and Kyma Sound parameters.
Reactive programming is a paradigm for computing and modifying asynchronous data streams. Some examples of asynchronous data streams are moving your finger on a tablet, pressing a key on a MIDI keyboard, or clicking a button in the VCS; those are asynchronous data streams, because they don’t happen at regularly spaced intervals, and there’s no way to anticipate exactly when a performer is going to touch a tablet or tilt an accelerometer. Whenever you generate a gesture, you are sending an asynchronous stream of values that Capytalk can interpret in order to update the parameter values of the Sound that is currently running on the APU.
The idea of reactive programming is to define a function that will be evaluated whenever a new value arrives. Those functions, sometimes called observers, “subscribe” to a stream; they listen for new values and react only when a new value arrives. This is a classic example of the so-called Observer Pattern.
Reactive programming in Kyma
Signal flow programming in Kyma is synchronous; everything is locked to the sample rate. Capytalk, on the other hand, deals with a mix of synchronous and asynchronous data streams. A Capytalk EventValue can be associated with a Virtual Control Surface widget and/or an external controller (or other data source) that could transmit a new data value at any time; you cannot predict when the performer will move a finger across a continuous fingerboard or when a sound designer will move a virtual fader on the screen, and these events do not happen at regularly spaced intervals.
When an EventValue changes, any EventExpressions (functional programs written in Capytalk) that depend on that EventValue are evaluated; they react to a change in the EventValue. In terms of the Observer Pattern, the EventValue stream is the observable and any Capytalk expressions that include that EventValue are subscribers to, or observers of that data stream.
There are also time-dependent Capytalk EventExpressions that generate synchronous data streams; the message ramp: for example, generates a stream of linearly increasing values once per millisecond, so it generates a synchronous stream of values.
Reactive programming in Capytalk is also functional. A stream can be used as the input to another stream; you can merge streams; you can filter a stream to get a new stream, and in accordance with the principle of data immutability, the original value is not changed.
You can compose Capytalk functions by cascading messages, for example
4 a hz s
As in analog modular synthesis, any signal can be used as either an audio signal and a control signal; that line is similarly blurred in Kyma.
You can teleport between the reactive world of Capytalk and the synchronous world of Sounds, because there are functional aspects of Capytalk and reactive aspects of Sounds. For example, you can use Threshold or Sign as control signals to make decisions or trigger other events. Or you can use CapytalkToSound to inject asynchronous control streams into the synchronous audio signal flow path.
To teleport in the other direction, you can take the output of a Sound (a stream of samples) and use it to control the value of a parameter. If you copy and paste one Sound into the parameter field of another Sound, the output stream of the first Sound flows into the parameter field of the second Sound where it can be interpreted directly as a changing parameter value or used as part of a Capytalk computation of that parameter’s value. The idea of using one signal to modulate a parameter of another is familiar to anyone who has ever used a voltage-controlled analog synthesizer.
Data is Water
Imagine that you would like the value of a Sound parameter to change over time. If you type a single number into that parameter field, you’ve set that parameter to a single, fixed value. To specify a parameter that could change over time, replace that fixed value with an EventValue — represented in Kyma by a name preceded with an exclamation point, for example !Morph.
The conceptual metaphor DATA is WATER provides a powerful analogy for reasoning about a “stream” of data. An EventValue is like the end of a pipe that is connected to the outside world. A stream of data flows through the pipe and ends up in the parameter field where you’ve typed the EventValue name. In fact, you can route the flow of data to any destination in your Sound by placing an outlet (an EventValue) in that destination parameter field. EventValues of the same name are connected to the same external data stream, so anywhere that EventValue appears, it’s a destination for the same external data source. (Think of a pipe junction that fans out to several destinations).
EventValues are global in the sense that every EventValue of the same name receives the same stream of values. EventValues are read-only (the data stream flows into the parameter field, never flowing back into the pipe).
Another way to think of an EventValue is as a symbolic placeholder for a time-varying value — otherwise known as a signal or a stream.