,#+ARROYO_EMACS_MODULE: tidalcycles
A Generative Art/Music library in Haskell focused around audio loops and live-coding Music. I'd like to make some weird drone and found-footage stuff.
TidalCycles (or 'tidal' for short) is free/open source software, that allows you to make patterns with code, whether live coding music at algoraves or composing in the studio.
It includes language for describing flexible (e.g. polyphonic, polyrhythmic, generative) sequences. It also has an extensive library of patterning functions, for transforming and combining them.
Tidal is highly composable in that pattern transformations can be easily combined together, allowing you to quickly create complex patterns from simple ingredients.
Tidal does not make sound itself, but is designed for use with the featureful SuperDirt synth, and can control other synths over Open Sound Control or MIDI. Whether you're using SuperDirt or a synth, every filter and effect can be patterned and manipulated independently with Tidal patterns.
Tidal is embedded in the Haskell language, although you don't have to learn Haskell to learn Tidal - most tidal coders have little or no experience in software engineering.
This sounds like my sort of fun.
Get Up and Running
NEW: Use PipeWire.
Start SuperDirt in nix-shell (on Nixos), wrapped with
pw-jackopen a Tidal mode buffer and run
tidal-start-haskell
NEXT pw-jack in the nix-shell instead of having to shell pw-jack?
Resources & Learning
if I have to use pulseaudio...
start jack
get pulseaudio loopback setup if i want to route through my bluetooth headphones:
pactl load-module module-null-sink sink_name=sink_mix sink_properties=device.description=sink_mix
pactl load-module module-loopback source=jack_in sink=sink_mixput the sink_mix on whatever headphone i want, like bluetooth
if jack routing is weird, make it look like this:
file:~/org/data/59/fecc44-79e4-47a6-94d6-c1354245d03b/qjackctl-graph.png
Installation and Configuration
DONE Re-enable installations pending NixOS/nixpkgs/pull/172208
https://github.com/NixOS/nixpkgs/pull/172208
Getting a Nix Shell to Tidal and SuperCollider
This shell.nix gets us a GHC with Tidal running, as well as a SuperCollider
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = [
pkgs.supercollider_scel
(pkgs.haskellPackages.ghcWithPackages (hpkgs: [hpkgs.tidal]))
];
}I can run sclang with this wrapper installed to ~/bin/sclang-wrapped:
nix-shell ~/org/nix-shells/tidalcycles-shell.nix --run "sclang $@"Emacs configuration
I have to pull sclang-mode out of the SuperCollider package, i would like to instead create an CCE_HOME_EPKGS override for this...
(use-package tidal
:config
(setq tidal-interpreter "~/bin/tidal-wrapped"))
(add-to-list 'load-path
(concat (s-chomp (shell-command-to-string
(concat
"nix-store --query --outputs "
"$(nix-instantiate --add-root -E '"
"with import <nixpkgs> {}; supercollider_scel"
"' 2>/dev/null)")))
"/share/emacs/site-lisp/SuperCollider"))
(use-package sclang
:ensure nil
:config
(setq sclang-program "~/bin/sclang-wrapped"))
(use-package sclang-extensions)
(provide 'cce/tidalcycles)redefine tidal-boot-script-path using the nix-shell
(setq tidal-boot-script-path
(let ((filepath
'(("path" . "echo -n data-dir: && nix-shell ~/org/nix-shells/tidalcycles-shell.nix --run \"ghc -e 'import Paths_tidal' -e 'getDataDir>>=putStr'\" 2>/dev/null")
("separator" . "/"))))
(concat
(string-trim (cadr (split-string
(shell-command-to-string (cdr (assoc "path" filepath))) ":")))
(cdr (assoc "separator" filepath))
"BootTidal.hs")))Installing SuperCollider to system with home-manager
I have this on my home-manager and PATH for the Emacs configuration to load sclang-mode et al.
{ pkgs, ... }:
{
home.packages = [ pkgs.supercollider_scel ];
}sclang = pkgs.supercollider_scel;
Installing SuperDirt
Run this in sclang or scide to install SuperDirt:
Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.2"); thisProcess.recompile()})This does some BS: : Cloning into '/home/rrix/.local/share/SuperCollider/downloaded-quarks/quarks'... : Cloning into '/home/rrix/.local/share/SuperCollider/downloaded-quarks/SuperDirt'...
NEXT install superdirt repositories in home-manager or so
Running SuperDirt
As for running it ... this is from SuperDirt repo, run pw-jack nix-shell nix-shells/tidalcycles-shell.nix --run 'sclang ./dirt-tidal-load.sclang'
(
s.reboot { // server options are only updated on reboot
// configure the sound server: here you could add hardware specific options
// see http://doc.sccode.org/Classes/ServerOptions.html
s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
s.options.numWireBufs = 64; // increase this if you get "exceeded number of interconnect buffers" messages
s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary
s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary
// boot the server and start SuperDirt
s.waitForBoot {
~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)
// for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
// s.sync; // optionally: wait for samples to be read
~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0
// optional, needed for convenient access from sclang:
(
~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];
~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];
~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];
~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
);
};
s.latency = 0.3; // increase this if you get "late" messages
};
);Starting up TidalCycles
With all the scaffolding in place, I should be able to start Tidal itself in ghci, for example with this wrapper provided to tidal-mode in the emacs configuration above:
[[ -s "`which nixGLIntel`" ]] && nixGLIntel nix-shell ~/org/nix-shells/tidalcycles-shell.nix --run "ghci $@"
[[ -s "`which nixGLIntel`" ]] || nix-shell pw-jack ~/org/nix-shells/tidalcycles-shell.nix --run "ghci $@"or directly with nixGLIntel nix-shell nix-shells/tidalcycles-shell.nix ghci in to a buffer name =tidal=
Basic noises
little drum loop:
d1 $ sound "bd sd:1"
d2 $ sound "hh hh hh hh"
d3 $ sound "arpy"
hush