Play

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

There are three options:

  • Play.midi() – play musical material using the MIDI synthesizer.
  • Play.audio() – play musical material using audio files as instruments.
  • Play.code() – execute arbitrary Python functions based on musical material. 

Play.midi() – use MIDI synthesizer

The first function, Play.midi(), is used to play musical material stored in Note, Phrase, Part, and Score objects via the Java MIDI synthesizer.

FunctionDescription
Play.midi(material)Play musical material through the Java synthesizer (material may be a Note, Phrase, Part, or Score).

The other Play functions are more advanced, and are intended for building interactive musical instruments.

Play.noteOn(pitch, volume, channel)Starts pitch sounding.  Specifically, it sends a NOTE_ON message with pitch (0-127), at given volume (0-127 – default is 100), to played on  channel (0-15 – default is 0) through the Java synthesizer.
Play.noteOff(pitch, channel)Stops pitch from sounding.  Specifically, it sends a NOTE_OFF message with pitch (0-127), on given channel (0-15 – default is 0) through the Java synthesizer.  If the pitch is not sounding on this channel, this has no effect.
Play.note(pitch, start, duration, volume, channel)Plays a note with pitch (0-127) to be sounded after start milliseconds, lasting duration milliseconds, at given volume (0-127 – default is 100), on  channel (0-15 – default is 0) through the Java synthesizer.
Play.allNotesOff()Stops all notes from sounding on all channels.

You can also make global changes interactively on instrument, volume, panning, and pitch bend.

FunctionDescription
Play.setInstrument(instrument, channel)Sets a MIDI instrument (0-127 – default is 0) for the given channel (0 – 15, default is 0).  Any notes played through channel will sound using instrument.
Play.getInstrument(channel)Returns the MIDI instrument (0-127) assigned to channel (0 – 15, default is 0).
Play.setVolume(volume, channel)Sets the global (main) volume (0-127) for this channel (0-15)  This is different from the velocity level of individual notes – see Play.noteOn().
Play.getVolume(channel)Returns the global (main) volume (0-127) for this channel (0-15).
Play.setPanning(position, channel)Sets the global (main) panning position (0-127) for this channel (0-15)  The default position is in the middle (64).

NOTE: Global panning does not affect the panning of a score being played through Play.midi() or Play.audio().

Play.getPanning(channel)Returns the global (main) position (0-127) for this channel (0-15).
Play.setPitchBend(bend, channel)Sets the pitch bend for this channel (0-15 – default is 0) to the Java synthesizer object. Pitch bend ranges from -8192 (max downward bend) to 8191 (max upward bend).  No pitch bend is 0 (this is the default).
Play.getPitchBend(channel)Returns the current pitch bend for this channel (0-15 – default is 0).

Play.audio() – use audio files as instruments

You may also play music using AudioSamples – external audio files as instruments.

This is done using the Play.audio() function.

FunctionDescription
Play.audio(material, listOfAudioSamples)Play musical material using the provided AudioSamples as instruments. Material may be a Note, Phrase, Part, or Score.
Play.audio(material, listOfAudioSamples, listOfEnvelopes)Play musical material using the provided AudioSamples as instruments with corresponding envelopes. Material may be a Note, Phrase, Part, or Score.
Play.audio(material, listOfAudioSamples, listOfEnvelopes, loopAudioSamples)Play musical material using the provided AudioSamples as instruments, with corresponding envelopes, and indicate if AudioSamples should be looped, if they are too short to play complete notes (default is False). Material may be a Note, Phrase, Part, or Score.

There should be at least as many audio samples as channels being used. Same for envelopes – if provided. It is OK to reuse audio samples (or envelopes) more than once inside these lists.

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

# furElise.py
# Generates the theme from Beethoven's Fur Elise...
# using Moondog's "Bird's Lament" audio sample as instrument
# for rendering sound.

from music import *

a = AudioSample("moondog.Bird_sLament.wav", G4)   # load an audio file

# 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)

# play it

# Play using the MIDI synthesizer
#Play.midi(theme)        

# Play using audio file as instrument
Play.audio(theme, [a])

# Create an envelope to soften above audio instrument
#e = Envelope(attackTimes = [5, 10, 30, 50], attackVolumes = [0.1, 0.3, 0.5, 1.0], delayTime = 25, sustainVolume = 0.7, releaseTime = 250)
#Play.audio(theme, [a], [e])   # and play it 

# Same, but loop audio file, if too short for a note
#Play.audio(theme, [a], [e], True)

The following Play audio functions are also available:

FunctionDescription
Play.audioNote(pitch, start, duration, audioSample, velocity, panning, envelope, loopAudioSample)Starts pitch sounding at the given time (in milliseconds), for duration (in milliseconds), using the given audio sample, at pitch (0-127), at given velocity (0-127 – default is 127), with given panning (default uses the global panning set with setPanning(), with envelope (default is None), indicating whether to loop audio sample, if too short (default is False)).
Play.audioOn(pitch, audioSample, velocity, panning, envelope, loopAudioSample)Starts pitch sounding immediately, using the given audio sample, at given pitch (0-127), at given velocity (0-127 – default is 127), with given panning (default uses the global panning set with setPanning()), with envelope (default is None), indicating whether to loop audio sample, if too short (default is False)).
Play.audioOff(pitch, audioSample, envelope)Stops pitch from sounding. If the pitch is not sounding via this audio sample, this has no effect. Optional envelope should be the same as the one provided in corresponding Play.audioOn().
Play.audioNote(pitch, start, duration, audioSample, velocity, panning, envelope)Plays a note with pitch (0-127) to be sounded after start milliseconds, lasting duration milliseconds, using a given audio sample at given velocity (0-127 – default is 127), with a given panning (default uses the global panning set with setPanning()) and a given envelope (if no envelope is given, a default is used).
Play.allAudioNotesOff()Stops all notes from sounding on all audio samples.

It is not necessary to use Envelopes with Audio Samples – they are optional. For more information, see Envelope.


Play.code() – execute arbitrary code

You may also execute arbitrary Python functions, using music notes in a Score (Part, or Phrase) as triggers. Whenever a note is to be played, a Python function is called instead. This could be used do a number of things (e.g., animation, sending OSC messages, etc.), as well as playing the actual note, if desired. This is very powerful… gives a musical score the power of a Turing Machine.

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

  • start – the start time of this note (in milliseconds)
  • duration – the duration of this note (in milliseconds)
  • pitch – the pitch of this note (a float, in Hertz), e.g., 440.0)
  • 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)

Similarly to Play.audio() which accepts lists of AudioSamples, associated with (parallel to) channels, Play.code() expects a list of functions, each of which is associated with a specific channel – in the order provided.

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 test(start, duration, pitch, velocity, channel, instrument, panning):
   
   # output provided parameters to demonstrate we got them!!!
   print pitch, duration, velocity, channel, instrument, panning
   
   # now, for the fun of it, also sound the actual note (to demonstrate that we can)
   if pitch != REST:   # play notes (but not RESTs)
      Play.note(pitch, 0, duration, velocity, channel, panning)
   
# and execute it, using the notes from theme above
Play.code(theme, [test])