Play.code()

Play provides various functions to play musical material stored in Note, Phrase, Part, and Score objects.

Play.code() executes one or more arbitrary Python functions to play musical material stored in Note, Phrase, Part, and Score objects. Specifically, when a note is to be played, a Python function is called instead.

FunctionDescription
Play.code(material, listOfFunctions)Play musical material using provided functions. Material may be a Note, Phrase, Part, or Score. listOfFunctions should contain one function per channel being used.

Provided functions should expect seven parameters – frequency, start, duration, velocity, channel, instrument, panning. These are as follows:

  • frequency – the frequency of this note (a float, in Hertz – e.g., 440.0)
  • start – the start time of this note (in milliseconds)
  • duration – the duration of this note (in milliseconds)
  • velocity – the volume of this note (0-127)
  • channel – the channel of this note (0-15)
  • instrument – the instrument of this note (0-127)
  • panning – the panning of this note (0.0 – left, to 1.0 – right)

NOTE: You need to provide a Python function for each channel used in the musical material. For example, if only one channel is being used (i.e., channel 0), you only need to provide one function. See example below.

It is OK to reuse the same function for more than one channel. If so, simply repeat it more than once in the function list. Order matters – channel 0 is associated with the first function provided (i.e., all notes with channel 0 will be sent to this function); channel 1 is associated with the second function, and so on.

NOTE: Play.code() functions could do various things (e.g., animation, send OSC messages, etc.), as well as play the actual note, if desired. This is very powerful… it gives a musical score the power of a Turing Machine.

For example, here is a variation on furElise.py in Ch. 3:

# furElise.py
# Generates the theme from Beethoven's Fur Elise...
# and demonstrates how to execute arbitrary code for each note.
 
from music import *
 
# create musical material...
# theme has some repetition, so break it up to maximize economy
# (also notice how we line up corresponding pitches and durations)
pitches1   = [E5, DS5, E5, DS5, E5, B4, D5, C5]
durations1 = [SN, SN, SN, SN, SN, SN, SN, SN]
pitches2   = [A4, REST, C4, E4, A4, B4, REST, E4]
durations2 = [EN, SN, SN, SN, SN, EN, SN, SN]
pitches3   = [GS4, B4, C5, REST, E4]
durations3 = [SN, SN, EN, SN, SN]
pitches4   = [C5, B4, A4]
durations4 = [SN, SN, EN]
 
# create an empty phrase, and construct theme from the above motifs
theme = Phrase()  
theme.addNoteList(pitches1, durations1)
theme.addNoteList(pitches2, durations2)
theme.addNoteList(pitches3, durations3)
theme.addNoteList(pitches1, durations1)  # again
theme.addNoteList(pitches2, durations2)
theme.addNoteList(pitches4, durations4)
 
# create a test function to demonstrate execution of arbitrary code
def testFunction(frequency, start, duration, velocity, channel, instrument, panning):
    
   # NOTE: If needed, you may convert frequency (in Hertz) back to MIDI pitch
   # Returns pitch (0-127) and pitch bend (ranges from -8191 to +8192 - 0 means no pitch bend)
   # pitch, pitchBend = frequencyToPitch(frequency)

   # output provided parameters - to demonstrate that we got them!!
   print frequency, start, duration, velocity, channel, instrument, panning
     
   # now, sound the actual note - to demonstrate that we can (if we wish)
   if frequency != REST:   # play notes (but not RESTs)
      
      Play.note(frequency, 0, duration, velocity, channel, panning)

   # NOTE:  In here, you can do anything using the above parameters (including
   # drawing graphical objects, creating animations, sending OSC messages, etc.
   # Sky (or Python) is the limit.

# and execute it, using the notes from theme above
Play.code(theme, [testFunction])