LFE Music Programming with undertone






by Duncan McGreggor











publisher logo

Published by Cowboys 'N' Beans Books

https://github.com/cnbbookshttp://cnbb.pub/info@cnbb.pub




First electronic edition published: 2020




© 2020, Duncan McGreggor

This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License

Creative Commons License




Cover art: Book covers for the 1.x series of LFE vertsions were inspired by the 1968 DEC FOCAL Programming Manual with stylised PDP-8 as the dominant cover graphic. For the LFE 2.x series, a new cover was designed along the same lines but using a PDP-11 as the basis.

Introduction

TBD

LFE and Erlang

Music Programming

MIDI

Audio Processing

Open Sound Control

Extempore

The undertone REPL

Programming Basics

The undertone Architecture

Quick Start

To try out undertone, you can just clone the project itself:

$ git clone git@github.com:lfex/undertone.git
$ cd undertone

and then start up the REPL:

$ rebar3 repl

Note that this does require that you have a modern Erlang installed (version 21 or above) as well as rebar3, the famous build and dependency management tool in the BEAM ecosystem.

Extempore

Tested against extempore version 0.8.7.

Download the latest Extempore from the project releases page on Github.

Assuming you've started extempore and have the LFE REPL running, as previously described, you will have been automatically connected to the Extempore TCP server. As such, you're ready to start living coding!

There are several ways to do this from LFE:

  1. From an LFE-managed REPL supporting native Extempore syntax,
  2. From an LFE-managed REPL with hybrid Extempore and LFE support, and
  3. From LFE itself (limited Extempore support)

The Extempore REPL

At the LFE prompt, start up the Extempore REPL:

lfe> (undertone.repl.extempore:start)
extempore> 

Once at the extempore> prompt, you will be able to enter native Extempore expressions (Scheme and xtlang). These will be passed to the Extempore TCP server as-is (executed asynchronously and non-blocking).

Additionally, you may call other supported functions. To see the list of supported REPL function, type (help):

extempore> (help)
The Extempore undertone REPL

Built-in functions:

(call body) -- make an explicitly blocking call to Extempore, with 'body' being
               a valid Extempore expression
(check-xt)  -- check on the status of Extempore (no response indicates a health
               problem, possibly requiring a restart of the 'extempore' binary)
(eom)       -- alias for '(term)'
(exit)      -- alias for '(quit)'
(h)         -- alias for '(help)'
(help)      -- display this information
(quit)      -- quit the Extempore REPL and return to the LFE REPL
(run file)  -- load the code in the given file and run in Extempore
(term)      -- send message-terminating character sequence to force Extempore
               end-of-message (useful when troubleshooting)
(version)   -- display all the version info for undertone

Extempore support:

All S-expressions other than the ones listed above will be treated as Extempore
Scheme / xtlang code and sent to the Extempore TCP server (compiler service) as
an asynchronous call (no result, no output printed). If you would like to block
on particular calls and see their return values, be sure to use the '(call ...)'
REPL function.

Most (if not all) of the official Extempore examples should work without modification in this REPL.

The Undertone REPL

TBD

Native LFE

Note that only a limited number of Exempore forms are supported from within LFE right now.

Load the appropriate Extempore files into the server and the LFE macros into the current REPL session:

(xt:sys-load "examples/sharedsystem/setup.xtm")
(include-lib "undertone/include/xt-patterns.lfe")

Play an ascending scale using the second synthesizer that comes with Extempore:

(/> 'ascending-scale 4 0 (play 'syn2 '@1 80 'dur) (scale 4 8))

Note that the Extempore syntax for this is :>, a character combination not supported in LFE symbols, so /> was settled upon instead. Similarly, below you will see // used in LFE as an analog for the :| used in Extempore.

Then change the tempo:

(set-tempo! 72)

You can stop the synth in two ways -- changing 'play' form to the 'stop' form while keeping the remaining body the same (this is useful for live coding scenarios):

(// 'ascending-scale 4 0 (play 'syn2 '@1 80 'dur) (scale 4 8))

or by calling the 'stop' form using just the pattern name you defined in the 'play' form:

(// 'ascending-scale)

OSC

The Erlang Server

Tested against erlsci/osc 2.0 and 2.1.

lfe> (set c (undertone.osc.client:connect "localhost" 2357))
; ok#(client #Pid<0.276.0> #Pid<0.277.0>)
lfe> (undertone.osc.client:echo c)
; ok

If you view the output of the running Erlang OSC server, you should see some debug output logged:

=INFO REPORT==== 27-Nov-2020::16:14:05.986773 ===
Received message: []

You can also check passed arguements:

lfe> (undertone.osc.client:echo c '(a list of args))
ok
=INFO REPORT==== 27-Nov-2020::16:35:28.652299 ===
Received message: [a,list,'of',args]

SuperCollider

Tested against SuperCollider 3.11.2.

Connecting

Start up the SuperCollider GUI / IDE, then in the editor enter the following:

s.options.maxLogins = 8;
s.reboot;
Server.default.options.asOptionsString

The last line will help you confirm the current settings, showing what they would be if you'd started scsynth manually. In particular, you want to confirm that you see -l 8.

Then, in a terminal at the LFE REPL:

lfe> (set c (sc.client:connect "localhost" 57110))
;#(client #Pid<0.344.0> #Pid<0.345.0>)

Once the client is set up, do a quick check to see that you are connected to the right server / version and that there are synthesizer definitions loaded:

lfe> (sc.client:version c)
;(#(version "3.11.2") #(branch "HEAD") #(commit-id "9a34118e"))

lfe> (sc.client:status c)
;(#(unit-generators 0)
; #(synths 0)
; #(gruops 9)
; #(loaded-synth-definitions 106)
; #(cpu-average-usage 0.030904095619916916)
; #(cpu-peak-usage 0.2695612609386444)
; #(nominal-sample-rate 4.41e4)
; #(actual-sample-rate 44099.98856935304))

Playing Sounds

First create a handful of instances of the default synth and then stop them, until we're ready:

lfe> (set synth-ids '(1000 1001 1002 1003 1004))
;"ϨϩϪϫϬ"
lfe> (set (list s0 s1 s2 s3 s4) (list-comp
       ((<- id synth-ids))
       (sc.client:create-synth c id)))
;"ϨϩϪϫϬ"
lfe> (list-comp ((<- id synth-ids)) (sc.client:stop-node c id))
;(ok ok ok ok ok)

Instead of a boring C chord, let's take some notes from the C scale's Locrian mode using B, E, F, A, and B (a combination rarely heard!):

lfe> (include-lib "include/notes.lfe")
;|-- loaded include: notes --|
lfe> (sc.client:set-node c s0 `("freq" ,(B3) out 0))
;ok
lfe> (sc.client:set-node c s1 `("freq" ,(E3) out 1))
;ok
lfe> (sc.client:set-node c s2 `("freq" ,(F3) out 0))
;ok
lfe> (sc.client:set-node c s3 `("freq" ,(A3) out 0))
;ok
lfe> (sc.client:set-node c s4 `("freq" ,(B4) out 1))
;ok

Now play them all:

lfe> (list-comp ((<- id synth-ids)) (sc.client:start-node c id))
;(ok ok ok ok ok)

For the MIDI-minded, in addition to the notes.lfe include, there is a midi-notes.lfe file with functions defined for getting notes by MIDI number.

And then, when you're done listening to that beautiful dissonance:

lfe> (list-comp ((<- id synth-ids)) (sc.client:stop-node c id))
;(ok ok ok ok ok)

Ardour

Tested with versions 5 and 6 of Ardour.

lfe> (set c (ardour.client:connect "localhost" 3819))
;#(client #Pid<0.281.0> #Pid<0.282.0>)
lfe> (ardour.client:strip-list c)
;(#(name "SynthMaster One")
; #(strip-number 1)
; #(type "MIDI track")
; #(inputs 0)
; #(outputs 2)
; #(muted? 0)
; #(soloed? 0)
; #(record-enabled? 0))

The undertone Guide

Getting Set Up

Programming Environments

Creating an undertone Project

The DSL

The Default Synth

Audio Processing

Audio Files

Creating Instruments

Samplers

Working with MIDI

Creating Music

Music Theory

The Virtual Studio

MIDI on the Mac

Controlling a DAW

Creating a Custom OSC Server

Epilogue

Versions

Current

You're looking at it.

There are currently no previous versions of the book.

Feedback and Docs or Project Bugs

If you would like to provide feedback about this guide, we would welcome the chance to improve the experience for everyone. Please create a ticket in the Github issue tracker.

If you would like to provide feedback about undertone, you make create a ticket in the project issue tracker.

In either case, be sure to give a full description so that we can best help you!