Rhythmic Pattern Tutorial

This extension shows a method for rhythm generations.


Author Name: Roger B. Dannenberg;
Author Email: rbd@cs.cmu.edu;

Additional File: rhythm.sal;

Usage:

In SAL mode:
load "rhythm/rhythm.sal"
exec rhythm-all()

Description

This example illustrates a very simple percussion sound created with noise and using the sound to generate a rhythm.

The sound is created by filtering noise. The filter is controlled using the piece-wise linear function pwl. Examples here are in SAL syntax followed by Lisp syntax in small print:

function pulse(dur)
  return hp(noise(),
            pwl(0, 15, 0.2, 6000, 0.6, 15000, 0.75, 7)) ~ dur
(defun pulse (dur)
  (stretch dur (hp (noise) (pwl 0 15 0.2 6000 0.6 15000 0.75 7))))

A sequence of sounds is constructed and repeated in the following code. Notice that each time through the pattern, the scale factor is increased by 0.1, giving the whole sequence a crescendo:

function pulsepat(rep) 
  return seqrep(i, rep, i * 0.1 *
                seq(pulse(1), pulse(1), pulse(2), pulse(2))) ~ 0.2

play pulsepat(17)

(defun pulsepat (rep) (seqrep (i rep) (stretch 0.2 (scale (* i 0.1) (seq (pulse 1) (pulse 1) (pulse 2) (pulse 2)))))) (play (pulsepat 17))

Pitched Patterns

This example uses the electrobass function. With the right pitch parameter, we hear a kind of electronic bass sound. Try this:

play electrobass(0.4, 30, 1.2)
(play (electrobass 0.4 30 1.2))

These notes can be combined to create a pattern. The techno function creates a short pattern of 3 notes repeated any number of times:

function techno(rep)
  return seqrep(i, rep, 0.8 *
                sim(0.8 * electrobass(0.4, 30, 1.2) @ 0,
                    0.6 * electrobass(0.2, 30, 0.9) @ 0.2,
	            0.7 * electrobass(0.1, 30, 1.1) @ 0.3))

(defun techno (rep) (seqrep (i rep) (scale 0.8 (sim (scale 0.8 (at 0.0 (electrobass 0.4 30 1.2))) (scale 0.6 (at 0.2 (electrobass 0.2 30 0.9))) (scale 0.7 (at 0.3 (electrobass 0.1 30 1.1))) ))))

Try this:

play techno(3)
(play (techno 3))
The following combines and transposes rhythmic segments to create a bass line:
play seqrep(i, 2, seq(techno(2),
                      transpose(5, techno(2)),
                      transpose(-2, techno(1)),
                      transpose(3, techno(1)),
                      techno(2)))
(play (seqrep (i 2)
        (seq (techno 2)
             (transpose 5 (techno 2))
             (transpose -2 (techno 1))
             (transpose 3 (techno 1))
(techno 2))))

Layers for Richer Texture

Sounds can often be combined with time and pitch offsets to create richer textures. The following layers two sequences are based on the same techno function:

play sim(0.4 * seqrep(i, 2,
                      seq(techno(2),
                          transpose(5, techno(2)),
                          transpose(-2, techno(1)),
                          transpose(3, techno(1)),
                          techno(2))) @ 0,
         0.2 * seqrep(i, 2,
                      seq(transpose(2, techno 2))
                          transpose(7, techno(2))
                          transpose(-4, techno(1))
                          transpose(5, techno(1))
                          transpose(-2, techno(2)))) @ 0.1)
(play (sim
        (scale 0.4
          (at 0.0
            (seqrep (i 2)
              (seq (techno 2)
                   (transpose 5 (techno 2))
                   (transpose -2 (techno 1))
                   (transpose 3 (techno 1))
                   (techno 2)))))
	(scale 0.2
          (at 0.1
            (seqrep (i 2)
              (seq (transpose 2 (techno 2))
                   (transpose 7 (techno 2))
                   (transpose -4 (techno 1))
                   (transpose 5 (techno 1))
                   (transpose -2 (techno 2)))) ))))

Note that the second layer is almost but not exactly a transposition of the first layer. If it were an exact transposition, it would make sense to encapsulate the first layer in a function and call it twice. The following variation is much more concise, but it does not compute exactly the same sound:

function bass-line()
  return seqrep(i, 2,
seq(techno(2), transpose(5, techno(2)), transpose(-2, techno(1)), transpose(3, techno(1)), techno(2)) play sim(0.4 * bass-line(), 0.2 * transpose(2, bass-line()) @ 0.1)
(defun bass-line ()
  (seqrep (i 2)
    (seq (techno 2)
         (transpose 5 (techno 2))
         (transpose -2 (techno 1))
         (transpose 3 (techno 1))
         (techno 2))))
(play (sim (scale 0.4 (bass-line))
           (scale 0.2 
             (at 0.1 (transpose 2 (bass-line))))))

Another Example

This example also uses the electrobass function.

play seqrep(i, 17, 
            lp((i * 0.05 + 0.3) * 
               seq(transpose(-4, electrobass(0.1, 32, 0.6)), 
                   transpose(-5, electrobass(0.05, 20, 0.2)),
                   transpose(2 * i, electrobass(0.1, 27, 0.5)), 
                   transpose(-3, electrobass(0.05, 22, 0.1)), 
                   transpose(i * 3, electrobass(0.1, 28, 0.4)), 
                   electrobass(0.05, 31, 0.7)),
               100 * i))

(play (seqrep (i 17) 
        (lp (scale (+ (* i 0.05 ) 0.3) 
              (seq (transpose -4 (electrobass 0.1 32 0.6)) 
                   (transpose -5 (electrobass 0.05 20 0.2)) 
                   (transpose i (electrobass 0.1 27 0.5)) 
                   (transpose -3 (electrobass 0.05 22 0.1)) 
                   (transpose i (electrobass 0.1 28 0.4)) 
                   (electrobass 0.05 31 0.7)))
            (* 100 i))))

This play 17 repetitions of a sound. Each time, the sound is a bit louder, the low-pass frequency is raised by 300 Hz, and two of the transpositions are increased. This creates a rhythmic and evolving sound.