Adding a tape part using CLM
+ Associated example files
- second-law-clm.lsp
- second-law.mid
- second-law.eps
- _second-law-score.pdf
- second-law-1-fl-ob-cl-bn-hn-tp-tb-vno-vnt-va-vc-cb-source-sndfile-grp-1-seq1-1.mp3
- second-law-1-fl-ob-cl-bn-hn-tp-tb-vno-vnt-va-vc-cb-source-sndfile-grp-2-seq1-1.mp3
- second-law-clm-mix.mp3
NB: An exercise relating to the material covered in this tutorial can be found on the Exercises page.
One of the fundamental goals in the development of slippery
chicken was to provide a means of unifying instrumental and
electroacoustic sound worlds in a convincing manner for compositions
that make use of both resources. This brief tutorial will provide
a quick introduction into how to produce a tape part from a
slippery-chicken
object using clm-play
. A
more detailed description of this topic, with instruction on how to
generate independent tape parts, can be found in the Tempus Perfectum tutorial.
This brief demonstration will use the same code used in
the Second Law tutorial, but
will expand it through the addition of a sndfile-palette
and two new calls to the output method clm-play
, thereby
creating two tape parts from the musical data already present in the
instrumental parts.
+ 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.
(in-package :sc) (in-scale :chromatic) (let* ((sndfiles-dir-1 (concatenate 'string cl-user::+slippery-chicken-home-dir+ "doc/manual/resources/")) (sl-rsp-orig ; defining the source material (make-rsp 'sl-rsp '((1 ((((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)))))) (sl-rsp-chopped (chop sl-rsp-orig '((1 2) (1 1) (2 2)) ; chop points 'e)) ; chopping unit (num-seqs-list '(53 61 97 79 89 73))) (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+)) (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)))) :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)))) :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-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)))))) :snd-output-dir "/tmp/" :sndfile-palette `(((source-sndfile-grp-1 ((test-sndfile-2.aiff :start 0.000 :end 0.504) (test-sndfile-2.aiff :start 0.504 :end 0.884) (test-sndfile-2.aiff :start 0.884 :end 1.608))) (source-sndfile-grp-2 ((test-sndfile-3.aiff :start 0.035 :end 0.426 :frequency 664) (test-sndfile-3.aiff :start 0.426 :end 0.682 :frequency 664) (test-sndfile-3.aiff :start 0.682 :end 2.200 :frequency 664)))) ,(list sndfiles-dir-1)))) (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 (cmn-display +second-law+ :file "/tmp/second-law.eps" :size 12) ;; LP (write-lp-data-for-all +second-law+ :base-path "/tmp/") ;; CLM (clm-play +second-law+ 1 nil 'source-sndfile-grp-1 :rev-amt 0.1 :src-width 5) (clm-play +second-law+ 1 nil'source-sndfile-grp-2 :reset-snds-each-rs nil :reset-snds-each-player nil :rev-amt 0.1 :src-width 5)
+ The basic concept behind clm-play
slippery chicken's clm-play
method functions
by generating sound files from the rhythm and pitch data in one or
more players' parts. In short, each attacked note in the specified
part(s) will trigger the playback of a sound file, and the playback
speed of this sound file will be adjusted on the basis of one of the
pitches of the current pitch set. The result is a tape part that is
directly created from the same compositional building blocks as the
instrumental parts, producing a piece whose electroacoustic and
instrumental sound worlds are unified by pitch, rhythm, and
structure.
The clm-play
method has 36 optional arguments,
providing the user with a broad number of specific parameters when
shaping the sound file output. This example will only make use of
four of these arguments. Further, more detailed information on the
remaining arguments can be found in the tutorial
for Tempus Perfectum, the
manual page for slippery chicken and
CLM, and
the source
code documentation.
+ Defining the palette of source sound files
The first requirement for producing such sound files is the
definition of a sndfile-palette
. This is where the sound
files that will serve as the source samples for the resulting output
file are identified.
:snd-output-dir "/tmp/" :sndfile-palette `(((source-sndfile-grp-1 ((test-sndfile-2.aiff :start 0.000 :end 0.504) (test-sndfile-2.aiff :start 0.504 :end 0.884) (test-sndfile-2.aiff :start 0.884 :end 1.608))) (source-sndfile-grp-2 ((test-sndfile-3.aiff :start 0.035 :end 0.426 :frequency 664) (test-sndfile-3.aiff :start 0.426 :end 0.682 :frequency 664) (test-sndfile-3.aiff :start 0.682 :end 2.200 :frequency 664)))) ,(list sndfiles-dir-1))
Groups
The source sound files
(test-sndfile-1.aiff, test-sndfile-2.aiff,
and test-sndfile-3.aiff)
are collected into groups with user-defined IDs. These groups consist
of each separate sound file contained in a list that may or may not
specify further parameters, such as the start and end point within
the source sound file from which to take the sample, and the
perceived fundamental frequency of that sound file or sound file
segment. There can be as many groups as the user likes, and each
group may contain as many sound files as the user likes as well. If
multiple segments of the same sound file are specified, these will be
treated by clm-play
as though they were separate sound
files.
File type extensions
The names of the sound files can be stated with or without the file
extension. If the extension is omitted, it must be added as a string
within a list that forms the third element of
the sndfile-palette
. This example specifies the
extensions when naming the files within the groups. See the other
pages mentioned above for more on the syntax that allows the
extensions to be omitted within the groups.
Paths
Following the list of groups, the sndfile-palette
also
requires a list of directory paths where the source sound files are
located. This example assigns the path where the desired source sound
files are stored to the variable sndfiles-dir-1
at the
top of the let*
enclosure, and passes it to
the sndfile-palette
using Lisp's backquote and comma
syntax. The path itself is created by concatenating the
global slippery chicken
parameter +slippery-chicken-home-dir+
with the path to
the resources directory of the sc/doc/manual/
folder.
(sndfiles-dir-1 (concatenate 'string cl-user::+slippery-chicken-home-dir+ "doc/manual/resources/"))
+ The basic call to clm-play
The clm-play
method can produce output with just its
four mandatory arguments, namely the slippery-chicken
object whose data is to be used to generate the new sound file, the
ID of the first section within that slippery-chicken
object on which the output is to be based, the IDs of the players
whose parts are to provide the pitch and rhythm material for the new
sound file, and the ID of the group within
the sndfile-palette
whose source sound files are to be
used to create the output.
This example creates two new audio files based on the musical data
from the piece Second Law. Each call
to clm-play
produces one new sound file. The first four
arguments of the two calls to clm-play
in this demo
composition are as follows:
(clm-play +second-law+ 1 nil 'source-sndfile-grp-1 [...] (clm-play +second-law+ 1 nil 'source-sndfile-grp-2 [...]
Both calls will create new output sound files based on the pitch and
rhythm data of the slippery-chicken
object with the
global ID +second-law+
, and both will create their
output starting with section 1
of the piece defined in
that object.
Instead of specifying a list of player IDs as the third argument,
this example passes NIL
. Passing NIL
as the
third argument causes the method to use all event objects (pitches
and rhythms) from all players' parts to create the resulting sound
file output.
The fourth argument of the first call here to clm-play
specifies that the source sound files from the first group defined in
the sndfile-palette
, with the
ID 'source-sndfile-grp-1
, are to be used to generate the
first output file. The second sound file will then be generated by
the second call to clm-play
using the source sound files
of the second group.
+ The four optional arguments used here
This example makes use of four of the 36 optional arguments
available to the clm-play
method. These
are :rev-amt
, :src-width
,
:reset-snds-each-rs
,
and :reset-snds-each-player
.
:rev-amt
The :rev-amt
argument determines how much
reverberation will be added to the resulting sound file. If this
argument is not given a specific value by the user, the amount of
reverb defaults to 0
. The value of 0.1
used in both calls to clm-play
here is already a
relatively high amount of reverb.
:src-width
The value passed to the :src-width
argument determines
the depth of the interpolation algorithms used when transposing
source sound files to other playback speeds ("sample-rate conversion"
= "src"). The higher the value, the finer the quality of the
transposition, but the longer it will take to process.
This value defaults to 20
if not otherwise
specified. It is set to 5
in each of the calls
to clm-play
here to facilitate faster rendering of the
resulting sound files. A value this low is highly recommended when
producing test sound-files of longer segments.
:reset-snds-each-rs and :reset-snds-each-player
These two related arguments affect the cyclical selection of the
sound files from each group. The clm-play
method cycles
through the list of source sound files of the given group from event
to event in the players' parts. When the last sound file in that list
has been used, the method returns to the first one again. By default,
the method will "reset" these sounds at each sequence and with each
new player; i.e., each consecutive section will always start with the
first sound in the list.
The second call to clm-play
in this example here sets
both of these arguments to NIL
. Doing so causes the
method to continue selecting the subsequent sounds from the given
group consecutively even past the beginning of a new sequence,
producing a slightly less obvious demarcation of the sequences within
the new output sound file. The first call to clm-play
in
this example leaves these arguments at their default value
of T
for a slightly different structural quality in its
output file.
+ Putting it all together with external software
Since this example uses multiple calls to clm-play
,
and thereby produces more than one new sound file, the final stereo
tape part had to be created using an external digital audio
workstation. In this case, the two output .aiff files were
imported into Digital Performer, mixed together with a sample-based
MIDI mock-up of the instrumental parts, and bounced to disk as an
MP3, which can be accessed from the corresponding link in the
"Associated example files" section above.