• No se han encontrado resultados

EL SISTEMA DE JUSTICIA EN UNA SOCIEDAD DEMOCRATICA

In the first example we implement a simple process to play twelve-tone rows.

Example 13-5. Basic row playing.

(definerow1 '(0 1 6 7 10 11 5 4 3 9 2 8)) (definerow2 (invert-row row1))

(definerow3 (retrograde-row row1)) (definerow4 (retrograde-row row2)) (define (ttone1 reps row key beat amp) (process with len = (length row) repeat reps

for i from 0

for p = (mod i len)

for pc = (list-ref row p) ; i mod 12

for k = (+ key pc)

output (new midi :time (now) :duration (* beat 2) :keynum k

:amplitude amp) wait beat))

The ttone1 process plays reps number of events given a row of pitch classes, a

key number offset, a rhythmic beat and an amp loudness factor. The stepping variable i is a counter that increases by 1 each time the process runs. The variable pc is set to the current pitch class at position p in row. Recall that list- ref returns an element from a list at a specified index and that the first element

in a list is always at index 0 and the last element is at index len-1. Our index into row is determined by taking the mod 12 value of i. Although this length is always 12 in our examples we have avoided specifying the value 12 directly so that it is possible to listen to pitch class lists with more or fewer than twelve elements. The mod calculation insures that our index p will always cycle over valid list

positions from 0 to 11 as i continually increases by 1. The key number k for the current event is calculated by adding the value of the pitch class pc to the key offset that was input into the function. The duration of each event is calculated to be 2*beat so that a legato effect is produced no matter what value of beat is specified to ttone1.

Interaction 13-3. Listening to ttone1

cm> (events (ttone1 36 row1 60 .2 .5) "ttone.mid")

"ttone-1.mid" cm>

→ ttone-1.mid

Variation 1

In this next example we make simple variation of ttone1 that plays a

Example 13-6. A pointillistic row.

(define (ttone2 len row key beat amp) (process repeat len

for i from 0

for pc = (list-ref row (mod i 12)) for n = (if (chance? .5)

(+ key 12) (- key 12)) for k = (+ n pc)

output (new midi :time (now) :duration (* beat 2) :keynum k

:amplitude amp) wait beat))

The main difference between this example and the preceding one is that

ttone2 determines a key number k by randomly choosing between values one

octave up or down from the key number input into the function. This has the effect of slightly randomizing the register of the row so that it does not sound quite so mechanical when the row repeats over the course of the process. The transposition value n is chosen by calling the chance? function we defined in

Chapter 7. The expression (if (chance? .5) (+ key 12) (- key 12)) says

that 50% of the time n will be key+12 and 50% of the time it will be key-12.

Interaction 13-4. Listening to ttone1

cm> (events (ttone2 36 row1 60 .2 .5) "ttone.mid")

"ttone-2.mid" cm>

→ ttone-2.mid

Variation 2

The next variation improves on the preceding one by implementing different wait times and controlling the amount of random pointillism that is applied to the row.

Example 13-7. A pointillistic row.

(define (ttone3 len row key beat amp) (process repeat len

for i from 0

for pc = (list-ref row (mod i 12)) for w = (* beat (random 4))

for n = (if (= w 0)

(if (chance? .5) (+ key 12) (- key 12)) key)

for k = (+ n pc)

output (new midi :time (now) :duration (* beat 2) :keynum k

:amplitude amp) wait w))

In Example 13-7 the w stepping variable is set to a random multiple of beat. Recall that the expression (random 4) generates random integers 0 to 3. This

means the wait value w will be either 0 (when random returns 0), beat (when random returns 1), 2*beat or 3*beat. A zero wait value causes the next run time of the process to be the same as its current time in the score. This means that the events generated over separate iterations will sound simultaneously in the score. The last improvement ttone3 makes is to transpose the key number only

in the case of simultaneous notes. This has the effect of preserving some “registeral integrity” of the row's melodic contour while still providing for some variety.

Interaction 13-5. Listening to ttone3

cm> (events (list (ttone3 36 row1 40 .2 .5) (ttone3 36 row1 60 .2 .5)) "ttone.mid" '(0 4)) "ttone-3.mid" cm> → ttone-3.mid

Variation 3

In our final twelve-tone example we modify the process definition to improve sound characteristics in the event that simultaneous instances of the process are running.

Example 13-8. Defining sections and instrumentation.

(define (ttone4 dur row key beat amp chan) (process while (< (now) dur)

for i from 0

for pc = (list-ref row (mod i 12)) for r = (* beat (random 4))

for n = (if (= r 0) (if (chance? .5) (+ key 12) (- key 12)) key) for k = (+ n pc)

output (new midi :time (now) :duration (* beat 2) :keynum k

:channel chan) wait r))

The ttone4 process makes two small modifications that greatly improve the

musicality of the output. The first modification is the addition of the new chan parameter to the function so that the process outputs to a MIDI channel specified by the composer. MIDI channels control which instrument in the synthesizer receives the note on and off messages. When you work with MIDI channels, remember that indexing always starts from 0 in Lisp so MIDI channels in Common Music are numbered from 0 to 15. Since our numbering system is zero-based this allows channel values to be calculated without constantly adding 1 to them.

The second modification to the process alters the way in which the algorithm controls iteration. In all of the preceding examples the processes iterate an exact number of times. In this version, the process iterates for a specified duration of time, regardless of how may iterations the process executes. The conditional clause

while (< (now) dur)

says to run the process as long as the current time of the process is less than the duration specified to the function. As soon as this condition is false the scheduler automatically stops the process.

We now listen to three contrapuntal voices of the same basic process definition, where each version has a different row form, register, instrument, start time and duration in the score. All three processes stop generating events at the same time in the score. Before playing the example be sure to select different MIDI instruments on the first three channels of your synthesizer. Listen to several versions of the example to observe the large scale effects that random selection has on each process.

Interaction 13-6. Playing a little 12-tone etude.

cm> (events (list (ttone4 16 row1 40 .2 .5 0) (ttone4 12 row2 60 .2 .5 1) (ttone4 8 row3 80 .2 .5 2)) "ttone.mid" '(0 4 8)) "ttone-4.mid" cm> → ttone-4.mid

Ghosts

As a final example of algorithmic process definition we look at a more involved definition called ghosts, written by Tobias Kunze. In addition to its interesting

musical properties ghosts also provides examples of most of the action

clauses supported by the process macro. The definition of ghosts requires

auxiliary functions are shown again here in Example 13-9.

Example 13-9. Helper functions for ghosts.

(define (pick-list lst) (let* ((len (length lst)) (pos (random len))) (list-ref lst pos))) (define (pick-range low high) (let ((rng (- high low))) (if (> rng 0)

(+ low (random rng)) 0)))

(define (bpm->seconds bpm) (/ 60.0 bpm))

(define (rhythm->seconds rhy tempo) (* rhy 4.0 (bpm->seconds tempo)))

The ghosts process gets its name from the fact that a short, randomly

generated melody serves as the basis for computing other bits of dependent structure that echo the melody in different ways at larger temporal levels in the piece. ghosts generates the following gestures, each of which depends on

certain tests applied to the characteristics of the main melody:

Temporally stretched versions of some melodic tones are repeated high above the the main melody.

Percussive thumps sometimes accompany the main melody in the low register.

Distant strums accompany the high stretched melody at even larger time scales.

Before looking at the main process we first define the functions that create the dependent gestures used in ghosts.

Example 13-10. Defining gestures for ghosts.

(define (hitone knum at)

;; create a long tone two octave above knum

(new midi :time at

:keynum (+ knum 24) :duration at

:amplitude .5)) (define (thump knum at)

;; make two percussive events below knum

(list (new midi :time at

:keynum (- knum 18)

:duration .05 :amplitude .4) (new midi :time at

:keynum (- knum 23)

(define (riff knum rhy)

;; generate an upward strum of notes

(let ((rate (rhythm->seconds (/ rhy 4) 60))) (process repeat 5

for k from (+ 39 (mod knum 13)) by 13 output

(new midi :time (now) :keynum k :amplitude .3 :duration 10) wait rate)))

The hitone function creates a single midi event two octaves (twenty-four

semitones) above the knum specified to the function. The at parameter serves as both the start time of the new midi event as well as its duration! The effect of

this is to create longer and longer high tones as the ghost process increments

time.

The thump function returns a list of two midi notes, each with a very short

duration. knum is the current main melody note and at is the time at which the thump events are to occur in the score. The key number of the first thump event is always an octave and a tritone lower than the main melody note; the second event is a perfect fourth above that. Since these transpositions are a fixed relationship, the thump events will follow the general melodic contour of the main melody notes to which they are attached.

The riff function defines a process that outputs five rapid events in an

upward arc. knum is the current main melody note and rhy is its metric rhythm value. riff converts this metric rhythm into a wait value that is four times faster

then the main melody rhythm. The first event that riff plays is a transposition of

the main melody key number shifted to lie somewhere within the octave above key number 39 (E-flat in the second octave). Each of the remaining four events will have a key number one minor-9th above the previous event.

We can listen to the gestures of thump and riff in isolation before

proceeding to the main ghosts process definition:

Interaction 13-7. A sample thump and strum.

cm> (events (hitone 60 0) "thump.mid") "thump-1.mid"

cm> (events (thump 60 0) "thump.mid") "thump-2.mid"

cm> (events (riff 60 1/8) "riff.mid") "riff-1.mid"

cm>

→ thump-1.mid

→ thump-2.mid

→ riff-1.mid

The ghosts process generates a main melody in the middle register of the MIDI

keyboard and then sprouts dependent structure above and below the main melody based on tests it applies to the melodic material. Recall that a sprout

sprout instead of output the dependent structures that ghosts generates

reflect current conditions of the process that are actually heard at a much later point in the score.

Example 13-11. The ghosts process.

(define (ghosts) (process repeat 12

for here = (now)

for ahead = (* (+ here .5) 2) for main = (pick-range 53 77) for high? = (>= main 65) for amp = (if high? .6 .4)

for rhy = (pick-list '(1/16 1/8 3/16)) ;; output main melody

output (new midi :time here :keynum main

:duration (rhythm->seconds rhy 60 ) :amplitude amp)

when high?

sprout (hitone main ahead)

and sprout (riff main rhy) at (* ahead 2) when (= rhy 3/16)

sprout (thump main (+ here .5)) wait (rhythm->seconds rhy 60 )))

The here variable holds the current score time returned by now. Ahead is a

future time twice the value of one-half second later than the current time in the score. In other words, as here increases each time the process runs the value of ahead is roughly twice as far in the future. Main is the main key number of the melody randomly set to any key number within a two octave range above key number 53 (F below Middle C). The high? variable is set to either true or false based on a test of the main key number. Recall that arithmetic relations like = are functions that return either true or false. The expression (>= main 65)

returns boolean true if the main key number is greater than or equal to 65 otherwise it returns false. So the high? variable will be true if the main key number was selected from the upper octave in the key number range, otherwise high? will be false. If high? is true then the main melody is played with at an amplitude of .6 otherwise it is played at the softer level of .4.

The last stepping clause sets the rhythm rhy of main melody> to a random choice of either a sixteenth, eight or dotted-eighth value.

The first action clause that ghosts performs is to output a main melody midi

event at the current time in the score. The following clause is a conditional clause that executes two sprout actions only if the high? variable is true. The conditional expression is reduced to one line here to show its important clausal features:

when high? sprout (hitone ...) and sprout (riff ...)

A when clause performs a test and evaluates one or more dependent action

clauses only if the test is true. The and conjunction joins action clauses together

H. Taube 05 Oct 2003

generating a high melodic tone 24 semitones above the main tone and a riff gesture only if the current main tone lies within the upper octave of its register.

The next clause in the process is another conditional clause but this time with only one dependent action:

when (= high 3/16) sprout (thump ...)

The effect of this clause is to only create a thump gesture if the current value of rhy is 3/16, i.e. a dotted-eighth value.

The last clause in ghosts is a wait action clause that increments the priority

time of the process by the current rhythmic value of rhy converted to seconds. Since there is no and conjunction preceding the wait clause it is independent of

the preceding conditional clause, which means that it is evaluated every time the process runs.

We are now ready to listen to ghosts. Generate the score a number of

different times to hear how the non-random dependent gestures track the randomly generated main melody.

Interaction 13-8. Listening to ghosts.

cm> (events (ghosts ) "ghosts.mid") "ghosts-1.mid"

cm> (events (ghosts ) "ghosts.mid") "ghosts-2.mid"

cm>

→ ghosts-1.mid

→ ghosts-2.mid

Chapter Source Code

The source code to all of the examples and interactions in this chapter can be found in the file processes.cm located in the same directory as the HTML file for this chapter. The source file can be edited in a text editor or evaluated inside the Common Music application.

References

Knuth, D.E. (1981). The Art of Computer Programming. Reading: Addison- Wesley.

Previous Contents Index Next

Previous Contents Index Next

14

Etudes, Op. 5: Steve Reich's Piano