Envelope

Envelopes, together with the choice of a sound (loaded as an AudioSample), establish a sound’s individual quality or timbre.

Envelope objects are used to help shape the sound of AudioSample instruments used to play notes.   They utilize four adjustable parameters:

Figure-6.25-Graph-of-ADSR-envelope
  • Attack models the beginning of the sound, i.e, how long it takes for the sound to begin sounding fully, once it has been started.  It is the initial build up of the sound.
  • Decay models the initial loss of energy after the Attack, i.e., how long it takes for the sound to reach its normal level, after the maximum of the initial attack.
  • Sustain models how long the sound maintains its normal level.
  • Release models the end of the sound, i.e., how long it takes for the sound to finish sounding, after it has been stopped.

For more information on Envelopes, see here and here.

Creating an Envelope

An envelope is created as follows:

FunctionDescription
Envelope(attackTimes, attackVolumes, delayTime, sustainVolume, releaseTime)Creates a new envelope, with attackTimes (a list of times in milliseconds, relative from the previous time – initially, from start of sound), attackVolumes (a list of sound volumes between 0.0 and 1.0 to be reached at the corresponding attack time, relative to the max volume of a given note, or sound – this is important), delayTime (how many milliseconds, from the last attack time, to reach the sustain volume), sustainVolume (a sound level between 0.0 and 1.0, which will last – no matter how long the note is – until the end of sound), and releaseTime (how many milliseconds it takes, after the end of sound, for it to end – adds more to the end of sound, in a diminishing volume).

For example,

env = Envelope([0, 20, 10], [0.0, 0.8, 1.0], 30, 0.6, 150)

creates an Envelope object env, which may be used to help shape an AudioSample, as follows:

  • Attack has three different times, namely 0, 20, and 10 (in milliseconds from the previous time – the first one, from the start of sound).  These correspond to volumes 0.0, 0.8, and 1.0 (where 1.0 means max sound level, and 0.0 means silence).  In other words, the sound will start at 0.0 volume, then after 20 milliseconds will increasingly reach 0.8 volume (relative the max volume of the note being played), then 1.0 (max volume) after 10 more milliseconds. 
  • Decay of 30 milliseconds (from the last attack value) to reach the sustain volume.
  • Sustain volume of 0.6 (relative to max sound).
  • Release of 30 milliseconds (from when the sound is stopped). In other words, sound will take 150 milliseconds to come to die down, after the end of the note.

Once an Envelope env has been created, the following functions are available:

FunctionDescription
env.getAttackTimesAndVolumes()Retrieve both lists of attack times and volumes of envelope env.
env.setAttackTimesAndVolumes( attackTimes, attackVolumes )Sets both lists of attack times and volumes of envelope env.
env.getSustainVolume()Retrieve the sustain volume of envelope env.
env.setSustainVolume( volume )Set the sustain volume of envelope env.
env.getDelayTime()Retrieve the delay time of envelope env.
env.setDelayTime( time )Set the delay time of envelope env.
env.getReleaseTime()Retrieve the release time of envelope env.
env.setReleaseTime( time )Set the release time of envelope env.

Example

The following demonstrates how to use an envelope to shape the sound of a loop:

# audioLoopWithEnvelope.py
#
# Demonstrates how to create a loop using an audio file and an envelope.
# This may be used for ambient or drone backdrops of sound to build on.
#

from music import *

loopTimes = 4

# load audio instruments
a1 = AudioSample("moondog.Bird_sLament.wav")

# define an envelope
e1 = Envelope([20, 60, 100, 10], [0.0, 0.8, 1.0, 0.8], 30, 0.6, 30)
#e1 = Envelope()

# create musical data structure
score = Score()

part1 = Part(0, 0)

phrase1 = Phrase()

# create musical data
pitches   = [A4] * loopTimes
durations = [4.12152] * loopTimes   # duration is in seconds (assuming 60bpm)
volumes   = [120] * loopTimes
pannings  = [0.5] * loopTimes
lengths   =  durations              # force playing length to be same as noted duration!

phrase1.addNoteList(pitches, durations, volumes, pannings, lengths)

part1.addPhrase(phrase1)

score.addPart(part1)

# play it!
#Play.audio( score, [a1] )
Play.audio( score, [a1], [e1] )