;; atonal-melody.sal -- example code for generating random atonal melodies ;; Jorge Sastre ;; 2014 ;; ;; Earlier versions of the code were used to generate melodies for the ;; following pieces written by Jorge Sastre: ;; - "Déjà vu" (2013), for Flute, Viola, Cello Piano and Electronics ;; performed at the concert "Computer Music from Carnegie Mellon" ;; on May 2, 2013, recording available at ;; https://soundcloud.com/jsastre/deja-vu ;; - "Oscura Luz" (Obscure light, 2014) for Orchestra, performed by ;; Carnegie Mellon Philharmonic Orchestra at Carnegie Music Hall ;; (Pittsburgh, USA) on March 5th, 2014, recording ;; https://soundcloud.com/jsastre/oscura-luz ;; - "Bacuum" (mixture of "Baco" and "vacuum", 2014), for Flute, Oboe, ;; Clarinet, Percussion, Piano, Violin, Viola and Cello ;; commissioned by CulturArts (Generalitat Valenciana, Spain) for ;; the XXXVI International Festival of Contemporary Music ENSEMS. ;; Premiered on May 17, 2014 at the Teatro Principal of Valencia ;; by Espai Sonor Ensemble. ;; - "Patrick" for piano premiered by Pablo Amorós at kresge Theatre ;; on Oct. 31, 2014 ;; - "Patrick", the chamber opera premiered by Daniel Arnaldos (tenor) ;; and Grant Braider (baritone) with Daniel Curtis conducting ; at CMU Alumni Concert Hall on Nov. 23, 2014. ;; ;; Jorge Sastre ;; Visiting Scholar from Universitat Politècnica de València (Spain) ;; R. Dannenberg's Computer Music Group ;; Computer Science Department ;; Carnegie Mellon University ;; December 2014 ;; Function atonal-melody() produces random atonal melodies with certain ;; adjustable parameters: ;; atonal-melody(start-note: c3, max-pitch: c7, min-pitch: a1, ;; speed: 1, chan: 0, rhythm-pat-type: 1, ;; score-length: 50, rest-notes: 3, length-changes: 20, ;; length-changes-random-part: 10, medium-speed-note-rate: 2) ;; startnote: first note of the melody (it is recommended to randomize it, ;; see example of use) ;; maxpitch: maximum pitch of the melody to be produced (limit it to the ;; max pitch of the concrete instrument or to the desired maximum ;; pitch of the melody) ;; minpitch: minimum pitch of the melody to be produced ;; speed: (must be >0) set to 1 for a medium speed of the notes (minimum ;; note value: 7 tuplet of 16ths), set to 2 for double speed (half ;; the medium speed note durations), set to 0.5 for half speed, etc. ;; chan: midi channel (to be able to separate the multiple voices when ;; opening the midi file in an editor) ;; rhythm-pat-type: if 1 then more regular rhythm pattern (values ;; equivalent to eight, quarter, half and whole notes), else ;; more irregular values ;; score-length: number of notes (and rests) to produce ;; length-changes + random(length-changes-random-part): number of notes ;; after which where there will be a possible change of octave (but ;; there might be changes of octave equally because of the random ;; chosen intervals), and other changes (see below parameters: ;; introducing rests and some medium speed valued notes at the ;; end of each cycle) ;; rest-notes: To introduce some rests at the end of each cycle of ;; length "length-changes + random(length-changes-random-part)" ;; medium-speed-note-rate: It applies the medium speed note durations ;; to medium-speed-note-rate notes at the end of each cycle of ;; length "length-changes + random(length-changes-random-part)" ;; (if a negative value it does not do anything) ;; The use example saves a midi file (atonal.mid) that can have one or ;; several voices. Open it in your music editor or sequencer with a ;; proper quantization (if it has to be played by humans) and using ;; separation by midi channels if you want to separate the different ;; voices in different tracks or staffs. In Finale: open the midi file, ;; select track-to-staff list, autoset to channels, eliminate split ;; points if Finale creates any (click on the Split word and select ;; Split none on the window that opens), select the desired quantization ;; settings, select in the score manager the desired instuments, ;; preferably with the Garritan sounds better than the midi default ;; ones, put your desired dynamisc, slurs, articulations, etc., and ;; playback. ;; See example files: ;; http://www.cs.cmu.edu/~rbd/algocompbook/jorge-sastre/Atonal%20aleatoric%20trio%20-%20Jorge%20Sastre%20-%20Nyquist.mid ;; http://www.cs.cmu.edu/~rbd/algocompbook/jorge-sastre/Atonal%20aleatoric%20trio%20-%20Jorge%20Sastre%20-%20Nyquist.pdf ;; http://www.cs.cmu.edu/~rbd/algocompbook/jorge-sastre/Atonal%20aleatoric%20trio%20-%20Jorge%20Sastre%20-%20Nyquist.wav load "pianosyn" ;; Piano sound selected to preview the result function atonal-melody(start-note: c3, max-pitch: c7, min-pitch: a1, speed: 1, chan: 0, rhythm-pat-type: 1, score-length: 50, rest-notes: 3, length-changes: 20, length-changes-random-part: 10, medium-speed-note-rate: 1) begin with pitch-pat = make-random(list(0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 6, 6, 6, 7, 8, 9, 10, 10, 11, 11, 12, 13, 13)), ; includes major seventh and minor 9th intervals, ; and higher probability to 2nds and minor thirds..., and less to ; fourths, fifths and octaves oct-pat = make-copier(make-random(list(-12, 0, 12), for: 1), repeat: 12), phrase-pat-regular = make-random( list(make-cycle(list(i)), ;eighth make-cycle(list(s, s)), ;eighth equivalent make-cycle(list(st, st, st)), ;eighth equivalent make-cycle(list(q)), ;quarter make-cycle(list(i, i))), ;quarter equivalent make-cycle(list(s, s, s, s)), ;quarter equivalent make-heap(list(s, s, i)), ;quarter equivalent make-heap(list(id, s)), ;quarter equivalent make-cycle(list(it, it, it)), ;quarter equivalent make-cycle(list(i, i, i, i)), ;half equivalent make-cycle(list(st, st, st, st, st, st)), ;half equivalent make-heap(list(it, st, st, st, st)), ;half equivalent make-cycle(list(0.2, 0.2, 0.2, 0.2, 0.2)), ;tuplet five 16ths make-heap(list(0.4, 0.2, 0.2, 0.2)), ;equivalent to tuplet five 16ths make-cycle(make-copier(list(1.0 / 7.0), repeat: 7)), ;tuplet: seven 16ths make-cycle(list(h)), ;half make-heap(list(id, id, i)), ;half equivalent make-heap(list(id, id, s, s)), ;half equivalent make-heap(list(id, sd, sd, s, s)), ;half equivalent make-heap(list(sd, sd, sd, sd, i)), ;half equivalent make-cycle(list(w))), ;whole phrase-pat-nonregular = make-random(list(make-cycle(list(i)), ;eighth make-cycle(list(s)), ;16th make-cycle(list(st, st)), make-cycle(list(q)), ;quarter make-cycle(list(qd)), ;dotted quarter make-cycle(list(i, i, i))), make-cycle(list(s, s, s)), make-heap(list(s, s, id)), make-heap(list(id, id)), make-cycle(list(i, i, i, i, i)), make-cycle(list(it, it, it)), make-cycle(list(st, st, st, st, st)), make-heap(list(it, st, st)), make-cycle(list(0.2, 0.2, 0.2, 0.2)), ;tuplet five 16ths make-heap(list(0.4, 0.2)), ;equivalent to tuplet five 16ths make-cycle(make-copier(list(2.0 / 7.0), repeat: 7)), ;tuplet seven 8ths make-cycle(list(h)), ;half make-cycle(list(h)), ;half (increasing probability to have a half) make-heap(list(id, i)), make-heap(list(id, id, s)), make-heap(list(id, sd, s, s)), make-heap(list(sd, sd, i)), make-heap(list(sd, sd, sd)), make-heap(list(id, s, sd, sd, sd, i)), make-heap(list(id, id, id)), make-heap(list(id, id, id)), make-heap(list(i, s, s, sd, s)), make-cycle(list(i, i, s, s, s, sd)), make-cycle(list(w))), ;whole rhythm-pat-regular = make-cycle(phrase-pat-regular), rhythm-pat-nonregular = make-cycle(phrase-pat-nonregular), pitch = start-note, counter = length-changes + random(length-changes-random-part), rhythm-pat = #?(rhythm-pat-type = 1, rhythm-pat-regular, rhythm-pat-nonregular) exec score-gen(save: quote(my-atonal-melody), score-len: score-length, pre: progn(setf(pitch, #?(counter = 0, pitch + next(oct-pat) + next(pitch-pat) * (random(2) * 2 - 1), pitch + next(pitch-pat) * (random(2) * 2 - 1))), setf(pitch, #?(pitch > max-pitch, start-note + random(10) - 5, pitch)), setf(pitch, #?(pitch < min-pitch, start-note + random(10) - 5, pitch)), setf(counter, #?(counter = 0, length-changes + random(length-changes-random-part), counter - 1))), ; apply the medium speed note durations to ; medium-speed-note-rate notes each time the counter ; goes to zero (counter < medium-speed-note-rate): ioi: #?(counter < medium-speed-note-rate, next(rhythm-pat), next(rhythm-pat) / speed), ; introduce some rests at the end of each cycle: pitch: #?(counter < rest-notes, NIL, pitch), ; midi channel separates multiple ; voices when opening the midi file in an editor: chan: chan) end begin ;; Creation of one atonal melody for the right hand of the Piano ;; using the range: c4-c7 exec atonal-melody(start-note: g5 + random(12), max-pitch: c7, min-pitch: c4, speed: 1, chan: 0, rhythm-pat-type: 2, score-length: 50, rest-notes: 3, length-changes: 20, length-changes-random-part: 10, medium-speed-note-rate: 3) exec score-play(my-atonal-melody) ; preview the melody with a piano sound ;; Write the midi file atonal.mid. Open it in your music editor or ;; sequencer with a proper quantization (if it has to be played by ;; humans) and separate by midi channels if you want to ;; separate the different voices in different tracks/staffs: exec score-write-smf(my-atonal-melody, "atonal-melody.mid") ;; ;; Create several atonal melodies to be played together ;; with random start notes using a loop and being able to ;; separate them by midi channel: exec atonal-melody(start-note: g5 + random(12), max-pitch: c7, min-pitch: c4, speed: 1, chan: 0, rhythm-pat-type: 2, score-length: 50, rest-notes: 3, length-changes: 20, length-changes-random-part: 10, medium-speed-note-rate: 3) set atonal-material = my-atonal-melody loop ;; add melodies for a Clarinet and a Bassoon ;; (below we add some randomness to the start notes) with start-note-list = list(c4, g3), max-desired-pitch-list = list(g6, g4), min-desired-pitch-list = list(e3, bf1), speed-list = list(1, .5), ; to make the bassoon melody slower ; both clarinet and basoon more regularly than flute: rhythm-pat-type-list = list(1, 1), ;; less notes to the basoon since its note duration values are ;; approx. half those of the clarinet: score-length-list = list(50, 25), rest-notes-list = list(2, 1), ; more rests in the clarinet melody ;; since the basoon has double note durations, we set the ;; changes to half the clarinet value, and both to the double ;; of the flute value so that their cycles are bigger length-changes-list = list(20, 10), ;; since the basoon has double note durations, we set the ;; random part of the changes to half the clarinet value length-changes-random-part-list = list(10, 5), ;; some notes at medium speed in the basoon and no one in ;; the clarinet, since the clarinet has already used medium ;; speed (speed = 1): medium-speed-note-rate-list = list(-1, 3) for k from 0 below 2 ; add two more simultaneous atonal melodies: exec atonal-melody(start-note: nth(k, start-note-list) + random(6), max-pitch: nth(k, max-desired-pitch-list), min-pitch: nth(k, min-desired-pitch-list), speed: nth(k, speed-list), chan: k + 1, rhythm-pat-type: nth(k, rhythm-pat-type-list), score-length: nth(k, score-length-list), rest-notes: nth(k, rest-notes-list), length-changes: nth(k, length-changes-list), length-changes-random-part: nth(k, length-changes-random-part-list), medium-speed-note-rate: nth(k, medium-speed-note-rate-list)) set atonal-material = score-merge(atonal-material, my-atonal-melody) end ;; preview the simultaneous melodies with a piano sound: exec score-play(atonal-material) ;; write the midi file atonal.mid. Open it in your music editor or ;; sequencer with a proper quantization (if it has to be played by ;; humans) and using separation by midi channels to separate the ;; different voices in different tracks/staffs exec score-write-smf(atonal-material, "atonal-simultaneous-melodies.mid") end