cl-patterns
2024-10-12
Pattern library for algorithmic music composition and performance in Common Lisp
A library for writing patterns to generate or process (a)musical sequences of mathematically (un)related (non-)compound values in Lisp.
Put more simply, cl-patterns is a system for making music and noise via Lisp code.
It is heavily inspired by SuperCollider's patterns system, with aims to implement much of it, but in a more robust, expressive, consistent, reflective, and lispy way:
- robust: prefer coercing values into something "correct" rather than failing or giving an error. if you're "in the zone" and writing music, you probably want your compositional tools to "do what you mean" and allow you to take as many sensible shortcuts as possible, rather than forcing you to waste time manually declaring and setting up everything.
- expressive: make writing music as easy and "natural" as possible, so that patterns can be built in real-time, in performance settings, without having to think so hard about how to bend the library to your will. I feel this is a weakness of SuperCollider.
- consistent: edge cases minimized, arguments for the various functions in an intuitive order, thus resulting in less cognitive load for the user.
- reflective: store more data about the stream state and more metadata about the patterns. make it easier for a pattern to access the values of another pattern, for patterns to affect other patterns, etc.
- lispy: prefer lisp idioms rather than direct translations of the SuperCollider way of doing things (while still keeping things relatively similar so it's not a huge adjustment for SC users to make).
In addition to emulating most of SuperCollider's patterns system, another goal is to further extend it with more tools and more ways to write patterns/sequences. The most obvious example being a "drum sequence" notation like k - - - k - - - k - - - k - - -
for a four-to-the-floor beat. The idea is that Lisp's macros should make it possible to more expressively write music with code.
1Intro
Make sure you have Quicklisp installed and working with your Lisp implementation, then load cl-patterns:
(ql:quickload 'cl-patterns)
(use-package 'cl-patterns)
Create a pattern like so:
(defparameter *pat* (pbind :foo (pseq '(1 2 3))
:bar (prand '(9 8 7) 5)))
Since patterns are basically "templates", you need to turn them into pstream
objects in order to actually get output from them:
(defparameter *pstream* (as-pstream *pat*))
Then, you can get results from the pstream one at a time with next
, or many at a time with next-n
or next-upto-n
:
(next-n *pstream* 3)
;; => ((EVENT :FOO 1 :BAR 8) (EVENT :FOO 2 :BAR 9) (EVENT :FOO 3 :BAR 8))
To actually hear sound output, you'll need to start an audio server. Right now, SuperCollider is the main audio server that cl-patterns is tested against, but there is also preliminary support for Incudine as well as MIDI output through ALSA.
To use the SuperCollider backend, simply load the cl-patterns/supercollider
system with quicklisp. This will automatically take care of loading the required cl-collider library for you:
(ql:quickload :cl-patterns/supercollider)
From here, you can take a look at the code in the supercollider-example.lisp file for a short example of how to define your own synths and play them with patterns. You may also be interested in my cl-collider tutorial for a more in-depth introduction to cl-collider.
For more information on how to use cl-patterns, refer to tutorial.org for an introduction.
You can get a list of all defined patterns using (all-patterns)
. Every pattern should have usage information and examples in its docstring, which of course can be accessed using the standand describe
or documentation
functions.
2Features
This library isn't just a copy of SuperCollider's patterns - I wanted to improve upon them as well. For a list of notable features in cl-patterns, see features.org.
If you're familiar with SuperCollider, you may also want to look at sc-differences.org for a listing of differences between this library and SC's patterns, or sc.org for a listing of patterns in SuperCollider and their equivalent (and implementation status) in cl-patterns.
2.1Emacs "Helper Functions"
Included in res/emacs/ are a few small libraries that make it more convenient to work with cl-patterns and the synthesis engines it supports from inside Emacs. Their functionality includes:
- commands for playing/stopping the pattern, buffer, proxy, or other object under point
- command to stop all playing patterns, nodes, etc.
- command to open the SuperCollider documentation for a specified class (with completion)
- skeletons for commonly-used patterns/functions
- and a few other utility functions.
Here's the recommended setup to load these libraries automatically via your Emacs init file:
(defun cl-patterns-helpers-load ()
(interactive)
(sly-eval-async '(cl:let ((system (asdf:find-system "cl-patterns" nil)))
(cl:when system (cl:namestring (asdf:system-source-directory system))))
(lambda (path)
(load (concat path "res/emacs/cl-patterns-helpers") nil nil nil t)
(load (concat path "res/emacs/cl-patterns-skeletons") nil nil nil t)))
(define-key sly-mode-map (kbd "C-c p") 'cl-patterns-play-or-end-context-or-select-pdef)
(define-key sly-mode-map (kbd "C-c P") 'cl-patterns-play-or-stop-context-or-select-pdef)
(define-key sly-mode-map (kbd "C-c s") 'cl-patterns-stop-all)
(define-key sly-doc-map (kbd "s") 'cl-patterns-supercollider-documentation))
(add-hook 'sly-connected-hook 'cl-patterns-helpers-load)
The above should also work with slime; just replace all instances of "sly" with "slime".
3Status
Right now, the library may be described as being in a "late alpha" stage, as fewer and fewer major changes are still being made. Most of the included patterns and exported functionality now have relatively stable APIs as well as tests to guard against regressions. There may still be the occasional change of functionality in the library, though most user-facing changes will be gracefully deprecated and documented in commit messages, so check those if you have any issues after updating.
Despite that, lots of functionality is already written and the library should be stable enough for normal usage in most cases.
Many tests have already been written to help guard against regressions.
Much documentation is still being written, but there is already a good amount of information in the doc directory, and in the docstrings for the patterns, functions, etc.
See TODO.org and roadmap.org for a listing of tasks that need to be completed and ideas for future features. The code itself is also littered with comments marked "FIX" noting various known issues and possible changes and optimizations that could be made.
3.1Backends
The SuperCollider backend is the primary backend that cl-patterns is tested against so it should generally work the best and should be usable for most purposes.
The Incudine backend should work for most purposes, though currently multichannel expansion does not work.
The ALSA MIDI backend has some functionality complete and should be usable for basic tasks, but is still very much a work in progress.
4Tour
- README.org - this file. self-expanatory, I'd hope.
- LICENSE - the MIT license.
- cl-patterns.asd - cl-patterns systems definition file.
4.1doc
- backends.org - information about cl-patterns backends, including how to write your own.
- cookbook.org - a cookbook of ideas and inspiration for your cl-patterns hacking.
- features.org - listing of notable features of cl-patterns.
- isobar.org - list of patterns in isobar and their equivalents in cl-patterns.
- other-libraries.org - listing of other libraries that have similar goals or may be useful in conjunction with cl-patterns.
- patterns.org - organized index of the pattern classes included in cl-patterns.
- roadmap.org - general overview of major goals for the future development of cl-patterns.
- sc.org - a list of pattern classes and special keys in SuperCollider and their cl-patterns implementation status.
- sc-differences.org - listing of things that differ between cl-patterns and SuperCollider.
- special-keys.org - description of keys that have special effects when used in an event or pbind.
- supercollider-example.lisp - short example of how to use cl-patterns with cl-collider.
- TODO.org - a list of things and ideas that have not yet been implemented into cl-patterns, but may be in the future.
- tutorial.org - explanation of the basic concepts of cl-patterns, meant for people who have never used SuperCollider's patterns.
- writing-your-own.org - information about how to write your own pattern classes.
4.2res
4.2.1emacs
- cl-patterns-helpers.el - Helper functions to make cl-patterns more convenient to use from Emacs (see above).
- cl-patterns-skeletons.el - Emacs skeletons (templates) for quickly inserting commonly-used lisp forms.
4.3src
- package.lisp - the package definition file.
- utility.lisp - general utility functions and special variable definitions.
- conversions.lisp - functions to convert between units (i.e. midinote to frequency, decibels to amplitude, etc.).
- scales.lisp - musical pitch (scales/tuning) data and structs.
- event.lisp - code to represent and deal with events. includes the
event
class, information about special keys (i.e.freq
,amp
...), etc. - eseq.lisp - event sequence class and functionality.
- backend.lisp - code to handle "backends"; i.e. how cl-patterns will actually "play" events.
- render.lisp - generic functionality for rendering patterns.
- clock.lisp - the scheduling functionality to make sure that each event is played at the proper time.
4.3.1patterns
- patterns.lisp - general pattern macros and functionality + the standard set of patterns; includes the
pattern
superclass,pbind
,pseq
,pk
, etc. - pdef.lisp -
pdef
and associated functionality to define and reference "named patterns". - pmeta.lisp -
pmeta
; meta-pattern for embedding and controlling other patterns. - bjorklund.lisp - Euclidean pattern functionality such as
pbjorklund
, etc. - cycles.lisp - TidalCycles-inspired patterns and notation, i.e.
pcycles
, etc. - track.lisp - tracker-inspired patterns and notation, i.e.
ptrack
and associated functions, macros, reader macros, etc. - sc-compatibility.lisp - patterns intended to be fully compatible with SuperCollider's patterns system.
- export.lisp - export all defined patterns in the
*patterns*
list.
4.3.2backends
- supercollider.lisp - code to interface cl-patterns with SuperCollider via the cl-collider library.
- incudine.lisp - code to interface cl-patterns with Incudine.
- debug.lisp - basic debug backend. responds to all events, printing and storing them without any audio output.
- alsa-midi.lisp - code to interface cl-patterns with cl-alsaseq.
4.3.3formats
- midifile.lisp - functionality to interact with MIDI files (load the
cl-patterns/midifile
system to use this). - supercollider-score.lisp - functionality to interact with SuperCollider Score files.
4.3.4extensions
- generic-cl.lisp - additional methods for generic-cl. enable by loading the
cl-patterns/generic-cl
subsystem. - sequence.lisp - additional methods for implementations that support extensible sequences.
- swank.lisp - creature comforts for slime/swank users.
- slynk.lisp - creature comforts for sly/slynk users.
4.4t
contains the files for the FiveAM-based test suite for the library.
5Community
If you need support or just want to chat, the official cl-patterns chatroom is on Matrix at #cl-patterns:struct.ws, and bridged to IRC at #cl-patterns on irc.libera.chat.
Any bugs, feature requests, suggestions, etc should be submitted to the GitHub issue tracker. Please feel free to submit issues even if they might already be known as it helps to figure out which parts of the library to prioritize development on. It's also nice to know that people are using the library. :)