CCRMA

Common Music Patterns, Random Processes


Abstractions

Using functions to create meta-instruments...

Using functions as envelope generators...

Common Music Patterns

Introduction to Common Music Patterns. See the Common Music Manual for version 2.4.0. Look at the Common Music dictionary for detailed definition of all the Common Music functions and macros.

Pattern Classes

During the class we took a look at the simplest classes or types of patterns. Each class of patterns has a different behavior in how elements are selected:

cycle
circular selection of elements in the pattern
line
go from first to last, repeat last
palindrome
first to last and back
heap
random selection without replacement
random
random selection with replacement

Patterns are objects created with the "new" macro. The following line stores a cyclic pattern (cyclic patterns are the default type of pattern) that contains five elements in the global variable "pat":

  (setf pat (new cycle :of '(1 2 3 4 5)))

We can access elements through the "next" function, which can either return one element at a time or a whole period of selected elements:

  (next pat)
  1
  (next pat)
  2

or if we want a whole "period" returned in a list we add an optional argument with the value ":chunk":

  (next pat :chunk)
  (1 2 3 4 5)

by default the period of a pattern is equal to the number of elements it contains. We can create a specific kind of pattern by naming its type when creating it:

  (setf pat (new cycle :of '(1 2 3 4 5)))
  (setf pat (new random :of '(1 2 3 4 5)))

Patterns can be nested to arbitrary depths, the following pattern contains a random sub-pattern as element four:

  (setf pat (new cycle :of (list 1 2 3 (new random :of '(10 20 30)) 5)))
  (next pat :chunk)
  (1 2 3 10 30 20 5)

Note that the included pattern completes its own period before returning control to the enclosing pattern. This behavior can be changed by altering the default period of the pattern using the for keyword:

  (setf pat (new cycle :of (list 1 2 3 (new random :of '(10 20 30) :for 1) 5)))
  (next pat :chunk)
  (1 2 3 10 5)
  (next pat :chunk)
  (1 2 3 30 5)

The period itself could be a pattern!:

  (setf pat (new cycle :of (list 1 2 3 (new random :of '(10 20 30) :for (new heap :of '(1 2))) 5)))
  (next pat :chunk)
  (1 2 3 20 10 5)
  (next pat :chunk)
  (1 2 3 10 5)

If you want to supply a prebuilt list of elements to the new macro just use the of keyword followed by a list of elements:

  (setf elements '(1 2 3 4))
  (setf pat (new heap :of elements :for 3))

Here is a link to the examples I played in class. I have added comments and some url's to the file so that the progression of examples make more sense

Some tools included in Common Music

There are some interesting functions that let you translate between different representation of musically interesting magnitudes (pitch/frequency, tempo/seconds, loudness/amplitude).

note
translates to note names from note names or key numbers
keynum
translates to key numbers from note names or frequencies
hertz
translates to frequencies either note numbers or key numbers
rhythm
translates rhythmic values to time in seconds
amplitude
translates amplitude values to amplitude (between 0 and 1)

"Hertz" is particularly interesting for controlling CLM instruments as most of them can only deal with frequency and not the most common note numbers or key numbers that represent the popular twelve tone tempered scale (Common Music can also work with other scales...). For example, we could be controlling our fm-violin using a heap pattern of note numbers that we translate into frequencies:

(with-sound()
  (let* ((notes (new heap :of '(64 66 68 61 60))))
    (loop
      for time from 0 by 0.1 repeat 10 do
      (fm-violin time 0.1 (hertz (next notes)) 0.1))))

Functions also exist that deal with rhythmic time and logical amplitudes


Probability distributions

Probability is the likehood of occurrence of a given event, ratio of number of occurrences of that event to the total number of results of the random process. A probability distribution is a table that shows the likehood of occurrence of one of more events, where the probability of occurrence of a given event is expressed as a value between 0 and 1.

[continuous vs discrete distributions]

Random numbers... as normally generated in a computer are not really really random. They are the result of executing an algorithm, the output values can be considered statistically random if the algorithm is good enough. Normally the random number generator is seeded by a number, after that the numbers generated are predictable (each time we seed the generator with the same number it produces the same sequence of "random" numbers).

In common lisp we can generate random floating point values using the (random xxx) function, where xxx is a floating point number. If we need integers (for example to generate midi note numbers) then the argument to random should be an integer.

[Distributions: uniform, linear, triangular, exponential...]

The example file probability.lisp has some examples of probability distributions (Note: you'll have to first compile and load plot.lisp to be able to plot the distributions)

See some useful functions in Common Music: drunk, between,

State Machines

[a definition]

A state machine remembers a "state" (a memory of where it is in its internal process) and depending on whar state it is in, it calculates outputs that are determined by the current inputs and then transitions to a different (or the same) state. We could specify a state machine by a connected graph. States are represented by circles. Directed arrows specify the transitions between states. Each transition is determined by the "current state" (that is, the circle it originates in) and by the input conditions. As a side effect of the state transition the state machine defines new output values.

[Mealy: transition -> output; Moore: state -> output]

A very simple state machine could be defined by the following lisp code:

(defparameter h-state t)

(defun harmonize (input)
  (if h-state
      ;; up by a fifth
      (progn
	(setf h-state nil)
	(+ input 7))
    ;; up by a fourth
    (progn
      (setf h-state t)
      (+ input 5))))

h-state is a global variable that remembers the current state of the state machine. It can have two values, t or nil (ie: this state machine has only two state). The function definition is simple, depending on h-state is executes two branches of code, each one calculates and returns an output value based on the input to the state machine and the current state. It then transitions to the other state.

(with-sound()
  (loop
    repeat 10
    for time from 0 by 0.2
    for note = 60 then (harmonize note)
    do
    (fm-violin time 0.16 (hertz (if (> note 128) 128 note)) 0.1)))

See statemachine.lisp for ready to run examples...

Each state within the state machine has to define what to do with the outputs and how to transition to the next state. So far we have only seen a completely deterministic behavior in our state machine.

What if some of the decisions were taken by stochastic (random) processes? The output of our state machine is no longer completely predictable. Those stochastic decisions could influence the transition between states of the generation of outputs from the current inputs to the state machine.

  • State Machines
    • Deterministic
    • Stochastic

[Markov chains: probability for transitions between states]

see the class lisp transcript for examples on how to define and use markov chains in our Lisp environment


©1998, 2001-2003 Fernando Lopez-Lezcano. All Rights Reserved.
nando@ccrma.stanford.edu