This is a writeup for my mobile setup for Emacs music composition - but iOS being iOS, this does require access to a Linux machine for most of the heavy lifting, with something like Blink on the phone as a thin client.

Previously: funktor + PulseAudio streaming

Song composition in Emacs in Blink on iOS

For a while now I’ve wanted a fully mobile programmatic music generation solution. I’d previously set this up using my own Haskell library funktor, which is an interpretive layer on top of csound-expression allowing terse music creation in a Haskell DSL.

I’d use Blink on iOS to connect to Emacs-in-tmux running on my VPS, with ghcid watching for changes, constantly reloading my track when saving the file. To stream audio, I’d transcode the VPS’s PulseAudio output on-the-fly, expose it to the internet, and connect to it using the iOS VLC app in the background. This gives about a second of latency.

For posterity, I’m streaming Pulse via:

cvlc -vvv pulse://$(pactl list | grep "Monitor Source" | awk '{print $3}') \
    --sout '#transcode{acodec=mp3,ab=128,channels=2}:standard{access=http,dst=}'

Moving to TidalCycles

I recently realised I had more or less made a TidalCycles lookalike with this setup. I’d wanted to try out Tidal for a while, and given its extreme terseness and focus on transience and experimentation rather than song composition, I figured it’d be an even better fit for the mobile interaction use-case.

I followed the Linux Installation instructions on my VPS, installing the Emacs Tidal package and getting to the point where I could get Supercollider/Superdirt/Tidal-in-Emacs talking.

Streaming JACK over the Network

The sticking point for me was that as I understand it, starting SuperDirt also suspends PulseAudio - the Tidal stack uses JACK instead. Thankfully, it was relatively straightforward to stream SuperCollider’s JACK output over the network via VLC:

$ cvlc -vvv "jack://channels=2:ports=.*out_1,.*out_2" \
    --sout '#transcode{acodec=mp3,ab=128,channels=2}:standard{access=http,dst=}'

With this running (and SuperDirt running in the background), one can open a .tidal file in Emacs, C-c C-s to bring up Tidal, and play around with very little latency.

We need to open SuperDirt first before streaming JACK, otherwise we end up with a race for port 57120.

The end result looks something like:

TidalCycles in Emacs in Blink on iOS