"Second Law" — Intra-phrasal looping
+ Associated files
- The slippery-chicken file from this example
- The MIDI output generated by this file
- The PDF score produced with this file's LilyPond output
- The CMN EPS output generated by this file
- An MP3 of the piece using instrument samples
NB: An exercise relating to the material covered in this tutorial can be found on the Exercises page.
This document assumes that you having familiarized yourself with the
core usage of slippery chicken.
It provides an introduction to generating some of the material
for slippery chicken algorithmically, using
the chop
method and the fibonacci-transitions
function to create intra-phrasal looping, in addition to
integrating separate Lisp routines.
Intra-phrasal looping is a compositional process made possible by slippery chicken and is a technique that demonstrates the strengths of using slippery chicken as a compositional tool. It allows the user to produce an entire, motivically coherent and structurally sound composition from a small amount of source material and a few concisely defined processes, even automatically incorporating musical elements such as orchestration and larger-scale structure.
+ The code
The code is first presented on its own here, then explained point by point below.
NB: It is strongly recommended that the user not copy and paste code from the web browser into the Lisp listener, as this can occasionally lead to errors. The code below can be downloaded in complete form under the Associated files section above.
(let* ((sl-rsp-orig ; defining the source material (make-rsp 'sl-rsp '((1 ;; A backslash (\) must be used as an escape character when ;; indicating a tie to the previous note using a + symbol before a ;; numerically represented rhythmic value (as opposed to a letter, ;; such as 's or 'e). (This is because Lisp will otherwise read ;; "+32" as "positive 32".) ((((4 4) - (e.) s - - \+32 32 32 32 (e) - - 32 32 (s) 32 32 32 (32) - - (s) s s (s) - ) (- (e..) 32 - +q q (q)) (h. (q))) :pitch-seq-palette ((1 2 1 2 3 2 3 3 1 2 5 5 7 6) (2 1 2 1 2 3 2 2 4 3 2 2 1 2) (5 3 4 5 4 5 4 5 2 3 6 6 8 7)) :marks (a 1 s 1 slur 3 5 a 6 slur 6 7 slur 8 10 a 11 s 11 12 a 13)))))) ;; fragmenting the source material (sl-rsp-chopped (chop sl-rsp-orig '((1 2) (1 1) (2 2)) ; chop points 'e)) ; chopping unit ;; setting the measure structure (num-seqs-list '(53 61 97 79 89 73))) ;; adjusting the instrument attributes (loop for i in '((flute 13) (oboe 7) (b-flat-clarinet 9) (bassoon 7) (french-horn 5) (b-flat-trumpet 7) (tenor-trombone 5) (double-bass 5)) do (set-slot 'largest-fast-leap (second i) (first i) +slippery-chicken-standard-instrument-palette+)) ;; This function prints the results of the chop method in easy-to-read form ;; (print-simple sl-rsp-chopped) ;; calling slippery-chicken (make-slippery-chicken '+second-law+ :title "Second Law" :instrument-palette +slippery-chicken-standard-instrument-palette+ :ensemble '(((fl (flute :midi-channel 1)) (ob (oboe :midi-channel 2)) (cl (b-flat-clarinet :midi-channel 3)) (bn (bassoon :midi-channel 4)) (hn (french-horn :midi-channel 5)) (tp (b-flat-trumpet :midi-channel 6)) (tb (tenor-trombone :midi-channel 7)) (vno (violin :midi-channel 8)) (vnt (violin :midi-channel 9)) (va (viola :midi-channel 12)) (vc (cello :midi-channel 13)) (cb (double-bass :midi-channel 14)))) ;; setting pitch ranges for the scope of this composition :set-limits-high '((cl (0 c6 100 c6)) (vc (0 a4 100 a4)) (cb (0 f3 100 f3))) :staff-groupings '(4 3 5) :tempo-map '((1 (q 69))) :set-palette '((1 ((c3 g3 cs4 e4 fs4 a4 bf4 c5 d5 f5 gf5 af5 ef6))) (2 ((c3 fs3 cs4 e4 g4 a4 b4 c5 df5 f5 g5 af5 ef6))) (3 ((d3 f3 cs4 e4 fs4 a4 b4 c5 d5 e5 fs5 af5 ef6))) (4 ((d3 e3 cs4 ef4 fs4 a4 b4 c5 d5 e5 fs5 af5 d6))) (5 ((d3 e3 g3 a3 c4 ef4 f4 af4 bf4 cs5 fs5 b5 df6))) (6 ((c3 d3 gf3 af3 b3 e4 a4 df5 ef5 g5 bf5 df6))) (7 ((b2 e3 fs3 as3 ef4 g4 a4 d5 f5 af5 c6 df6))) (8 ((af2 b2 ef3 fs3 as3 cs4 e4 g4 a4 d5 f5 bf5 c6 e6 af6))) (9 ((af2 b2 ef3 fs3 bf3 d4 f4 a4 cs5 e5 g5 c6 f5 af6))) (10 ((af2 c3 ef3 fs3 bf4 d4 f4 a4 cs5 e5 g5 b5 fs6)))) ;; using a Lisp routine to generate the set-map :set-map (loop for section in '((1 (1 2 3)) (2 (2 3 4 1)) (3 (1 3 5 6 7)) (4 (8 9)) (5 (5 6 7 9 3)) (6 (9 10))) collect (list (first section) (fibonacci-transitions (nth (1- (first section)) num-seqs-list) (second section)))) :rthm-seq-palette sl-rsp-chopped ;; using a Lisp routine to generate the rthm-seq-map :rthm-seq-map (loop for section in '((((1 3) fl ob )) (((3 4) fl ob cl)) (((5 6 7 8) fl ob cl) ((11 12 13 14) bn tb vc cb)) (((9 10 11) hn tp)) (((15 16 25 26) fl ob vno vnt) ((9 10 13 14) cl hn va) ((3 1 16 3) tp tb) ((12 13 10 11) bn vc cb)) (((1 3 4) fl ob cl bn hn tp tb vno vnt va vc cb))) for section-num from 1 collect (list section-num (loop for ins-group in section appending (loop with fts = (loop for ch in (first ins-group) collect (list 1 ch)) for ins in (rest ins-group) collect (list ins (fibonacci-transitions (nth (1- section-num) num-seqs-list) fts)))))))) ;; The re-bar method can be applied outside of the above "let*" scope, since ;; the slippery-chicken class produces a global variable from its first ;; argument (re-bar +second-law+ :min-time-sig '(4 4) :auto-beam 'q) ;;; the output: ;;; midi (midi-play +second-law+ :midi-file "/tmp/second-law.mid") ;; CMN output (cmn-display +second-law+ :file "/tmp/second-law.eps" :size 12) ;; LP output (write-lp-data-for-all +second-law+ :base-path "/tmp/") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; EOF
The code explained
The material for the rthm-seq-palette
,
the rthm-seq-map
, and the set-map
for this
composition is generated algorithmically. Two of the options for
algorithmically generating material are to place the generating code
directly into the slippery-chicken
object, as can be seen in
the set-map
and rthm-seq-map
blocks, or to
assign the generating code to variables, as has been done here at the top
of the example.
Setting up the environment
As in the core usage tutorial, this
example first sets the global parameters for package
and scale
:
(in-package :sc) (in-scale :chromatic)
Setting up the scope
Setting the variables
The variables in this example are declared using the let
macro and enclosed in the same scope as the call to
the make-slippery-chicken
function below them, allowing the
material assigned to these variables to be used in that
function. (Another option would be to declare global variables for the
material, but the let
option is more concise.)
Three variables are declared here. The first,
sl-rsp-orig
, stores the rthm-seq-palette
that
serves as the source material for this piece. The
second, sl-rsp-chopped
, stores the results of applying
the chop
method to the contents of
the sl-rsp-orig
variable. The chop
method
itself returns a rthm-seq-palette
object, and can therefore
be directly passed to the :rthm-seq-palette
keyword argument
within the subsequent call to the make-slippery-chicken
function. This method will be described in more detail below. The third
variable, num-seqs-list
, is a list of numbers that will be
the number of rthm-seq
objects and sets
in each of their respective maps within the
slippery-chicken
object, thereby determining the length of
each section.
The original rthm-seq-palette
The original palette is constructed in essentially the same way as in
the core usage guide, with one new
attribute, namely that this example defines more than one curve
(pitch-seq
) for the pitch-seq-palette
.
:pitch-seq-palette ((1 2 1 2 3 2 3 3 1 2 5 5 7 6) (2 1 2 1 2 3 2 2 4 3 2 2 1 2) (5 3 4 5 4 5 4 5 2 3 6 6 8 7))
See the page on using multiple curves in the same :pitch-seq-palette for more detail on this feature.
Adjusting instrument attributes for the scope of the piece
The last element before the creation of
the slippery-chicken
object is a short routine that adjusts
the largest-fast-leap
value of the instrument
objects used in the composition.
(loop for i in '((flute 13) (oboe 7) (b-flat-clarinet 9) (bassoon 7) (french-horn 5) (b-flat-trumpet 7) (tenor-trombone 5) (double-bass 5)) do (set-slot 'largest-fast-leap (second i) (first i) +slippery-chicken-standard-instrument-palette+))
This loop passes through a list of instrument names paired with numbers
and sets the largest-fast-leap
value of the
corresponding instrument
object in the global
+slippery-chicken-standard-instrument-palette+
(which is
the instrument-palette
used in this piece) to the given
number. Note that the instrument names here are the IDs in the given
instrument-palette
, not the user-defined player IDs in
the ensemble
block.
This routine limits the maximum linear interval between two consecutive 32nd-notes for each of the instruments in the list to a relatively small span (mostly perfect fourths and fifths), ensuring that the resulting music is more easily playable.
More information on the largest-fast-leaps
and other slots
of the instrument
class can be found in the source
documentation here.
Also see the page on tailoring instrument
definitions for related information.
The call to make-slippery-chicken
Many of the components of the make-slippery-chicken
function for this piece are the same as in
the core-usage guide. Thus, the usage of
the initial global variable, as well as
the title
, instrument-palette
,
ensemble
,
staff-groupings
, and tempo-map
blocks will
not be discussed here.
Setting tessitura for one piece
Although the set-slot
method used above could be used here
as well to set the upper limits for instrument ranges for the entirety of
the given piece, this example uses the :set-limits-high
keyword argument of the make-slippery-chicken
function to
cap the upper limits of the clarinet, cello, and bass for the duration of
the piece:
:set-limits-high '((cl (0 c6 100 c6)) (vc (0 a4 100 a4)) (cb (0 f3 100 f3)))
See the page on pitches for more
details on the usage of :set-limits-high
and :set-limits-low
.
Well-considered set palettes
The set-palette
for this example is constructed by hand
and not algorithmically. Emphasis was placed on choosing pitches that are
seldom more than a third apart, to allow for smoother lines in the
instruments.
:set-palette '((1 ((c3 g3 cs4 e4 fs4 a4 bf4 c5 d5 f5 gf5 af5 ef6))) (2 ((c3 fs3 cs4 e4 g4 a4 b4 c5 df5 f5 g5 af5 ef6))) (3 ((d3 f3 cs4 e4 fs4 a4 b4 c5 d5 e5 fs5 af5 ef6))) (4 ((d3 e3 cs4 ef4 fs4 a4 b4 c5 d5 e5 fs5 af5 d6))) (5 ((d3 e3 g3 a3 c4 ef4 f4 af4 bf4 cs5 fs5 b5 df6))) (6 ((c3 d3 gf3 af3 b3 e4 a4 df5 ef5 g5 bf5 df6))) (7 ((b2 e3 fs3 as3 ef4 g4 a4 d5 f5 af5 c6 df6))) (8 ((af2 b2 ef3 fs3 as3 cs4 e4 g4 a4 d5 f5 bf5 c6 e6 af6))) (9 ((af2 b2 ef3 fs3 bf3 d4 f4 a4 cs5 e5 g5 c6 f5 af6))) (10 ((af2 c3 ef3 fs3 bf4 d4 f4 a4 cs5 e5 g5 b5 fs6))))
Another important attribute of this particular set-palette
definition is that the IDs of each of the sets are consecutive
integers. Although these IDs could be numbers or alphabetic symbols, the
use of numbers facilitates the implementation of
the fibonacci-transitions
function below.
See the page on pitches for
more details on the usage of set-palettes
.
An application of fibonacci-transitions
The fibonacci-transitions
function is used several times in
this composition (see the page
Fibonacci Transitions for a general
introduction to the function). It occurs for the first time in the
generation of the set-map
, in conjunction with the
variable num-seqs-list
.
(num-seqs-list '(53 61 97 79 89 73))) :set-map (loop for section in '((1 (1 2 3)) (2 (2 3 4 1)) (3 (1 3 5 6 7)) (4 (8 9)) (5 (5 6 7 9 3)) (6 (9 10))) collect (list (first section) (fibonacci-transitions (nth (1- (first section)) num-seqs-list) (second section))))
For each number-list pair in the loop
,
the fibonacci-transitions
function is called and applied to
the list of numbers of that pair (accessed by
(second section)
) according to the number of times
stipulated by the corresponding nth
element of
the num-seqs-list
. The result is then collected into a list
with the corresponding section number (accessed by
(first section)
) and passed to the set-map
keyword argument of the call to slippery-chicken
. The loop
eliminates the need for a series of individual calls
to fibonacci-transitions
that would look like:
(fibonacci-transitions 53 '(1 2 3)) (fibonacci-transitions 61 '(2 3 4 1)) etc.
Its result, if typed in manually instead, would look like this:
((1 (1 1 1 1 1 1 2 1 1 1 1 2 1 1 2 1 2 2 2 1 2 1 2 2 2 2 2 2 2 3 2 2 3 2 3 3 3 2 3 2 3 3 3 2 3 3 3 3 3 3 3 3 3)) (2 (2 2 2 2 2 3 2 2 2 2 3 2 2 3 2 3 2 3 2 3 3 3 3 3 4 3 4 3 4 3 4 3 4 3 4 4 4 4 4 1 4 1 4 1 4 1 4 1 4 1 1 1 4 1 1 1 1 1 1 1 1)) (3 (1 1 1 1 1 1 1 3 1 1 1 1 3 1 1 3 1 3 1 3 1 3 1 3 1 3 3 3 3 3 3 3 5 3 3 5 3 5 3 5 3 5 3 5 3 5 5 5 5 5 5 5 6 5 5 6 5 6 5 6 6 5 6 5 6 6 6 6 6 6 6 7 6 6 7 6 7 6 7 7 6 7 6 7 7 7 6 7 7 7 7 7 7 7 7 7 7)) (4 (8 8 8 8 8 8 8 8 8 8 8 8 8 8 9 8 8 8 8 8 8 8 9 8 8 8 8 9 8 8 9 8 8 9 8 9 8 9 8 9 9 8 9 8 9 9 8 9 9 8 9 9 9 9 9 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9)) (5 (5 5 5 5 5 5 6 5 5 5 5 6 5 5 6 5 6 6 6 5 6 5 6 6 6 6 6 6 6 7 6 6 7 6 7 7 7 6 7 6 7 7 7 7 7 7 7 9 7 7 9 7 9 9 9 7 9 7 9 9 9 9 9 9 9 3 9 9 3 9 3 3 3 9 3 9 3 3 3 9 3 3 3 3 3 3 3 3 3)) (6 (9 9 9 9 9 9 9 9 9 9 9 9 9 10 9 9 9 9 9 9 9 10 9 9 9 9 10 9 9 10 9 9 10 9 10 9 10 10 9 10 9 10 9 10 10 9 10 10 10 10 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10)))
This short loop has automatically generated a considerable amount of data and made its representation and inclusion in the example conceptually concise, easy to enter and modify, and tidy.
An application of the chop method
For this composition, the chop
method is employed to break
the original rthm-seq-palette
into fragments for use
with fibonacci-transitions
. (See
the chop
page for a more general
introduction to the method.) The method is applied here to create
fragments whose durations are multiples of an eighth note using the
following arguments, then assigning the
resulting rthm-seq-palette
to the
variable sl-rsp-chopped
:
(sl-rsp-chopped (chop sl-rsp-orig '((1 2) (1 1) (2 2)) ; chop points 'e)) ; chopping unit
The chop points here are stipulated specifically, dividing the
basis beat of the original material (which is determined by the time
signature of the original material and is a quarter note in this
instance) into three fragments, two that are one unit long (one beginning
and ending on the first eighth of the beat and one beginning and ending
on the second eighth of the beat), and one that is two units long
(beginning on the first eighth of the beat and ending on the second
eighth of the beat). The method applies this chopping pattern
successively to each beat in the entire
original rthm-seq-palette
, resulting in this example in 36
fragments, the first twelve of which have the following structure:
;; These are first 12 results of the (print-simple sl-rsp-chopped) function ;; commented out in the source code above. rthm-seq 1 (1 4): rest E., note S, rthm-seq 2 (1 8): rest 8, rthm-seq 3 (1 8): rest S, note S, rthm-seq 4 (1 4): rest 32, note 32, note 32, note 32, rest E, rthm-seq 5 (1 8): rest 32, note 32, note 32, note 32, rthm-seq 6 (1 8): rest 8, rthm-seq 7 (1 4): note 32, note 32, rest S, note 32, note 32, note 32, rest 32, rthm-seq 8 (1 8): note 32, note 32, rest S, rthm-seq 9 (1 8): note 32, note 32, note 32, rest 32, rthm-seq 10 (1 4): rest S, note S, note S, rest S, rthm-seq 11 (1 8): rest S, note S, rthm-seq 12 (1 8): note S, rest S, etc.
The results of the chop
method are assigned to the
variable sl-rsp-chopped
and passed to
the rthm-seq-palette
.
:rthm-seq-palette sl-rsp-chopped
The individual fragments within the
resulting rthm-seq-palette
are then accessed using
the fibonacci-transitions
function from within
the rhtm-seq-map
, as detailed below.
Combining chop and fibonacci-transitions for
intra-phrasal looping
The :rthm-seq-map and orchestration
In the next block of this example, the rthm-seq-map
is
then also generated algorithmically:
:rthm-seq-map (loop for section in '((((1 3) fl ob )) (((3 4) fl ob cl)) (((5 6 7 8) fl ob cl) ((11 12 13 14) bn tb vc cb)) (((9 10 11) hn tp)) (((15 16 25 26) fl ob vno vnt) ((9 10 13 14) cl hn va) ((3 1 16 3) tp tb) ((12 13 10 11) bn vc cb)) (((1 3 4) fl ob cl bn hn tp tb vno vnt va vc cb))) for section-num from 1 collect (list section-num (loop for ins-group in section appending (loop with fts = (loop for ch in (first ins-group) collect (list 1 ch)) for ins in (rest ins-group) collect (list ins (fibonacci-transitions (nth (1- section-num) num-seqs-list) fts))))))
In addition to being the code that creates the
intra-phrasal looping, this loop
also determines
one aspect of the orchestration for the piece, in that it defines which
instruments of the ensemble play in each section, and which of those
instruments are "coupling" each other by playing rhythmically identical
material.
The loop
passes through a list of nested lists. The first
level of these contains six lists, each corresponding to one section of
the piece's section map. The next level of lists determines how many
separate rhythmic patterns will be simultaneously played in each
section. Sections 1, 2 and 4, for example, each have only one rhythmic
element played by all instruments, while section 5 has four rhythmic
elements played by different instrument groups. The final level
determines exactly which rhythmic patterns will be played, and which
instruments will play each of these patterns, by specifying a sublist of
numbers and a series of player IDs.
'((((1 3) fl ob)) (((3 4) fl ob cl)) (((5 6 7 8) fl ob cl) ((11 12 13 14) bn tb vc cb)) (((9 10 11) hn tp)) (((15 16 25 26) fl ob vno vnt) ((9 10 13 14) cl hn va) ((3 1 16 3) tp tb) ((12 13 10 11) bn vc cb)) (((1 3 4) fl ob cl bn hn tp tb vno vnt va vc cb)))
The player IDs are taken from the ensemble
block. The
numbers are the IDs of the individual rthm-seq
objects
contained in the rthm-seq-palette
created by
the chop
method.
Assembling the rthm-seq-map from the chop fragments
To accommodate for the additional level of nesting that
the chop
method adds to any rthm-seq-palette
it processes, the loop function here automatically adds the additional ID
from the original rthm-seq
object required to reference each
given rthm-seq
(fragment) that the chopped palette
contains. Since only one rthm-seq
was defined in the
original rthm-seq-palette
, and this was given the
ID 1
, the newly created fragments are accessed
using (1 1)
, to get the first fragment
of rthm-seq
1
, (1 2)
to get the
second fragment of rthm-seq
1
,
(1 3)
to get the third fragment
of rthm-seq
1
, etc.
(loop for ch in (first ins-group) collect (list 1 ch))
See the manual page on chop for more detail on this concept.
The last component of this loop
is then a call to
the fibonacci-transitions
function for each of the players
listed, using the references created from the collection of the
original rthm-seq
ID and the new rthm-seq
IDs,
and the same num-seqs-list
used for
the set-map
.
collect (list ins (fibonacci-transitions (nth (1- section-num) num-seqs-list) fts))))))
If these were written out in full, they would look like this:
((1 ((fl (fibonacci-transitions 53 '((1 1) (1 3)))) (ob (fibonacci-transitions 53 '((1 1) (1 3))))) (2 ((fl (fibonacci-transitions 61 '((1 3) (1 4)))) (ob (fibonacci-transitions 61 '((1 3) (1 4)))) (cl (fibonacci-transitions 61 '((1 3) (1 4)))))) etc.
All together, then, the code that this loop
generates would
begin like this:
((1 ((FL ((1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 3) (1 1) (1 1) (1 1) (1 1) (1 3) (1 1) (1 1) (1 3) (1 1) (1 1) (1 3) (1 1) (1 3) (1 1) (1 3) (1 1) (1 3) (1 3) (1 1) (1 3) (1 3) (1 1) (1 3) (1 3) (1 3) (1 3) (1 3) (1 1) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3))) (OB ((1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 1) (1 3) (1 1) (1 1) (1 1) (1 1) (1 3) (1 1) (1 1) (1 3) (1 1) (1 1) (1 3) (1 1) (1 3) (1 1) (1 3) (1 1) (1 3) (1 3) (1 1) (1 3) (1 3) (1 1) (1 3) (1 3) (1 3) (1 3) (1 3) (1 1) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3))))) (2 ((FL ((1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 4) (1 3) (1 4) (1 4) (1 4) (1 3) (1 4) (1 3) (1 4) (1 4) (1 3) (1 4) (1 4) (1 4) (1 4) (1 4) (1 3) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4))) (OB ((1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 4) (1 3) (1 4) (1 4) (1 4) (1 3) (1 4) (1 3) (1 4) (1 4) (1 3) (1 4) (1 4) (1 4) (1 4) (1 4) (1 3) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4))) (CL ((1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 3) (1 3) (1 4) (1 3) (1 3) (1 4) (1 3) (1 4) (1 4) (1 4) (1 3) (1 4) (1 3) (1 4) (1 4) (1 3) (1 4) (1 4) (1 4) (1 4) (1 4) (1 3) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4) (1 4))))) etc.
Equal lengths
A final reminder must be made before leaving this section. As discussed
in the core-usage guide, all
simultaneously occurring rthm-seq
objects in a
given rthm-seq-map
must be of the same length. For example,
the fifth section from this piece includes fibonacci-based transitions
from rthm-seq
(1 15)
to
(1 16)
to (1 25)
to (1 26)
in
the fl
, ob
, vno
and vnt
, against simultaneously occurring transitions
from rthm-seq
(1 3)
to (1 1)
to (1 16)
to (1 3)
in the tp
and tb
. This only functions without returning an error
because the corresponding sections are of equal length, thus
(1 15)
and (1 3)
both 1/8 bars,
(1 16)
and (1 1)
are both 1/4 bars, etc. (This
holds true for the other simultaneously occurring rhythmic material in
that section as well.)
Calling functions for editing material generated by slippery chicken
re-bar
The final method called in this example before generating the output is
the re-bar
method, which re-groups the existing musical
material into new bars as close to the specified length as possible. The
chopped material from this example produces only 1/4 and 1/8 bars, so
re-barring them into larger measures, in this instance, bars that are 4/4
or larger, will make the resulting music easier to read. That is done by
calling the re-bar
method with the global variable assigned
to the musical material generated above (+second-law+
) and
specifying the :min-time-sig
as '(4 4)
. This
example also turns on the :auto-beam
function, setting it to
automatically beam the newly barred content into quarters
('q
).
(re-bar +second-law+ :min-time-sig '(4 4) :auto-beam 'q)
As seen here, the re-bar
method can be applied outside of
the above let
scope, since the
slippery-chicken class
produces a global variable from its
first argument.
The output
The output from this piece is generated in the same manner described in
the core-usage guide, with the one
addition of the :size
argument to
the cmn-display
method.
;;; midi (midi-play +second-law+ :midi-file "/tmp/second-law.mid") ;; CMN output (cmn-display +second-law+ :file "/tmp/second-law.eps" :size 12) ;; LP output (write-lp-data-for-all +second-law+ :base-path "/tmp/")
NB: slippery chicken has a number of built-in
algorithms for automatic tidying, such as respell-notes
,
which attempts to automatically choose the best enharmonic spelling of
pitches in the printed output. The respell-notes
algorithm
is called automatically within the cmn-display
and write-lp-data-for-all
methods. This can be disabled by
specifying :respell-notes nil
in the call
to cmn-display
or write-lp-data-for-all
. If the
user finds that the decisions slippery chicken makes are not in
line with his or her own preferences, the post-generation editing methods
can be used to manually tweak the output after the fact, such as by
changing enharmonic spellings etc. The output for this tutorial has not
been tweaked. See the page
on post-generation data editing for
more on this.
The :size
argument of the cmn-display
method
scales the size of the music on the page. The use of this argument is
necessary in this example, as the music would not fit on the page
otherwise, and the following warning would be issued by
slippery chicken.
WARNING: we don't have room on the page for this score: try a font size less than 13:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; EOF