RTG (Rhythm, Time and Geometry) is a music EDSL for the creation and manipulation of rhythmic patterns implementing a geometrically informed API exploring:
- The two way relation between musical rhythm and geometric structure
- Computational abstractions and implementations of musical time.
It is part of my doctoral research project on the affordances of programming language abstractions in music language design and implementation, particularly in the context of live coding. It addresses the following general question: How programming language design and features translate to musical expressiveness for composition and live performance?
Important
The library is in a provisional state and still not released on Hackage. The API is bloated (most module functions are exported for experimentation) and still subject to redesign.
- Rhythm, Time and Geometry @ Algorithmic Pattern Salon (2023)
- Demo: A Geometric Approach to Generate Musical Rhythmic Patterns in Haskell @ FARM (2024)
This method installs Haskell tools system wide and is the most direct way of using the library. In case of problems, you may try using nix.
- Install GHCup to install the Haskell toolchain (you may select all the default options).
- Clone this repository.
- Run
cabal build
from the root of the repository. In case of error, please open an issue with the output. - Follow the usage instructions below to use RTG.
The alternative installation uses the Nix package manager to achieve a reproducible cross-platform development environment, necessary for interacting with the library. Another advantage of this method is that it abstracts away the installation of Haskell and reduces dependency compilation thanks to the Nix binary cache, which covers a large part of the packages in its repository. Below are the steps to install the required components.
- Install Nix Package Manager. Note that on Windows, you'll need WSL with systemd enabled.
- Clone this repository.
- From the root of the repository, run
./run.sh
and choose the "default" option: it uses nix to build and install the library. If the process completes successfully the interpreter (ghci
) prompt will be waiting for a command. In case of error, please open an issue with the output. - Exit with the
:quit
command. - Follow the usage instructions below to use RTG.
Warning
Nix will download (and, if necessary, build) all the library dependencies.
This process may take a while to finish, but subsequent invocations will be almost immediate
as long as the Nix store is not cleaned (with nix-collect-garbage
or nix-store --gc
for example).
If you need to clean the store to free up some space and avoid a subsequent rebuild,
add the following lines to your system's nix configuration file (in Linux this is located at /etc/nix/nix.conf
):
keep-outputs = true
keep-derivation = true
With this options, the garbage-collection root created automatically by the run.sh
script
at .nix-gc-roots/
will make the build persistent.
- Install SuperDirt (audio engine):
- Install SuperCollider and, to have all the predefined synths, the sc3-plugins. Both are accessible through the package manager in various Linux distributions.
- In the SuperCollider IDE (or in a terminal at the
sclang
shell prompt) run:Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.4"); thisProcess.recompile()})
.
- Install FluidSynth (virtual midi synth).
- You might need a (virtual) MIDI connection and routing application, such as
qjackctl
(for Jack or Pipewire on Linux),qpwgraph
(Pipewire on Linux) or Audio MIDI Setup (default on MacOS). For Windows, this article suggests to the "loopMIDI" application (which currently support Windows 7 to 10).
- Start SuperDirt: Open SuperCollider (or run
sclang
from a terminal) and run (Ctrl+Enter)SuperDirt.start
. This will load the audio engine and load its standard samples.- Alternatively, or in case of SuperCollider error messages regarding the buffer or late messages, run with the SuperDirt configuration file provided (it contains configuration and optimization options):
sclang superdirt_startup.scd
- Alternatively, or in case of SuperCollider error messages regarding the buffer or late messages, run with the SuperDirt configuration file provided (it contains configuration and optimization options):
- Run
fluidsynth
its own terminal window and make sure is connected to your default midi output device (through the routing application of your system).- In Linux (using pipewire-jack or jack), you may run the following command to make the midi connections automatically:
fluidsynth --server --audio-driver jack --midi-driver jack --connect-jack-outputs
- In Linux (using pipewire-jack or jack), you may run the following command to make the midi connections automatically:
- Open a terminal at the repository root (where this file is located)
- Run
cabal repl
or - If installed using Nix: run
./run.sh
, selectdefault
and wait for the input prompt.
- Run
- Sample names used in some pattern functions match those of the
DirtSamples
quark installed bySuperDirt
. a list of them can be printed by running~dirt.postSampleInfo;
in SuperCollider.
RTG has several funcions to generate rhythmic patterns
that are interpreted as MIDI and OSC message streams.
In the first case the default MIDI output device is used.
The list of active MIDI devices can be displayed using the devices
command at the prompt:
λ> devices
For OSC message playback, an active SuperDirt instance, with its standard sample library loaded, is needed. To create a pattern use any of the following:
λ> o <sample> <rhythm> -- OSC | play rhythm once
λ> l <sample> <rhythm> -- OSC | play rhythm in loop
λ> p <root> <rhythmA> <rhythmB> -- MIDI | play rhythmA as an scale over rhythmB (loop)
λ> s <root> <rhythmA> -- MIDI | play rhythmA as a scale (loop)
The playback speed of the patterns can be changed on the fly.
λ> setcps <new-cps> -- Change CPS value
λ> readcps -- View current CPS value
To stop playback make sure to bind all patterns to a name with the following syntax:
λ> name <- ...
λ> stop name
If a name is given again to a new pattern, the former becomes headless and the ghci session needs to be ended to kill all active pattern.
λ> :quit
For examples, try running the following commands in sequence:
λ> pat1 <- l "cp" $ rumba <> japanese
λ> o "blip" $ e'(7,13,0) & amiotScale
λ> pat2 <- p (Fs,3) wholeTone (e'(3,8,2))
λ> o "can" $ e'(3,7,0) <> e'(4,8,3)
λ> readcps
λ> setcps 160
λ> stop pat1
λ> stop pat3
Note
The project is being developed with GHC 9.4.8 using regular cabal
commands.
The run.sh
script and the nix-shell itself are intended for end users.
The current default shell
environment can be invoked directly by nix-shell nix/shell0.nix
.
It depends on the files created by the following sequence of commands,
which should be called to update them any time the .cabal
file is changed.
# Translate cabal file into a nix function
cabal2nix ./. > nix/project.nix
REV = nix-instantiate --eval --expr 'builtins.readFile <nixpkgs/.git-revision>'
# Version reference to pin packages
nix-prefetch-git https://github.com/NixOS/nixpkgs.git $REV > nix/nixpkgs.json
For comparison, a default shell-example.nix
file can be created with
cabal2nix . --shell > nix/shell-example.nix
To build the project using nix:
nix-build --attr project nix/release.nix
The compiler version can be given as an argument for the build:
nix-build --argstr compiler ghc964 --attr project nix/release.nix
Current implementation
- Asynchronous evaluation of patterns
- Make patterns addressable so they can be stopped and updated(¿in global state?)
- Implement pattern sync alternatives
- A syntax to make new scheduled patterns affect current playing patterns
- Homogenize rhythmic pattern types show function. Each type should be tagged appropriately.
- Implement well-formed rhythms (¿3 parameters?)
- Continuous morphing of well-formed rhythms using ratio parameter
- Have signals for parameter control (for morphing)
- Geometrically informed continuous morphing between two arbitrary rhythms
- Add
doctest
/doctest-extract
for automatic in-documentation property testing (QuickCheck) - Fix haddocks (see Polygon module for example module header)
Alternative implementations and further work
- FRP implementations.
- Tidal Cycles pattern representation
- AFRP: Yampa, Euterpea MUI library
- New interpreter
- Parsing: parsec/megaparsec
- Audio
- OSC:
hosc
- MIDI:
Euterpea
- Embed MIDI functionality using
fluidsynth
- OSC:
Midterm
- Expose options to change/modify event streams to make the system modular (regarding changing sound engine or using other digital instrument).
- Create a Tidal Cycles module version.