"Reeling Trains" — Composing with Rhythm Chains
+ Associated files
This demo composition and tutorial focuses on slippery
chicken's rhythm chains feature. It also implements two
user-defined functions and the process-events-by-time
method to distribute dynamics and articulation throughout the
instruments over the course of the piece, and it makes use of
the map-over-bars
, consolidate-notes
,
and auto-slur
methods for further automatic adjustment
of the piece created before outputting the result.
More on the rthm-chain
class can be found on
the rhythm chains page of the user
manual.
+ The Code
;; A function to place dynamics on random notes in the score (defun place-dyns (event) (when (equalp (start-time event) 0.0) (random-rep 10 t)) (unless (is-rest event) (when (> (random-rep 100) 67) (setf (marks event) (list (nth (random-rep 8) '(ppp pp p mp mf f ff fff))))))) ;; A function to place articulations (accent or staccato) on random notes in ;; the score (defun place-arts (event) (when (equalp (start-time event) 0.0) (random-rep 10 t)) (unless (is-rest event) (when (> (random-rep 100) 67) (setf (marks event) (list (nth (random-rep 5) '(a s))))))) ;; Disabling the chord function on the string instruments (no double-stops) (loop for i in '(violin viola cello) do (set-slot 'chords nil i +slippery-chicken-standard-instrument-palette+)) ;; Changing the chord function for the piano instruments (loop for i in '(piano piano-lh) do (set-slot 'chord-function 'chord-fun1 i +slippery-chicken-standard-instrument-palette+)) (let* ((num-seqs 137) ; The number of sequences in the rthm-chain to be made ;; Defining the rthm-chain object (rch (make-rthm-chain 'test-rch num-seqs '((((e) e) ; the 1-beat fragments: 4 in total (- s (s) (s) s -) ({ 3 (te) - te te - }) ((e.) s)) (({ 3 (te) te (te) }) ; what we transition to ({ 3 - te (te) te - }) ({ 3 (te) - te te - }) ({ 3 (te) (te) te })) (((q)) ; the second transition (- s e s -) ({ 3 te (tq) }) (s (e.))) ((- e e -) ; the third transition (- s s s - (s)) ((32) 32 (e.)) ((q)))) '((((q q) ; the 2/4 bars: 4 total ((q) q) ((q) q) ((q) (s) e.)) (({ 3 te te +te te +te te }) ; what we transition to (q - s e. -) (q (s) e.) (q (s) - s e -)) ((q - +e e -) ; the second transition ((e) e +e e) (q - s (e) s -) ((s) e. +s e.))) ((((e.) s (e) e (s) e.) ; the 3/4 bars: 4 total (- e e - (e) e (q)) (- e. s - - +e e - (q)) (q (e.) s (q))) (({ 3 (te) (te) te +te te +te } (q)) ; what we transition to (- e. s - (q) (s) - s e -) ({ 3 te te +te } (q) q) ({ 3 - te +te te - } (e) e { 3 (te) (te) te })) ((q +q +q) ; the second transition (q +q (q)) (- e e - +q (q)) (s (e.) (q) (q))))) ;; The proportion of rests or sounding notes in each passage :activity-curve '(0 5 20 7 30 8 50 3 70 5 80 8 100 10) ;; The durations to be used for the inserted rests :rests '(s e s q) ;; The durations to be used for the inserted rhythms :sticking-rthms '(e h e. w s e h s) ;; The activity-curve for the sticking rhythms :sticking-curve '(0 2 20 3 30 5 50 8 80 10 100 2) ;; The number of times each sticking rhythm is repeated :sticking-repeats '(3 5 3 5 8) ;; The number of consecutive sequences that have the same ;; harmonic set :harmonic-rthm-curve '(0 1 10 2 30 3 40 1 50 2 80 4 90 5 100 1) ;; The min and max beat duration of bars generated; beat taken from ;; the given time signature. :split-data '(4 7) ;; The IDs for the original two players :players '(fl cl)))) ;; Adding new voices based on the content of the original two, these with ;; offsets however to avoid completely identical voices. (add-voice rch '(1 fl) 'ob 1) (add-voice rch '(1 cl) 'bn 1) (add-voice rch '(1 fl) 'pnr 2) (add-voice rch '(1 cl) 'pnl 2) (add-voice rch '(1 fl) 'vn 3) (add-voice rch '(1 fl) 'va 4) (add-voice rch '(1 cl) 'vc 3) (add-voice rch '(1 cl) 'vb 4) ;; Creating automatically generated pitch-seq palettes for the rthm-seqs made (create-psps (palette rch)) ;; A series of variables for the make-slippery-chicken function, starting ;; with the definition of the set-palette (let* ((sp '((1 ((c3 cs3 d3 e3 fs3 g3 c4 cs4 e4 c5 gs5 cs6 d6 ds6))) (2 ((b2 c3 fs3 gs3 ds4 e4 d5 ds5 cs6))) (3 ((af2 f3 fs3 d4 e4 fs4 a4 d5 e5 c6 af6))) (4 ((b2 c3 df3 f3 af3 c4 e4 d5 c6))) (5 ((bf2 g3 e4 ef5 d6))) (6 ((f3 ef4 a4 d5 e5 df6))) (7 ((a2 b2 af3 f4 ef5 e5 c6))) (8 ((e4 a4 c5 g5 af5 e6))) (9 ((e4 df5 bf5))) (10 ((b1 a2 g3 e4 df5 a5))) (11 ((ef3 bf3 e4 b4 d5 f5 c6 ef6))) (12 ((f3 df4 e4 b4 e5 f5 c6 g6))) (13 ((e4 b4 df5))) (14 ((d4 ef4 bf4))) (15 ((df4 bf4 a5 fs6))) (16 ((d4 ef4 f4 g4))) (17 ((g1 bf1 fs2 af2 f3 fs3 e4))) (18 ((ef1 df2 b2 a3 e4 f4 fs4 d5 a5 bf5))) (19 ((e4 f4 g4 b4 c5 g5 af5 e6 f6))) (20 ((bf3 b3 e4 f4 bf4))) (21 ((e3 f3 df4 d4 ds4 f4 df5 d5 b5))) (22 ((d3 g3 a3 e4 af4 ef5 df5))) (23 ((g4 af4 df5 d5 af5 df6 d6))) (24 ((af3 e4 a4 e5 bf5))) (25 ((df2 a2 e3 ef4 d5 af5))) (26 ((b2 ef3 df4 e4 c5 g5 ef6))) (27 ((d1 a1 ef2 c3 a3 f4))) (28 ((df3 g3 c4 df4 d4 e4))) (29 ((c3 b3 e4 df5 b5))) (30 ((ds1 ef2 b2 c3 g3 af3 d4 e4 b4 fs5 d6))) (31 ((d1 ef2 a2 ef3 bf3 e4 d5 bf5 g6))))) ;; Creating the set-palette using the procession algorithm (sm (procession (num-rthm-seqs rch) (length sp))) ;; Determining the high and low pitches for each instrument for each ;; harmonic set. Every time the same set occurs, the same instruments ;; will have the same limits. (sls '((fl ((1 gs5 c7) (2 d5 c7) (3 e5 c7) (4 d5 c7) (5 ef5 c7) (6 e5 c7) (7 ef5 c7) (8 g5 c7) (9 df5 c7) (10 df5 c7) (11 d5 c7) (12 e5 c7) (13 df5 c7) (14 bf4 c7) (15 a5 c7) (16 g4 c7) (17 e4 c7) (18 d5 c7) (19 g5 c7) (20 bf4 c7) (21 df5 c7) (22 ef5 c7) (23 af5 c7) (24 e5 c7) (25 d5 c7) (26 g5 c7) (27 f4 c7) (28 e4 c7) (29 df5 c7) (30 fs5 c7) (31 d5 c7))) (ob ((1 g4 a5) (2 g4 a5) (3 g4 a5) (4 g4 a5) (5 g4 a5) (6 g4 a5) (7 g4 a5) (8 g4 a5) (9 g4 a5) (10 g4 a5) (11 g4 a5) (12 g4 a5) (13 g4 a5) (14 g4 a5) (15 g4 a5) (16 g4 a5) (17 e4 a5) (18 g4 a5) (19 g4 a5) (20 g4 a5) (21 g4 a5) (22 g4 a5) (23 g4 a5) (24 g4 a5) (25 g4 a5) (26 g4 a5) (27 f4 a5) (28 e4 a5) (29 g4 a5) (30 g4 a5) (31 g4 a5))) (cl ((1 b4 c6) (2 b4 c6) (3 b4 c6) (4 b4 c6) (5 b4 c6) (6 b4 c6) (7 b4 c6) (8 b4 c6) (9 b4 c6) (10 b4 c6) (11 b4 c6) (12 b4 c6) (13 b4 c6) (14 bf4 c6) (15 b4 c6) (16 g4 c6) (17 e4 c6) (18 b4 c6) (19 b4 c6) (20 bf4 c6) (21 b4 c6) (22 b4 c6) (23 b4 c6) (24 b4 c6) (25 b4 c6) (26 b4 c6) (27 f4 c6) (28 e4 c6) (29 b4 c6) (30 b4 c6) (31 b4 c6))) (bn ((1 a2 d4) (2 a2 d4) (3 a2 d4) (4 a2 d4) (5 a2 d4) (6 a2 d4) (7 a2 d4) (8 a2 e4) (9 a2 e4) (10 a2 d4) (11 a2 d4) (12 a2 d4) (13 a2 e4) (14 a2 d4) (15 a2 d4) (16 a2 d4) (17 a2 d4) (18 a2 d4) (19 a2 e4) (20 a2 d4) (21 a2 d4) (22 a2 d4) (23 a2 g4) (24 a2 d4) (25 a2 d4) (26 a2 d4) (27 a2 d4) (28 a2 d4) (29 a2 d4) (30 a2 d4) (31 a2 d4))) (vb ((1 c4 f6) (2 c4 f6) (3 c4 f6) (4 c4 f6) (5 c4 f6) (6 c4 f6) (7 c4 f6) (8 c4 f6) (9 c4 f6) (10 c4 f6) (11 c4 f6) (12 c4 f6) (13 c4 f6) (14 c4 f6) (15 c4 f6) (16 c4 f6) (17 c4 f6) (18 c4 f6) (19 c4 f6) (20 c4 f6) (21 c4 f6) (22 c4 f6) (23 c4 f6) (24 c4 f6) (25 c4 f6) (26 c4 f6) (27 c4 f6) (28 c4 f6) (29 c4 f6) (30 c4 f6) (31 c4 f6))) (pnr ((1 c4 c8) (2 c4 c8) (3 c4 c8) (4 c4 c8) (5 c4 c8) (6 c4 c8) (7 c4 c8) (8 g5 c8) (9 df5 c8) (10 c4 c8) (11 c4 c8) (12 c4 c8) (13 b4 c8) (14 ef4 c8) (15 a5 c8) (16 f4 c8) (17 f3 c8) (18 c4 c8) (19 c5 c8) (20 e4 c8) (21 df5 c8) (22 c4 c8) (23 af5 c8) (24 a4 c8) (25 c4 c8) (26 c4 c8) (27 a3 c8) (28 c4 c8) (29 c4 c8) (30 c4 c8) (31 c4 c8))) (pnl ((1 a0 b3) (2 a0 b3) (3 a0 b3) (4 a0 b3) (5 a0 b3) (6 a0 b3) (7 a0 b3) (8 a0 c5) (9 a0 e4) (10 a0 b3) (11 a0 b3) (12 a0 b3) (13 a0 e4) (14 a0 d4) (15 a0 bf4) (16 a0 ef4) (17 a0 af2) (18 a0 b3) (19 a0 b4) (20 a0 b3) (21 a0 ds4) (22 a0 b3) (23 a0 d5) (24 a0 e4) (25 a0 b3) (26 a0 b3) (27 a0 c3) (28 a0 b3) (29 a0 b3) (30 a0 b3) (31 a0 b3))) (vn ((1 a4 c7) (2 a4 c7) (3 a4 c7) (4 a4 c7) (5 a4 c7) (6 a4 c7) (7 a4 c7) (8 a4 c7) (9 a4 c7) (10 a4 c7) (11 a4 c7) (12 a4 c7) (13 a4 c7) (14 a4 c7) (15 a4 c7) (16 f4 c7) (17 e4 c7) (18 a4 c7) (19 a4 c7) (20 f4 c7) (21 a4 c7) (22 a4 c7) (23 a4 c7) (24 a4 c7) (25 a4 c7) (26 a4 c7) (27 a3 c7) (28 d4 c7) (29 a4 c7) (30 a4 c7) (31 a4 c7))) (va ((1 g3 gs4) (2 g3 gs4) (3 g3 gs4) (4 g3 gs4) (5 g3 gs4) (6 g3 gs4) (7 g3 gs4) (8 g3 gs4) (9 g3 gs4) (10 g3 gs4) (11 g3 gs4) (12 g3 gs4) (13 g3 gs4) (14 g3 gs4) (15 g3 gs4) (16 g3 gs4) (17 g3 gs4) (18 g3 gs4) (19 g3 gs4) (20 g3 gs4) (21 g3 gs4) (22 g3 gs4) (23 g3 gs4) (24 g3 gs4) (25 g3 gs4) (26 g3 gs4) (27 g3 gs4) (28 g3 gs4) (29 g3 gs4) (30 g3 gs4) (31 g3 gs4))) (vc ((1 c2 fs3) (2 c2 fs3) (3 c2 fs3) (4 c2 fs3) (5 c2 fs3) (6 c2 fs3) (7 c2 fs3) (8 c2 e4) (9 c2 e4) (10 c2 fs3) (11 c2 fs3) (12 c2 fs3) (13 c2 e4) (14 c2 d4) (15 c2 df4) (16 c2 d4) (17 c2 fs3) (18 c2 fs3) (19 c2 e4) (20 c2 b3) (21 c2 fs3) (22 c2 fs3) (23 c2 g4) (24 c2 af3) (25 c2 fs3) (26 c2 fs3) (27 c2 fs3) (28 c2 fs3) (29 c2 fs3) (30 c2 fs3) (31 c2 fs3))))) ;; Creating a list for just the low set-limits, with consecutive ;; integers as x-values so there are equal number of breakpoint pairs ;; as sets in the set-palette (sll (loop for p in sls collect (list (first p) (loop for s in sm for i from 1 collect i collect (second (nth (1- s) (second p))))))) ;; Creating a list for just the high set-limits, with consecutive ;; integers as x-values so there are equal number of breakpoint pairs ;; as sets in the set-palette (slh (loop for p in sls collect (list (first p) (loop for s in sm for i from 1 collect i collect (third (nth (1- s) (second p))))))) ;; Creating the sc object (reeling-trains (make-slippery-chicken '+reeling-trains+ :title "reeling trains" :ensemble '(((fl (flute :midi-channel 1)) (ob (oboe :midi-channel 2)) (cl (b-flat-clarinet :midi-channel 3)) (bn (bassoon :midi-channel 4)) (vb (vibraphone :midi-channel 5)) (pnr (piano :midi-channel 6)) (pnl (piano-lh :midi-channel 7)) (vn (violin :midi-channel 8)) (va (viola :midi-channel 9)) (vc (cello :midi-channel 11)))) :staff-groupings '(4 1 2 3) :set-palette sp :set-map `((1 ,sm)) :set-limits-low sll :set-limits-high slh :tempo-map '((1 (q 72))) ;; The rs palette and map can be taken directly from the rthm-chain ;; object. :rthm-seq-palette (palette rch) :rthm-seq-map rch))) ;; add random dynamics (process-events-by-time reeling-trains #'place-dyns) ;; add random articulations (process-events-by-time reeling-trains #'place-arts) ;; remove repeated dynamics (remove-extraneous-dynamics reeling-trains) ;; remove specific marks (loop for pm in '((1 1 (cl bn vb pnr pnl vc) s) (2 1 vc ppp) (2 2 (vn vc) s) (2 3 vc ff) (3 1 va p) (3 2 (ob va) s) (3 2 vc fff) (5 3 ob f) (5 2 vn mf) (6 3 bn p) (8 4 ob s) (9 1 fl s) (12 1 vn s) (17 1 ob ff) (17 2 fl ppp) (19 3 vc mf) (20 2 cl s) (26 2 vn s) (26 2 va p) (27 1 bn p) (27 2 va s) (28 3 ob ff) (35 1 vn s) (38 2 bn fff) (42 2 vc f) (44 1 bn s) (47 2 ob mp) (47 3 bn ppp) (51 1 pnr s) (53 1 (fl vb) s) (53 2 (vb vc) s) (53 2 pnl mf) (54 2 vn s) (58 1 vc pp) (61 1 bn s) (61 4 (ob pnr va) (mf fff ppp)) (62 1 ob s) (62 2 va s) (63 2 va s) (65 1 pnr s) (66 1 ob pp) (66 3 ob s) (66 3 fl s) (70 2 fl mf) (72 1 va p) (73 2 vn s) (74 2 vn fff) (75 3 cl pp) (76 2 ob s) (77 2 ob s) (85 1 bn s) (85 3 vb ff) (85 4 bn s) (85 5 cl p) (85 5 bn a) (85 5 vc a) (86 3 (bn vc) (pp fff)) (86 4 vc s) (86 5 vb f) (87 2 ob s) (90 2 vb mf) (90 3 bn ff) (96 2 ob pp) (97 1 fl pp) (98 4 vn mf) (100 1 ob mf) (101 1 fl p) (101 1 vn s) (101 2 vn p) (102 1 vn s) (103 1 ob s) (103 1 vc mf) (105 1 vn s) (105 1 vb mp) (106 2 va fff) (106 2 vc s) (106 3 vb s) (106 3 vn f) (106 5 vb ff) (106 5 pnl ff) (106 5 vc p) (110 2 vn s) (110 3 va s) (110 3 vn mp) (110 2 va ppp) (111 2 ob fff) (114 2 vn fff) (114 2 ob mp) (114 3 pnr ppp) (116 3 vb mp) (118 2 pnr s) (118 2 vn mf) (120 2 va s) (120 2 cl pp) (120 3 pnr mp) (125 3 fl f) (125 3 va p) (125 3 va mp) (131 2 vn mf) (132 1 fl mp) (134 1 va ppp) (137 1 vn s) (137 2 fl fff) (138 2 pnr p) (139 1 va mp) (139 3 vn p) (142 2 vn s) (143 1 vn f) (144 1 pnr ff) (151 3 ob f) (153 1 bn s) (156 1 pnl s) (156 2 bn fff) (156 3 vb pp) (156 3 pnl fff) (156 3 va f) (156 5 vc a) (156 6 vb mf) (158 3 pnr ff) (163 2 fl p) (163 2 vn mp) (163 3 ob fff) (166 1 (fl va) (p mf)) (166 2 ob p) (167 1 cl f) (169 3 ob mp) (170 2 vn mf) (172 3 pnr s) (172 3 vn pp) (173 1 pnr s) (173 1 vb ff) (173 3 vn mp) (175 4 pnr mf) (175 4 vn ff) (175 4 va p) (176 2 cl s) (178 2 pnr pp) (178 2 va ff)) do (rm-marks-from-notes reeling-trains (first pm) (second pm) (third pm) (fourth pm))) ;; add diminuendo marks (loop for pdcr in '((pnr 2 2 4 1) (pnl 2 4 4 1) (vn 2 2 2 3) (bn 5 1 5 2) (bn 14 1 14 2) (fl 17 1 18 1) (ob 26 1 27 2) (fl 26 2 27 2) (ob 54 1 54 3) (vn 81 1 81 2) (ob 103 1 103 2) (bn 102 2 103 2) (vb 102 2 103 2) (va 107 1 107 2) (va 118 1 118 3) (va 169 1 169 3) (vn 172 2 172 4) (va 176 1 176 2)) do (add-mark-to-note reeling-trains (second pdcr) (third pdcr) (first pdcr) 'dim-beg) (add-mark-to-note reeling-trains (fourth pdcr) (fifth pdcr) (first pdcr) 'dim-end)) ;; add crescendo marks (loop for pdcr in '((va 2 2 4 3) (va 10 1 10 3) (cl 14 1 14 2) (va 17 2 18 1) (va 26 1 27 1) (fl 35 1 35 3) (ob 48 1 48 3) (vb 53 1 53 3) (pnl 54 1 54 2) (pnr 57 1 57 3) (fl 65 2 66 2) (bn 67 1 67 2) (va 66 3 67 1) (fl 77 3 78 1) (va 83 1 83 2) (fl 93 1 94 1) (va 93 2 94 1) (va 98 3 98 5) (pnr 106 1 106 3) (ob 110 1 110 3) (fl 142 2 143 2) (cl 145 1 145 3) (cl 164 1 164 2) (vb 170 1 170 2) (vn 175 3 175 5) (vc 176 1 176 2)) do (add-mark-to-note reeling-trains (second pdcr) (third pdcr) (first pdcr) 'cresc-beg) (add-mark-to-note reeling-trains (fourth pdcr) (fifth pdcr) (first pdcr) 'cresc-end)) ;; consolidate sounding durations (map-over-bars reeling-trains 1 nil nil #'consolidate-notes) ;; make the first dynamic forte (loop for p in '(fl ob cl bn vb pnr pnl vn va vc) do (add-mark-to-note reeling-trains 1 1 p 'f)) ;; auto-slur (auto-slur reeling-trains '(fl ob cl bn vb pnr pnl vn va vc) :over-accents nil :rm-staccatos nil) ;; output (midi-play reeling-trains :midi-file "/tmp/reeling-trains.mid") (cmn-display reeling-trains :file "/tmp/reeling-trains.eps" :size 14 :auto-clefs nil :in-c t) (write-lp-data-for-all reeling-trains :auto-clefs nil :in-c t)))
+ Functions to auto-insert dynamics and articulation
The musical material for this piece is generated automatically by
the algorithms associated with the rthm-chain
class. The
ultimate sequences of the given rhythm fragments will be influenced
by the procession
function as well as by values passed
to the rthm-chain
object's slots for controlling
activity levels and the automatic insertion of rests and notes. For
this reason, the final outcome will be rather difficult to predict,
and the smallest changes to any of those parameters may result in
very different content.
Correspondingly, this demo composition uses a post-generation data
editing method called process-events-by-time
in
conjunction with two user-defined functions to automatically place
dynamics and articulation into the score after the notes,
rests, and rhythms have all be generated.
process-events-by-time
The process-events-by-time
method will be covered in
more detail below, but its basic function is described here briefly
as a background to the first two functions defined in the code for
the piece.
The method essentially takes two arguments: The
slippery-chicken
object to process, and a
function that modifies individual events. It then passes through the
events of the generated piece in absolute chronological order,
regardless of the player, and applies the specified function to every
event in chronological sequence.
place-dyns and place-arts
The two user-defined functions
here, place-dyns
and place-arts
, are
essentially the same except for the marks they apply. They use
fixed-seed random processes to select articulation and dynamic marks.
They each first test to see if the current event
object is
at the beginning of the piece by checking to see if its
start-time
slot is 0.0
. If it is, they call
the random-rep
function once with the optional argument
T
to reset the random state of the current Lisp
environment. This ensures that the exact same pseudo-random series of
marks are chosen for the same notes each time the piece is generated
within that Lisp.
The functions then test to see whether the
current event
object is a rest or not. If not, they
choose a random number between 0 and 99, and if that number is
greater than 67 (i.e. roughly a third of the time), they replace
the marks
slot of that event
object with a
random mark from a specified list of marks. In the first function,
these marks are all dynamics, and in the second they are articulation
(either an accent or a staccato).
Both functions use
slippery chicken's random-rep
function again to
choose the mark, by pseudo-randomly selecting the position within the
list for the mark to be added. The articulation function includes an
additional degree of sparsity in its placement of marks, in that it
chooses a random number between 0 and 4 for the index position,
although there are only two marks in the given list.
;; A function to place dynamics on random notes in the score (defun place-dyns (event) (when (equalp (start-time event) 0.0) (random-rep 10 t)) (unless (is-rest event) (when (> (random-rep 100) 67) (setf (marks event) (list (nth (random-rep 8) '(ppp pp p mp mf f ff fff))))))) ;; A function to place articulations (accent or staccato) on random notes in ;; the score (defun place-arts (event) (when (equalp (start-time event) 0.0) (random-rep 10 t)) (unless (is-rest event) (when (> (random-rep 100) 67) (setf (marks event) (list (nth (random-rep 5) '(a s)))))))
These two functions are defined first, outside of the scope of the rest of the code, as they are called within the primary block of code that follows.
+ Adjusting the chord functions
The next two loops in the the code for this piece adjust the chord
functions for the instrument
objects which the piece is
to use.
Turning off double-stop capability in the strings
By default, the violin
, viola
,
and cello
instruments of
the +slippery-chicken-standard-instrument-palette+
are
set to be chord-capable. This allows double-stops to be incorporated
into pieces where chords are indicated. For this piece, the strings
are to play single notes only, so the first loop changes
the chords
slot of the
corresponding instrument
objects
to NIL
.
;; Disabling the chord function on the string instruments (no double-stops) (loop for i in '(violin viola cello) do (set-slot 'chords nil i +slippery-chicken-standard-instrument-palette+))
Changing the default chord function for the piano parts
The default chord function for the piano
and piano-lh
instruments of
the +slippery-chicken-standard-instrument-palette+
attempts to create four-note chords from consecutive pitches in the
current set. Since the pitch sets used in this piece contain
consecutive pitches that are minor and major seconds apart, this
default function would potentially create four-note clusters in the
resulting piano parts.
To avoid the creation of such clusters, this piece sets
the chord-function
slots of the
corresponding piano
and piano-lh
instruments to chord-fun1
, which attempts to create only
three-note chords from every second pitch in the set.
;; Changing the chord function for the piano instruments (loop for i in '(piano piano-lh) do (set-slot 'chord-function 'chord-fun1 i +slippery-chicken-standard-instrument-palette+))
+ Defining the rhythm fragments
The next section in the code for this piece consists of the
definition of the 1-beat, 2-beat, and 3-beat rhythmic fragments that
are to serve as the source material for the resulting
composition. Each of these lists will be used implicitly in
conjunction with the procession
algorithm to generate
the chains of rhythms for the piece (see the rhythm chains page for more
detail).
Each group also includes at least two transition sublists as well. This will result in a fibonacci-based transition from the initial fragments to the final fragments in each group over the course of the piece (again, see the rhythm chains page).
(let* ((num-seqs 137) ; The number of sequences in the rthm-chain to be made ;; Defining the rthm-chain object (rch (make-rthm-chain 'test-rch num-seqs '((((e) e) ; the 1-beat fragments: 4 in total (- s (s) (s) s -) ({ 3 (te) - te te - }) ((e.) s)) (({ 3 (te) te (te) }) ; what we transition to ({ 3 - te (te) te - }) ({ 3 (te) - te te - }) ({ 3 (te) (te) te })) (((q)) ; the second transition (- s e s -) ({ 3 te (tq) }) (s (e.))) ((- e e -) ; the third transition (- s s s - (s)) ((32) 32 (e.)) ((q)))) '((((q q) ; the 2/4 bars: 4 total ((q) q) ((q) q) ((q) (s) e.)) (({ 3 te te +te te +te te }) ; what we transition to (q - s e. -) (q (s) e.) (q (s) - s e -)) ((q - +e e -) ; the second transition ((e) e +e e) (q - s (e) s -) ((s) e. +s e.))) ((((e.) s (e) e (s) e.) ; the 3/4 bars: 4 total (- e e - (e) e (q)) (- e. s - - +e e - (q)) (q (e.) s (q))) (({ 3 (te) (te) te +te te +te } (q)) ; what we transition to (- e. s - (q) (s) - s e -) ({ 3 te te +te } (q) q) ({ 3 - te +te te - } (e) e { 3 (te) (te) te })) ((q +q +q) ; the second transition (q +q (q)) (- e e - +q (q)) (s (e.) (q) (q)))))
num-seqs
The second argument to the make-rthm-chain
function
called above is passed the variable num-seqs
, which is
defined as 137
in the first line of
this let*
enclosure. This simple variable allows for
the quick-and-easy modification of the length of the piece generated
through the modification of just one number.
+ Setting activity and auto-insertion of rests and rhythms
The rthm-chain
class has numerous slots whose values
influence the final sequences of the musical material generated. Most
of these are also made conveniently accessible through keyword
arguments to the make-rthm-chain
function. A number of
these will be looked at here briefly. For a complete list, see the
source code documentation
for rthm-chain. More
information on curves (envelopes) can be found on
the envelopes page.
activity-curve
The activity-curve
slot takes a list of breakpoint
pairs to define how active the instruments are over the course of the
piece. As with other slippery chicken curves, the x-values
of the activity-curve
can span any arbitrary
(increasing) range, which will then be scaled to the duration of the
entire piece.
The y-values for this curve must be between 1
and
10
, and these values indicate the amount of overall
activity at that given point in the piece. A value of 10
indicates that all beats generated for the rthm-chain
object will consist of sounding notes, while a value of
1
indicates that only 1 in 10 beats will have sounding
notes, with the remainder being rests. This algorithm is
deterministic, not stochastic, so the results will be the same each
time the piece is re-generated.
The activity curve for the rthm-chain
object in this
piece varies between 3
and 10
over the
course of the piece:
;; The proportion of rests to sounding notes in each passage :activity-curve '(0 5 20 7 30 8 50 3 70 5 80 8 100 10)
rests
The rests
slot of the rthm-chain
object
takes a list of rhythms from which the durations will be selected
when applying the automatic rest-insertion algorithm. This list
defaults to (e q q. w)
, but has been specified as
follows for this piece, so as to result in shorter rests being
inserted than is default:
;; The durations to be used for the inserted rests :rests '(s e s q)
The order in which specific durations are chosen for insertion is
based on the rest-cycle
slot. More on
the rest-cycle
and other rest-related slots can be found
in
the rthm-chain
source code documentation.
sticking-rthms
In addition to automatically inserting rests,
the rthm-chain
class also automatically inserts
so-called sticking-rhythms
. These are notes of specified
durations that are inserted at various points throughout the piece
(always after rests), according to predefined curves, and
repeated in a broken-record manner. The default sticking rhythms are
(e e e. q e s)
, but these have been changed to the
following for this piece, so as to incur a greater number of
sustained durations over the course of the composition:
;; The durations to be used for the inserted rhythms :sticking-rthms '(e h e. w s e h s)
sticking-curve
Similar to the activity-curve
, the
sticking-curve
slot acts as an activity envelope to
control the degree of repetition when inserting sticking
rhythms.
;; The activity-curve for the sticking rhythms :sticking-curve '(0 2 20 3 30 5 50 8 80 10 100 2)
sticking-repeats
The sticking-repeats
slot takes a list of integers that
indicate the number of repetitions applied in sticking segments. When
the values of this list have been exhausted, the method cycles to the
beginning and continues drawing from the head of the list again.
;; The number of times each sticking rhythm is repeated :sticking-repeats '(3 5 3 5 8)
harmonic-rthm-curve
The general speed of harmonic motion in the resulting piece can be
influenced by defining a harmonic-rthm-curve
. This curve
determines how many slower (2-beat and 3-beat) rhythm fragments are
combined into one rthm-seq
(each rthm-seq
in a slippery-chicken
object takes only one set of
pitches).
;; The number of consecutive sequences that have the same ;; harmonic set :harmonic-rthm-curve '(0 1 10 2 30 3 40 1 50 2 80 4 90 5 100 1)
split-data
The split-data
slot allows the user to set target
values for the minimum and maximum number of beats in the bars
generated for the resulting piece. These values are targets only; the
method may create bars of different lengths if the data generated
cannot be otherwise split. The values given here will apply to a
different beat basis depending on the time signature of each bar,
rather than on a consistent beat basis. The default value is
(2 5)
, but has been changed for this piece to avoid
very short bars:
;; The min and max beat duration of bars generated; beat taken from ;; the given time signature. :split-data '(4 7)
+ Setting up the players and adding voices
The last slot of the rthm-chain
object that is
explicitly set for this piece is the players
slot. The rthm-chain
class initially generates music
data with only two voices, and these two voices must be assigned
player IDs that correspond to the players in
the ensemble
slot of the
associated slippery-chicken
object.
;; The IDs for the original two players :players '(fl cl))))
add-voice
The add-voice
method allows the user to automatically
expand the content of the rthm-chain
object generated to
include further voices. Each new voice is based on sequences drawn
from one of the original two voices in the
initial rthm-chain
object, and must be assigned a player
ID. An additional integer can be passed to the method to indicate a
specific offset of the sequences chosen. More on this method can be
found on the rhythm chains manual
page.
;; Adding new voices based on the content of the original two, these with ;; offsets however to avoid completely identical voices. (add-voice rch '(1 fl) 'ob 1) (add-voice rch '(1 cl) 'bn 1) (add-voice rch '(1 fl) 'pnr 2) (add-voice rch '(1 cl) 'pnl 2) (add-voice rch '(1 fl) 'vn 3) (add-voice rch '(1 fl) 'va 4) (add-voice rch '(1 cl) 'vc 3) (add-voice rch '(1 cl) 'vb 4)
The IDs specified in the above slot and method correspond to
the ensemble
slot of the
subsequent slippery-chicken
object, as can be seen
here:
:ensemble '(((fl (flute :midi-channel 1)) (ob (oboe :midi-channel 2)) (cl (b-flat-clarinet :midi-channel 3)) (bn (bassoon :midi-channel 4)) (vb (vibraphone :midi-channel 5)) (pnr (piano :midi-channel 6)) (pnl (piano-lh :midi-channel 7)) (vn (violin :midi-channel 8)) (va (viola :midi-channel 9)) (vc (cello :midi-channel 11))))
+ Automatic pitch-seq-palettes
The rthm-chain
object contains an automatically
generated palette of rthm-seq
objects and
a rthm-seq-map
. The rthm-seq
objects must
have curves assigned to them for their melodic contours
(pitch-seqs
), and these can be automatically generated
for all rthm-seqs
in a rthm-chain
using
the create-psps
method, which takes
a rthm-seq-palette
object as its only required
argument. The rthm-seq-palette
for a
given rthm-chain
object can be accessed using
the palette
accessor keyword.
;; Creating automatically generated pitch-seq palettes for the rthm-seqs made (create-psps (palette rch))
+ The set-palette and the set-map
The set-palette
and the set-map
for this
piece are defined as variables prior to the call
to make-slippery-chicken
.
set-palette
The set-palette
consists of 31 pitch collections with
consecutive numerical IDs from 1
to 31
.
(let* ((sp '((1 ((c3 cs3 d3 e3 fs3 g3 c4 cs4 e4 c5 gs5 cs6 d6 ds6))) (2 ((b2 c3 fs3 gs3 ds4 e4 d5 ds5 cs6))) (3 ((af2 f3 fs3 d4 e4 fs4 a4 d5 e5 c6 af6))) (4 ((b2 c3 df3 f3 af3 c4 e4 d5 c6))) (5 ((bf2 g3 e4 ef5 d6))) (6 ((f3 ef4 a4 d5 e5 df6))) (7 ((a2 b2 af3 f4 ef5 e5 c6))) (8 ((e4 a4 c5 g5 af5 e6))) (9 ((e4 df5 bf5))) (10 ((b1 a2 g3 e4 df5 a5))) (11 ((ef3 bf3 e4 b4 d5 f5 c6 ef6))) (12 ((f3 df4 e4 b4 e5 f5 c6 g6))) (13 ((e4 b4 df5))) (14 ((d4 ef4 bf4))) (15 ((df4 bf4 a5 fs6))) (16 ((d4 ef4 f4 g4))) (17 ((g1 bf1 fs2 af2 f3 fs3 e4))) (18 ((ef1 df2 b2 a3 e4 f4 fs4 d5 a5 bf5))) (19 ((e4 f4 g4 b4 c5 g5 af5 e6 f6))) (20 ((bf3 b3 e4 f4 bf4))) (21 ((e3 f3 df4 d4 ds4 f4 df5 d5 b5))) (22 ((d3 g3 a3 e4 af4 ef5 df5))) (23 ((g4 af4 df5 d5 af5 df6 d6))) (24 ((af3 e4 a4 e5 bf5))) (25 ((df2 a2 e3 ef4 d5 af5))) (26 ((b2 ef3 df4 e4 c5 g5 ef6))) (27 ((d1 a1 ef2 c3 a3 f4))) (28 ((df3 g3 c4 df4 d4 e4))) (29 ((c3 b3 e4 df5 b5))) (30 ((ds1 ef2 b2 c3 g3 af3 d4 e4 b4 fs5 d6))) (31 ((d1 ef2 a2 ef3 bf3 e4 d5 bf5 g6)))))
set-map
The set-map
is automatically generated using
the rthm-chain
class's procession
function. It accesses the num-rthm-seqs
slot of the
given rthm-chain
object to obtain the number of items
that need to be in that map (one for each rthm-seq
), and
uses the length of the variable sp
(the set-palette
defined above) as its second argument,
thereby determining that it is to create its output from a list of
elements consisting of integers 1
to 31
.
;; Creating the set-palette using the procession algorithm (sm (procession (num-rthm-seqs rch) (length sp)))
These two variables will be passed directly to
the :set-palette
and :set-map
keyword
arguments of the make-slippery-chicken
function.
+ Set-limits for each instrument and each set
The next three variables determine the set-limits-high
and set-limits-low
envelopes for each player in the
piece. Usually these limits would be specified explicitly with an
envelope but here we use another mechanism for expressing this data
which seems more appropriate to the piece in hand. Essentially we use
the set-map
to create the envelope, ensuring that when
a specific set occurs then the upper and lower pitches for each
player are drawn from our hand-typed data.
The sls
variable consists of a list of the player IDs
paired with lists of 3-item sublists, each of those consisting of an
integer and two note-name symbols. The integers refer to pitch sets
in the set-palette
, and the two pitches represent the
lowest and highest pitches to be played by the given player whenever
that set occurs in the piece. There is one sublist for each set for
each player.
;; Determining the high and low pitches for each instrument for each ;; harmonic set. Every time the same set occurs, the same instruments ;; will have the same limits. (sls '((fl ((1 gs5 c7) (2 d5 c7) (3 e5 c7) (4 d5 c7) (5 ef5 c7) (6 e5 c7) (7 ef5 c7) (8 g5 c7) (9 df5 c7) (10 df5 c7) (11 d5 c7) (12 e5 c7) (13 df5 c7) (14 bf4 c7) (15 a5 c7) (16 g4 c7) (17 e4 c7) (18 d5 c7) (19 g5 c7) (20 bf4 c7) (21 df5 c7) (22 ef5 c7) (23 af5 c7) (24 e5 c7) (25 d5 c7) (26 g5 c7) (27 f4 c7) (28 e4 c7) (29 df5 c7) (30 fs5 c7) (31 d5 c7))) (ob ((1 g4 a5) (2 g4 a5) (3 g4 a5) (4 g4 a5) (5 g4 a5) (6 g4 a5) (7 g4 a5) (8 g4 a5) (9 g4 a5) (10 g4 a5) (11 g4 a5) (12 g4 a5) (13 g4 a5) (14 g4 a5) (15 g4 a5) (16 g4 a5) (17 e4 a5) (18 g4 a5) (19 g4 a5) (20 g4 a5) (21 g4 a5) (22 g4 a5) (23 g4 a5) (24 g4 a5) (25 g4 a5) (26 g4 a5) (27 f4 a5) (28 e4 a5) (29 g4 a5) (30 g4 a5) (31 g4 a5))) (cl ((1 b4 c6) (2 b4 c6) (3 b4 c6) (4 b4 c6) (5 b4 c6) (6 b4 c6) (7 b4 c6) (8 b4 c6) (9 b4 c6) (10 b4 c6) (11 b4 c6) (12 b4 c6) (13 b4 c6) (14 bf4 c6) (15 b4 c6) (16 g4 c6) (17 e4 c6) (18 b4 c6) (19 b4 c6) (20 bf4 c6) (21 b4 c6) (22 b4 c6) (23 b4 c6) (24 b4 c6) (25 b4 c6) (26 b4 c6) (27 f4 c6) (28 e4 c6) (29 b4 c6) (30 b4 c6) (31 b4 c6))) (bn ((1 a2 d4) (2 a2 d4) (3 a2 d4) (4 a2 d4) (5 a2 d4) (6 a2 d4) (7 a2 d4) (8 a2 e4) (9 a2 e4) (10 a2 d4) (11 a2 d4) (12 a2 d4) (13 a2 e4) (14 a2 d4) (15 a2 d4) (16 a2 d4) (17 a2 d4) (18 a2 d4) (19 a2 e4) (20 a2 d4) (21 a2 d4) (22 a2 d4) (23 a2 g4) (24 a2 d4) (25 a2 d4) (26 a2 d4) (27 a2 d4) (28 a2 d4) (29 a2 d4) (30 a2 d4) (31 a2 d4))) (vb ((1 c4 f6) (2 c4 f6) (3 c4 f6) (4 c4 f6) (5 c4 f6) (6 c4 f6) (7 c4 f6) (8 c4 f6) (9 c4 f6) (10 c4 f6) (11 c4 f6) (12 c4 f6) (13 c4 f6) (14 c4 f6) (15 c4 f6) (16 c4 f6) (17 c4 f6) (18 c4 f6) (19 c4 f6) (20 c4 f6) (21 c4 f6) (22 c4 f6) (23 c4 f6) (24 c4 f6) (25 c4 f6) (26 c4 f6) (27 c4 f6) (28 c4 f6) (29 c4 f6) (30 c4 f6) (31 c4 f6))) (pnr ((1 c4 c8) (2 c4 c8) (3 c4 c8) (4 c4 c8) (5 c4 c8) (6 c4 c8) (7 c4 c8) (8 g5 c8) (9 df5 c8) (10 c4 c8) (11 c4 c8) (12 c4 c8) (13 b4 c8) (14 ef4 c8) (15 a5 c8) (16 f4 c8) (17 f3 c8) (18 c4 c8) (19 c5 c8) (20 e4 c8) (21 df5 c8) (22 c4 c8) (23 af5 c8) (24 a4 c8) (25 c4 c8) (26 c4 c8) (27 a3 c8) (28 c4 c8) (29 c4 c8) (30 c4 c8) (31 c4 c8))) (pnl ((1 a0 b3) (2 a0 b3) (3 a0 b3) (4 a0 b3) (5 a0 b3) (6 a0 b3) (7 a0 b3) (8 a0 c5) (9 a0 e4) (10 a0 b3) (11 a0 b3) (12 a0 b3) (13 a0 e4) (14 a0 d4) (15 a0 bf4) (16 a0 ef4) (17 a0 af2) (18 a0 b3) (19 a0 b4) (20 a0 b3) (21 a0 ds4) (22 a0 b3) (23 a0 d5) (24 a0 e4) (25 a0 b3) (26 a0 b3) (27 a0 c3) (28 a0 b3) (29 a0 b3) (30 a0 b3) (31 a0 b3))) (vn ((1 a4 c7) (2 a4 c7) (3 a4 c7) (4 a4 c7) (5 a4 c7) (6 a4 c7) (7 a4 c7) (8 a4 c7) (9 a4 c7) (10 a4 c7) (11 a4 c7) (12 a4 c7) (13 a4 c7) (14 a4 c7) (15 a4 c7) (16 f4 c7) (17 e4 c7) (18 a4 c7) (19 a4 c7) (20 f4 c7) (21 a4 c7) (22 a4 c7) (23 a4 c7) (24 a4 c7) (25 a4 c7) (26 a4 c7) (27 a3 c7) (28 d4 c7) (29 a4 c7) (30 a4 c7) (31 a4 c7))) (va ((1 g3 gs4) (2 g3 gs4) (3 g3 gs4) (4 g3 gs4) (5 g3 gs4) (6 g3 gs4) (7 g3 gs4) (8 g3 gs4) (9 g3 gs4) (10 g3 gs4) (11 g3 gs4) (12 g3 gs4) (13 g3 gs4) (14 g3 gs4) (15 g3 gs4) (16 g3 gs4) (17 g3 gs4) (18 g3 gs4) (19 g3 gs4) (20 g3 gs4) (21 g3 gs4) (22 g3 gs4) (23 g3 gs4) (24 g3 gs4) (25 g3 gs4) (26 g3 gs4) (27 g3 gs4) (28 g3 gs4) (29 g3 gs4) (30 g3 gs4) (31 g3 gs4))) (vc ((1 c2 fs3) (2 c2 fs3) (3 c2 fs3) (4 c2 fs3) (5 c2 fs3) (6 c2 fs3) (7 c2 fs3) (8 c2 e4) (9 c2 e4) (10 c2 fs3) (11 c2 fs3) (12 c2 fs3) (13 c2 e4) (14 c2 d4) (15 c2 df4) (16 c2 d4) (17 c2 fs3) (18 c2 fs3) (19 c2 e4) (20 c2 b3) (21 c2 fs3) (22 c2 fs3) (23 c2 g4) (24 c2 af3) (25 c2 fs3) (26 c2 fs3) (27 c2 fs3) (28 c2 fs3) (29 c2 fs3) (30 c2 fs3) (31 c2 fs3)))))
Separating low from high
The two individual set-limits-low
and set-limits-high
lists are then collected using
loops:
;; Creating a list for just the low set-limits, with consecutive ;; integers as x-values so there are equal number of breakpoint pairs ;; as sets in the set-palette (sll (loop for p in sls collect (list (first p) (loop for s in sm for i from 1 collect i collect (second (nth (1- s) (second p))))))) ;; Creating a list for just the high set-limits, with consecutive ;; integers as x-values so there are equal number of breakpoint pairs ;; as sets in the set-palette (slh (loop for p in sls collect (list (first p) (loop for s in sm for i from 1 collect i collect (third (nth (1- s) (second p)))))))
These will be passed directly to the corresponding keyword
arguments within the make-slippery-chicken
function.
+ The call to make-slippery-chicken
With all of these variables declared, the call to
the make-slippery-chicken
function remains quite
sleek. Only the global variable, title, ensemble, staff groups, and
tempo must be specified explicitly; the remaining keyword arguments
can be passed the variables declared above.
;; Creating the sc object (reeling-trains (make-slippery-chicken '+reeling-trains+ :title "reeling trains" :ensemble '(((fl (flute :midi-channel 1)) (ob (oboe :midi-channel 2)) (cl (b-flat-clarinet :midi-channel 3)) (bn (bassoon :midi-channel 4)) (vb (vibraphone :midi-channel 5)) (pnr (piano :midi-channel 6)) (pnl (piano-lh :midi-channel 7)) (vn (violin :midi-channel 8)) (va (viola :midi-channel 9)) (vc (cello :midi-channel 11)))) :staff-groupings '(4 1 2 3) :set-palette sp :set-map `((1 ,sm)) :set-limits-low sll :set-limits-high slh :tempo-map '((1 (q 72))) ;; The rs palette and map can be taken directly from the rthm-chain ;; object. :rthm-seq-palette (palette rch) :rthm-seq-map rch)))
+ Post-generation placement and editing of marks
With the pitch and rhythm data now generated and stored in
a slippery-chicken
object, the next few post-generating
editing entries are used to apply and manipulate marks in the
piece.
process-events-by-time
As mentioned above, the process-events-by-time
method
is used here to randomly place dynamics and articulations into the
score. The method takes as its two required arguments the name of
the slippery-chicken
object to be processed, and the
name of the function to apply to each event in that object. It is
called here once with the place-dyns
function, and once
with the place-arts
function, both defined above.
;; add random dynamics (process-events-by-time reeling-trains #'place-dyns) ;; add random articulations (process-events-by-time reeling-trains #'place-arts)
remove-extraneous-dynamics
One possible side-effect of placing marks randomly is that the score
may then contain two or more identical dynamics in sequence in the
same part. The remove-extraneous-dynamics
method
resolves this by deleting all consecutive repetitions of a given
dynamic in the same part.
;; remove repeated dynamics (remove-extraneous-dynamics reeling-trains)
rm-marks-from-notes
If the user is not completely satisfied with some of the randomly
placed marks, the rm-marks-from-notes
method can be used
to remove specific marks from specific notes, as is done here.
Since the two user-defined functions for random marks placement use
the random-rep
function and reset the random state each
time, the marks placed, though random, will be identical each time
the piece is generated in the same Lisp environment. This allows the
user to create a list of bar numbers, note numbers, players, and
marks for specific dynamics and articulations to be removed from the
score. In this piece, this list is then passed to
the rm-marks-from-notes
method, using
the first
, second
, third
,
and fourth
functions to retrieve the values for its
arguments from that list.
;; remove specific marks (loop for pm in '((1 1 (cl bn vb pnr pnl vc) s) (2 1 vc ppp) (2 2 (vn vc) s) (2 3 vc ff) (3 1 va p) (3 2 (ob va) s) (3 2 vc fff) (5 3 ob f) (5 2 vn mf) (6 3 bn p) (8 4 ob s) (9 1 fl s) (12 1 vn s) (17 1 ob ff) (17 2 fl ppp) (19 3 vc mf) (20 2 cl s) (26 2 vn s) (26 2 va p) (27 1 bn p) (27 2 va s) (28 3 ob ff) (35 1 vn s) (38 2 bn fff) (42 2 vc f) (44 1 bn s) (47 2 ob mp) (47 3 bn ppp) (51 1 pnr s) (53 1 (fl vb) s) (53 2 (vb vc) s) (53 2 pnl mf) (54 2 vn s) (58 1 vc pp) (61 1 bn s) (61 4 (ob pnr va) (mf fff ppp)) (62 1 ob s) (62 2 va s) (63 2 va s) (65 1 pnr s) (66 1 ob pp) (66 3 ob s) (66 3 fl s) (70 2 fl mf) (72 1 va p) (73 2 vn s) (74 2 vn fff) (75 3 cl pp) (76 2 ob s) (77 2 ob s) (85 1 bn s) (85 3 vb ff) (85 4 bn s) (85 5 cl p) (85 5 bn a) (85 5 vc a) (86 3 (bn vc) (pp fff)) (86 4 vc s) (86 5 vb f) (87 2 ob s) (90 2 vb mf) (90 3 bn ff) (96 2 ob pp) (97 1 fl pp) (98 4 vn mf) (100 1 ob mf) (101 1 fl p) (101 1 vn s) (101 2 vn p) (102 1 vn s) (103 1 ob s) (103 1 vc mf) (105 1 vn s) (105 1 vb mp) (106 2 va fff) (106 2 vc s) (106 3 vb s) (106 3 vn f) (106 5 vb ff) (106 5 pnl ff) (106 5 vc p) (110 2 vn s) (110 3 va s) (110 3 vn mp) (110 2 va ppp) (111 2 ob fff) (114 2 vn fff) (114 2 ob mp) (114 3 pnr ppp) (116 3 vb mp) (118 2 pnr s) (118 2 vn mf) (120 2 va s) (120 2 cl pp) (120 3 pnr mp) (125 3 fl f) (125 3 va p) (125 3 va mp) (131 2 vn mf) (132 1 fl mp) (134 1 va ppp) (137 1 vn s) (137 2 fl fff) (138 2 pnr p) (139 1 va mp) (139 3 vn p) (142 2 vn s) (143 1 vn f) (144 1 pnr ff) (151 3 ob f) (153 1 bn s) (156 1 pnl s) (156 2 bn fff) (156 3 vb pp) (156 3 pnl fff) (156 3 va f) (156 5 vc a) (156 6 vb mf) (158 3 pnr ff) (163 2 fl p) (163 2 vn mp) (163 3 ob fff) (166 1 (fl va) (p mf)) (166 2 ob p) (167 1 cl f) (169 3 ob mp) (170 2 vn mf) (172 3 pnr s) (172 3 vn pp) (173 1 pnr s) (173 1 vb ff) (173 3 vn mp) (175 4 pnr mf) (175 4 vn ff) (175 4 va p) (176 2 cl s) (178 2 pnr pp) (178 2 va ff)) do (rm-marks-from-notes reeling-trains (first pm) (second pm) (third pm) (fourth pm)))
Adding diminuendos and crescendos
Two more loops are used in a similar manner to add diminuendo and
crescendo marks to the score. The lists created specify the player
ID, the bar and note numbers where the mark is to begin, and the bar
and note numbers where the mark is to end. These are then passed to
the add-mark-to-note
method in conjunction with
the dim-beg
/cresc-beg
and dim-end
/cresc-end
marks to insert
those marks into the score.
;; add diminuendo marks (loop for pdcr in '((pnr 2 2 4 1) (pnl 2 4 4 1) (vn 2 2 2 3) (bn 5 1 5 2) (bn 14 1 14 2) (fl 17 1 18 1) (ob 26 1 27 2) (fl 26 2 27 2) (ob 54 1 54 3) (vn 81 1 81 2) (ob 103 1 103 2) (bn 102 2 103 2) (vb 102 2 103 2) (va 107 1 107 2) (va 118 1 118 3) (va 169 1 169 3) (vn 172 2 172 4) (va 176 1 176 2)) do (add-mark-to-note reeling-trains (second pdcr) (third pdcr) (first pdcr) 'dim-beg) (add-mark-to-note reeling-trains (fourth pdcr) (fifth pdcr) (first pdcr) 'dim-end)) ;; add crescendo marks (loop for pdcr in '((va 2 2 4 3) (va 10 1 10 3) (cl 14 1 14 2) (va 17 2 18 1) (va 26 1 27 1) (fl 35 1 35 3) (ob 48 1 48 3) (vb 53 1 53 3) (pnl 54 1 54 2) (pnr 57 1 57 3) (fl 65 2 66 2) (bn 67 1 67 2) (va 66 3 67 1) (fl 77 3 78 1) (va 83 1 83 2) (fl 93 1 94 1) (va 93 2 94 1) (va 98 3 98 5) (pnr 106 1 106 3) (ob 110 1 110 3) (fl 142 2 143 2) (cl 145 1 145 3) (cl 164 1 164 2) (vb 170 1 170 2) (vn 175 3 175 5) (vc 176 1 176 2)) do (add-mark-to-note reeling-trains (second pdcr) (third pdcr) (first pdcr) 'cresc-beg) (add-mark-to-note reeling-trains (fourth pdcr) (fifth pdcr) (first pdcr) 'cresc-end))
One starting dynamic for all parts
A final dynamic is added to the first note of all players' parts to produce an initial dynamic for all players in the piece:
;; make the first dynamic forte (loop for p in '(fl ob cl bn vb pnr pnl vn va vc) do (add-mark-to-note reeling-trains 1 1 p 'f))
auto-slur
The last kind of mark to be added here is
the slur. The auto-slur
method automatically
places slur marks into the parts of the specified players. By default
it slurs all notes between two rests, slurring over accents and first
removing all staccatos from the specified part.
Since accents and staccatos have been already placed in this piece,
the optional keyword arguments over-accents
and rm-staccatos
for this method are both set
to NIL
. This will result in slurs that always end prior
to an accent, and in staccato markings being left in the
score. Unwanted staccato markings were removed in the above steps,
however, thus leaving the score as desired.
;; auto-slur (auto-slur reeling-trains '(fl ob cl bn vb pnr pnl vn va vc) :over-accents nil :rm-staccatos nil)
+ Consolidating durations
The last post-generation editing method to be called here prior to
the output methods is map-over-bars
. This method can be
used in conjunction with a second method or function to apply that
second function to every bar in a specified range of a specified
player's part.
The method takes as its arguments the slippery-chicken
object to be processed, two integers indicating the first and last
bars to process within that object, and the ID of the player whose
part is to be changed. If the end bar and player arguments are set
to NIL
, all bars from the start bar to the end of the
piece in all players' parts will be processed.
The use of map-over-bars
in this piece applies
the consolidate-notes
method to every bar of the piece
in all players' parts. It is important that this be called prior to
the auto-slur
method, as
the consolidate-notes
method may remove a number of
event
objects during the consolidation process.
;; consolidate sounding durations (map-over-bars reeling-trains 1 nil nil #'consolidate-notes)
+ Output
With the music generated, the marks placed, and the durations
consolidated, the final step is to generate the MIDI and score
output for the composition. This is done in the same manner as
described in the other tutorials, with the addition of the
specification of the font-size for the CMN output, and the
indication that both the CMN and LilyPond scores are to be in C. For
the scope of this piece, as well, the auto-clefs
function has been disabled, as the set-limits-
values
have been specified such that clef changes are not necessary.
;; output (midi-play reeling-trains :midi-file "/tmp/reeling-trains.mid") (cmn-display reeling-trains :file "/tmp/reeling-trains.eps" :size 14 :auto-clefs nil :in-c t) (write-lp-data-for-all reeling-trains :auto-clefs nil :in-c t)))