Skip to content

Rick Taube's Pattern Streams from Common Music v.2, but without the rest of Common Music.

Notifications You must be signed in to change notification settings

tanders/cm-patterns

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Common Music Patterns (cm-patterns)

This is Rick Taube’s Pattern Streams from Common Music v.2, but without the rest of Common Music. The code is based on the Patterns library by Anders Vinjar, who ported the Common Music to OpenMusic (OM Patterns library version 0.99.2).

References

Taube, H. (2004) Notes from the Metalevel. London and New York: Taylor & Francis.

Installation

The instructions below use git for the installation. Even though it is a bit more involved at first, it allows for convenient updates later, and you can even contribute to the development.

Install git (if you have not done already). Also, you should register at GitHub.

Download the present software with git into a directory where ASDF can find the software, e.g., ~/common-lisp/. For example, on UNIX incl. OS X you can enter the following commands at the command line (after you created the directory ~/common-lisp/). Note that $ is the terminal prompt here, you do not need to enter that :)

$ cd ~/common-lisp
$ git clone https://github.com/tanders/cm-patterns.git

You will be asked for your GitHub username and password.

Updating your software

You can update your software later at the terminal in the following way.

$ cd ~/common-lisp/cm-patterns
$ git pull

Usage Demonstrations

An introduction to algorithmic composition using patterns is chapter 20 in Rick’s book (Taube, 2004). Patterns are used everywhere in the book; is a nice intro. The code of the book is available online. See also the Common Music 2 reference documentation, in particular the section on patterns.

CM-patterns is an ASDF system (ASDF is the de facto standard for building Common Lisp software), and you can load it into your Lisp compiler as follows.

(require :cm-patterns)

To get started, here are a few examples. I am using CM-patterns from within another Lisp package (e.g., the Opusmodus package, :om), therefore I am adding the package prefix cm: before each CM-patterns symbol.

The cycle pattern repeats its elements in a cyclic fashion. The macro new initialises a pattern object, and the function next returns one or more pattern elements.

; define the pattern
(setf p (cm:new cm:cycle :of '(a b c)))

; retrieve the first pattern value
(cm:next p)
; => a

; retrieve the next pattern value
 (cm:next p)
; => b

; retrieve multiple pattern values
 (cm:next p 19)
; => (c a b c a b c a b c a b c a b c a b c)

; retrieve the all pattern values of one pattern period
(cm:next p T)
; => (a b c)

The plain cycle pattern can be used, e.g., to define the pitch sequence of an alberti bass.

(setf bass (cm:new cm:cycle :of '(c3 e3 g3 e3)))

(cm:next bass 16)
; => (c3 e3 g3 e3 c3 e3 g3 e3 c3 e3 g3 e3 c3 e3 g3 e3)

Common Music provides a number of pattern classes; the heap pattern returns a random permutation of its elements.

(setf q (cm:new cm:heap :of '(c4 d4 eb4 b3) :for 20))

(cm:next q T)
; => (d4 c4 eb4 b3 eb4 c4 b3 d4 b3 c4 eb4 d4 eb4 d4 c4 b3 eb4 d4 b3 c4)

Patterns can be nested. Here, the cycle pattern alternates between two sub-patterns.

(setf pat1
 (cm:new cm:cycle 
        :of (list (cm:new cm:heap :of '(c4 e4 g4))
                  (cm:new cm:heap :of '(gs4 as4 cs5)))))
(cm:next pat1 T)
; => (c4 g4 e4 as4 gs4 cs5)

Here, the outer pattern of the nesting is the weighting pattern, and the maximum number of repetitions of the sub-patterns is specified.

(setf pat1b 
      (cm:new cm:weighting
        :of `((,(cm:new cm:cycle :of '(a4 b4 c5 d5)) :max 2)
              (,(cm:new cm:heap :of '(gs4 as4 cs5 ds5)) :max 2))))
(cm:next pat1b 20)
; => (a4 b4 c5 d5 gs4 ds5 cs5 as4 as4 cs5 ds5 gs4 a4 b4 c5 d5 gs4 ds5 as4 cs5)

Another nested pattern example, but this time the length of the second sub-pattern is only 1, and so a single period of this sub-pattern is distributed over multiple periods of the outer pattern.

(setf pat2 
      (cm:new cm:cycle 
        :of (list 'c4 'd4 (cm:new cm:cycle :of '(gs4 as4 bs4) :for 1))))
(cm:next pat2 20)
; => (c4 d4 gs4 c4 d4 as4 c4 d4 bs4 c4 d4 gs4 c4 d4 as4 c4 d4 bs4 c4 d4)

In the next example, the length of a sub-pattern is controlled by another pattern.

(setf pat3 
       (cm:new cm:cycle 
         :of (list (cm:new cm:cycle :of '(c4))
                   (cm:new cm:cycle 
                     :of '(cs5 ds5 fs5)
                     :for (cm:new cm:cycle :of '(1 2 3))))))
(cm:next pat3 20)
; => (c4 cs5 c4 ds5 fs5 c4 cs5 ds5 fs5 c4 cs5 c4 ds5 fs5 c4 cs5 ds5 fs5 c4 cs5)

While Common Music processes are missing in this library, we can use loops instead of combine multiple patterns. Below, two patterns are combined by adding their values. These patterns have differing lengths.

(let ((p1 (cm:new cm:cycle :of '(60 62 64 65)))
      (p2 (cm:new cm:cycle :of '(0 2 4 6 8))))
  (loop repeat 20
    for x = (cm:next p1)
    for y = (cm:next p2)
    collect (+ x y)))
; => (60 64 68 71 68 62 66 69 66 70 64 67 64 68 72 65 62 66 70 73)

Another example of combining multiple patterns with a loop: a nested loop allows to have another form of nested patterns.

(let ((p1 (cm:new cm:cycle :of '(0 2 4 6 8)))
      (p2 (cm:new cm:cycle :of '(60 62 64 65))))
  (loop repeat 4
    for x = (cm:next p1)
    append (loop repeat 4
              for y = (cm:next p2)
              collect (+ x y))))
; => (60 62 64 65 62 64 66 67 64 66 68 69 66 68 70 71)

The last example defines a join pattern, which merges two or more parallel sub-patterns into lists.

(setf pat4 
      (cm:new cm:join :of 
        (list (cm:new cm:weighting :of '(c4 g4) :for 1)
              (cm:new cm:cycle :of '(q q e e)))))
(cm:next pat4 20)
; => ((c4 q) (c4 q) (c4 e) (g4 e) (g4 q) (c4 q) (g4 e) (g4 e) (g4 q) (g4 q) (c4 e) (c4 e) (g4 q) (c4 q) (g4 e) (g4 e) (g4 q) (c4 q) (c4 e) (g4 e))

For more detail see the Common Music book and documentation linked above.

Comparison with Common Music

This section lists changes to the original patterns in Common Music 2, introduced by the OM Patterns library. Anders Vinjar extracted the pattern stream functionality – arguably the most important contribution of Common Music to algorithmic composition in general – from an otherwise rather large and complex system. Common Music features beyond the actual patterns are missing, e.g., there are no CM processes.

Compared with the original Common Music heap pattern, this version supports an additional keyword. In the original version, direct repetitions could occur when crossing period-boundaries, as shown below.

(setf p (cm:new cm:heap :of '(0 1 2)))
(cm:next p 20)
; => (1 2 0 1 0 2 0 1 2 0 2 1 0 1 2 2 1 0 2 1)

This can now be prevented by setting the new keyword :elide-last? to T for this pattern.

(setf p (cm:new cm:heap :of '(0 1 2) :elide-last? T))
(cm:next p 20)
; => (1 2 0 1 0 2 0 1 2 0 2 1 0 1 2 0 1 2 0 1)

Otherwise, all of Rick’s various pattern classes from Common Music are included, except for a few that depend on other Common Music functionality, namely the data parsing features of the original versions with pattern keywords like keynum, transposer, and chord.

Also, as the resulting code was only meant for OpenMusic, some code ensuring compatibility with various Lisp compilers was removed.

Changes Compared With the OM Patterns Library

I (Torsten) turned this library in an ASDF system for easy installation, removed all code that depends on OpenMusic, and changed the code slightly so that it compiles and runs on Clozure CL (e.g., make sure the MOP symbols from the correct package are called).

Platform Support

This code has been tried with Clozure CL (under Opusmodus), LispWorks and SBCL. However, the code is still not as portable as the original Common Music source.

If you want to get the present library running on another CL compiler, then that is likely easy to do. All platform-specific code is in ./sources/make-package.lisp, which imports implementation-specific MOP details, as provided in the Common Music v2 sources, into the Common Music package. For example, for OpenMCL (including Clozure CL) all that is necessary is the following.

#+openmcl
(progn 
  (import '(ccl:class-slots
            ccl:slot-definition-initargs
            ccl:slot-definition-initform
            ccl:slot-definition-name
            ccl:class-direct-superclasses
            ccl:class-direct-subclasses
            ccl:class-direct-slots
            ccl:validate-superclass
            ccl:without-interrupts)
          :cm)
  (defun finalize-class (class) class t))

There is a good chance that there is a file for your – so far unsupported – compiler in the Common Music source tree. Take that file, and search in it for the above symbols and definitions to include. If you get this code working on another platform then let us know (e.g., via a GitHub issue).

About

Rick Taube's Pattern Streams from Common Music v.2, but without the rest of Common Music.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published