Stroke n' Spray: Composing by Function Call

If you know how to call a function then you can start composing interesting algorithmic music by using two functions -- stroke and spray -- to generate sound for you.

Think about these two functions as different ways to "paint" notes: stroke generates musical events in sequential order while spray generates musical events using randomness.

To work with these functions you need to download the file "paint.scm" and load that file into Grace:

[fileicon]Download paint.scm

You can load "paint.scm" into Grace using the File>Load File... menu item or using SAL's load command:

SAL's load command. Replace "/path/to/" with the appropriate path on your machine.

load("/path/to/paint.scm")

The following is an explanation of each function's parameters.


[Function]
stroke( ... )

Generates MIDI events in sequential order. Most parameters allow lists of values to be specified, in which case elements from the list are played in left-to-right order. Lists containing fewer elements than the total number of notes generated will automatically loop around from the last element back to the first until the algorithm stops.

stroke supports the following named parameters:

len: number
The number of MIDI events to generate. If the value is not specified it defaults to the length of the longest list of values specified to the function. If a number is specified then that many events will be output, regardless of list lengths.
end: number
An optional end time (in beats) after which no more events will be generated. This is an alternate way to stop the process if len: is not specified. If values for both len: and end: are specified then the process stops as soon as the first condition holds true.
rhy: {number | list}
The amount of time (in beats) to wait between MIDI events. Negative time values are interpreted as musical rests, i.e. events are not output when rests are selected. The default value is .5, or half a beat.
dur: {number | list}
The amount of time (in beats) each MIDI event lasts. The default value is the current rhythm.
key: {number | list}
A MIDI key number or list of key numbers to play. The list can contain sublists of key numbers; in this case each sublist is treated as a chord, i.e. the key numbers in the sublist are performed simultaneously.
amp: {number | list}
A value or list of values between 0.0 and 1.0 for determining the loudness of the MIDI events.
chan: {number | list}
A MIDI channel number (zero based) or list of channel numbers for MIDI events. Channel value 9 will send events to the synthesizer's drum map for triggering various percussion sounds. See General MIDI drum map for more information.
[Function]
spray( ... )

Uses discrete, uniform random selection to generate MIDI events. Most parameters allow lists of values to be specified, in which case elements are randomly chosen from the list each time an event is generated.

spray supports the following named parameters:

len: number
The number of MIDI events to generate. The default value is 1 event.
end: number
See stroke.
rhy: {number | list}
See stroke.
dur: {number | list}
See stroke.
key: {number | list}
A MIDI key number or list of key numbers to play. If a list is specified a key number is randomly selected from the list for each midi event.
band: {number |list}
A number is treated as a half-step range on either side of the current key: value to randomly select the next key number. If a list of intervals is specified then a new interval is randomly selected from the list each time a MIDI event is output and added to the current key number to determine the actual key number that is played. The list can contain sublists of intervals; in this case each sublist is treated as a chord, i.e. the key numbers in the sublist are performed simultaneously.
amp: {number | list}
See stroke.
chan: {number | list}
See stroke.

About sprout

The sprout command starts musical algorithms running. The first argument to the command is the algorithm, or list of algorithms, you want to execute. The second (optional) argument is the start times or list of start times that the algorithms should start running at, where 0 means now. If you provide a list of algorithms and a list of start times then each algorithm will be paired to its corresponding start time in left-to-right order. The (optional) third argument to sprout is a scorefile to write. If a scorefile is specified then the system will run the algorithms as fast as possible and algorithms will generate all their musical output to that file. For example, to achieve the most precise timing you can sprout the examples to Midifiles (instead of out the Midi Port) and then use a Midifile player to play the file. See the comments below on how to do this.

Examples

Piano Phase (Steve Reich)

Download source: [fileicon.png] reich.sal

load("paint.scm")

variable pphase = {64 66 71 73 74 66 64 73 71 66 74 73}

sprout(list(stroke(len: 147, key: pphase, rhy: 0.16666667),
            stroke(len: 150, key: pphase, rhy: 0.16333333)))

;; to write a Midifile add two additional arguments to the 
;; sprout command: a score startime (keep it 0 for now) and 
;; the name (string) of the Midifile to write.

sprout(list(stroke(len: 147, key: pphase, rhy: 0.16666667),
            stroke(len: 150, key: pphase, rhy: 0.16333333)) ,
       0, "test.mid")

Piano part, Liturgie de Cristal (Olivier Messiaen)

Download source: [fileicon.png] messiaen.sal

load("paint.scm")

variable liturgie-talea =
  {1 1 1 .5 .75 .5 .5 .5 .5 .75 .75 .75 .25 .5 .75 1 2 }

variable liturgie-color =
  {{f3 g bf c4 ef b e5}  {f3 g bf c4 e a d5} {f3 af bf df4 ef a d5}
   {f3 af bf df4 ef g c5} {f3 g bf d4 fs b c5} {f3 g bf d4 e a c5}
   {f3 a c4 d g cs5 fs} {f3 g c4 d g b e5} {f3 bf df4 gf e5}
   {f3 b d4 g e5 g} {f3 c4 ef af g5} {f3 cs4 e a g5 b}
   {af3 ef4 gf bf ef5 gf cf6} {af3 ef4 f bf df5 f5 bf5}
   {gf3 df4 af ef af cf6 ef} {gf3 df4 bf d5 f bf d6}
   {a3 c4 d fs bf df5 gf bf df6} {bf3 cs e gs c5 d gs c6}
   {c4 d f a4 cs5 e a} {cs4 e fs bf d5 f} {fs4 g bf d5 fs a}
   {fs4 a b ds5 es gs} {f4 bf d5 e g} {e4 af cs5 d}
   {d4 g b cs5 e} {cs4 f bf b f5} {b3 e4 af bf} {af3 cs4 f g}
   {gf3 cf4 ef f}}

sprout( stroke( len: length(liturgie-talea) * 8 + 14,
               rhy: in-tempo(liturgie-talea, 80),
               key: key(liturgie-color),
               chan: {0 1 2 3}))

;; Midifile version

sprout( stroke( len: length(liturgie-talea) * 8 + 14,
               rhy: in-tempo(liturgie-talea, 80),
               key: key(liturgie-color),
               chan: {0 1 2 3}) ,
       0, "test.mid")

Random Blues (Mike Purfield)

Download source: [fileicon.png] mike.sal

load("paint.scm")

variable blues = {0 3 5 6 7 10 12}

sprout(list(spray(len: 200, dur: .2, rhy: .2, band: {0 3 5},
                  key: 30, amp: 0.35, end: 36),
            spray(len: 160, dur: .2, rhy: {-.2 -.4 .2 .2}, 
                  band: {3 7 6},
                  key: pick({30 42}), amp: 0.5, end: 25),
            spray(len: 180, dur: .2, rhy: {-.2 .2 .2}, band: blues,
                  key: pick({42 54}), chan: 2, end: 20),
            spray(len: 100, dur: .2, rhy: {-.6 .4 .4}, band: blues,
                  key: 66, amp: 0.4, end: 15),
            spray(len: 200, dur: .2, rhy: .2, band: {0 3 5},
                  key: 30, amp: 0.5, end: 10),
            spray(len: 160, dur: .2, rhy: {-.2 -.4 .2 .2}, 
                  band: {3 7 6},
                  key: pick({30 42}), amp: 0.8, end: 10),
            spray(len: 180, dur: .2, rhy: {-.2 .2 .2}, band: blues,
                  key: pick({42 54}), chan: 2, end: 10),
            spray(len: 100, dur: .2, rhy: {-.6 .4 .4}, band: blues,
                  key: 66, amp: 0.6, end: 10),
            spray(len: 100, dur: .2, rhy: .2, band: blues,
                  key: 66, amp: 0.4, end: 6) ),
        {0 5 10 15 37 37 37 37 47}
        )

More Examples

Alex Bielen

Ming-Ching Chiu

James Bunch

Taylor Briggs