I have been porting my ChucK tools to Ocaml. There are a few reasons for this:

  • After the delight of programming in Elm, I wanted a functional programming oriented, strongly typed language.
  • Have a single codebase instead of split between Python and Chuck
  • Ocaml is a bit more performant than ChucK, and its garbage collector plays nice enough to not mess up audio synthesis too much.
  • It has escape hatches if things get stateful (both a blessing and a curse!).
  • CISP always had functional programming (lisp-like) design, which didn’t combine so well with the more imperative ChucK.

As a starting point, I used Luc Döbereiner’s “processes”, but right now it mainly uses the JACK bindings and has it’s own libraries with a wide variety of tools:

Cisp.ml is the main algorithmic toolkit. Its main datatype is sequences of values. These values can be amplitudes, events or even midinotes.

Although Ocaml has lists ( [1;2;3;4] ) which could be used for sequences, I use a slightly different data type. Seq.t is a data type in Ocaml that is very similar to a lazy list: a Seq.t is a function that takes a unit argument “( )” and returns either the empty Seq or a Cons of an element and a new function that returns the rest of the sequence. Because it is not a value, but a function, it is lazy. This allows one to be more flexible with

type 'a Seq.t = unit -> 'a Node

type 'a Node = Nil | Cons( 'a, Seq.t )

A possible issue with Seq.t is that although they can be finite, it may also be infinite. Functions that process seq’s thus have to be capable of dealing with that (without getting stuck trying to process the whole infinite sequence). I therefore also defined “Infseq.t”:

type 'a inf_node = InfCons of 'a * 'a t
and +'a t = unit -> 'a inf_node

This can simplify the code a lot, since we know it is infinite, we don’t have to worry about it ending! We can also only expose functions that safely handle infinite sequences.