The Arcology Garden

TidalCycles

Contents

,#+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

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:

shell
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_mix

put 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

nix:tangle nix-shells/tidalcycles-shell.nix
{ 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:

shell:tangle ~/bin/sclang-wrapped:shebang #!/run/current-system/sw/bin/env
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...

emacs-lisp#+name: tidalcycles-emacs-config:tangle cce/tidalcycles.el
(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

emacs-lisp:tangle cce/tidalcycles.el
(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.

nix:tangle ~/nix/hm/supercollider.nix
{ pkgs, ... }:
{
   home.packages = [ pkgs.supercollider_scel ];
}
nix:tangle ~/nix/overrides/supercollider.nix
sclang = pkgs.supercollider_scel;

Installing SuperDirt

Run this in sclang or scide to install SuperDirt:

sclang
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'

sclang:tangle dirt-tidal-load.sclang:comments nil
(
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:

shell:tangle ~/bin/tidal-wrapped:shebang #!/run/current-system/sw/bin/env
[[ -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:

tidal
d1 $ sound "bd sd:1"

d2 $ sound "hh hh hh hh"

d3 $ sound "arpy"

hush