Commodore‎ > ‎BASIC‎ > ‎Keywords‎ > ‎

ENVELOPE

Keyword Abbreviation Token (hex) Version(s) Classification
ENVELOPE E{Shift+N} FE 0A 7.0 Command and Statement

 
  Syntax   
ENVELOPE toneNum [ , [ attack ] [ , [ decay ] [ , [ sustain ] [ , [ release ] [ , [ waveform ] [ , pulseWidth ] ] ] ] ] ]
 
Parameters Type Legal Value(s) Default Value Note(s)
toneNum Unsigned Byte 0 ~ 9 T parameter of PLAY
attack Unsigned Byte 0 ~ 15* old value *Due to a bug, values up to 255 are accepted
decay Unsigned Byte 0 ~ 15* old value *Due to a bug, values up to 255 are accepted
sustain Unsigned Byte 0 ~ 15* old value *Due to a bug, values up to 255 are accepted
release Unsigned Byte 0 ~ 15* old value *Due to a bug, values up to 255 are accepted
waveform Unsigned Byte 
  1. Triangle
  2. Sawtooth
  3. Rectangle
  4. Noise
  5. Triangle + Ring
old value Ring with ((voice - 1 -1) mod 3) +1.
pulseWidth Unsigned Integer 0 ~ 4095 old value Only used if waveform is 2 (rectangle).
 
 
  Purpose  
State management.  Define a PLAY "instrument" (toneNum).

 
  Remarks  
ENVELEOPE allows you to define an "instrument" to be used with PLAY.  This allows you to set several SID parameters for any voice used in a PLAY command/statement.  (The main parameter of a sound, frequency, is set by a "note" in PLAY.)  Although ENVELOPE provides several parameters to customize your "instrument", real musical instruments have complex waveforms that can not be immitated with only a handful of parameters.  So don't expect your "instruments" to sound much like anything real.
 
The toneNum is the only required parameter.  It is a number referring to a virtual "musical instrument" which may be used in subsequent PLAY statement(s) with a "T" parameter.  On power-up, BASIC defines the 10 toneNums shown in the following table.  Unfortunately, the values are not reset when a program is RUN, so any program that uses PLAY should use ENVELOPE before any PLAY statement.  Otherwise the last-defined "instrument" will be in effect and thus PLAY'd music may sound wrong.  Also, there is bug in the BASIC power-up routine: the low byte of each pulseWidth is never set, so the pulseWidth will be slightly random depending on the powe-up value of uninitialized RAM (therefore the table shows a range of values for pulseWidth).  On a related note, BASIC provides no way to read any of the parameters assigned to a toneNum.  To do so, you would need to PEEK one of several secret variables.
 
In any case, the pulseWidth only applies to a rectangular waveform, and the equivalent Duty Cycle (described later) is shown if applicable.  Importantly, any Duty Cycle greater than 50% is equilavant to another less than 50% and is shown where applicable.  The time-period parameters (described below) are shown in the table using the average of NTSC and PAL values; if you need more precision, see tables for those specific parameters.  Strangely, the "drum" (toneNum 3) has a non-zero sustain; percussion instruments should normally use zero.
 
 
toneNum Description attack decay sustain release waveform pulseWidth
range
Duty Cycle
range
0 Piano 0: 2ms 9: 750ms 0: 0% 0: 6ms 2: rectangle 1536 ~ 1791 37.5% ~ 43.7%
1 Accordian 12: 1000ms 0: 6ms 12: 80% 0: 6ms 1: sawtooth 0 ~ 255
2 Calliope 0: 2ms 0: 6ms 15: 100% 0: 6ms 0: triangle 0 ~ 255
3 Drum 0: 2ms 5: 168ms 5: 33.33% 0: 6ms 3: noise 0 ~ 255
4 Flute 9: 250ms 4: 114ms 4: 26.67% 0: 6ms 0: triangle 0 ~ 255
5 Guitar 0: 2ms 9: 750ms 2: 13.33% 1: 24ms 1: sawtooth 0 ~ 255
6 Harpischord 0: 2ms 9: 750ms 0: 0% 0: 6ms 2: rectangle 512 ~ 767 12.5% ~ 18.7%
7 Organ 0: 2ms 9: 750ms 9: 60% 0: 6ms 2: rectangle 2048 ~ 2303 50.0% ~ 56.2% 
43.8% ~ 50%
8 Trumpet 8: 100ms 9: 750ms 4: 26.67% 1: 24ms 2: rectangle 512 ~ 767  12.5% ~ 18.7%
9 Xylophone 0: 2ms 9: 750ms 0: 0% 0: 6ms 0: triangle 0 ~ 255
 
The attack, decay, and release values specify a machine-specific time period.  The attack period uses the following scale (three signifigant digits).  The attack determines the time it takes for the amplitude (volume) of a voice to rise from its current value (typically zero = silence) to peak chip amplitude (see VOL) when a "note" in a PLAY statment is first "struck".
attack NTSC Time PAL Time
0 1.96 ms 2.04 ms
1 7.84 ms 8.16 ms
2 15.7 ms 16.3 ms
3 23.5 ms 24.5 ms
4 37.3 ms 38.8 ms
5 54.9 ms
57.1 ms
6 66.7 ms 69.4 ms
7 78.4 ms 81.6 ms
8 98.0 ms 102 ms
9 245 ms 255 ms
10 490 ms 510 ms
11 784 ms 816 ms
12 980 ms 1020 ms
13 2940 ms 3060 ms
14 4900 ms 5100 ms
15 7840 ms 8160 ms
 
The decay and release values both use the following machine-specific time periods, although they have different purposes (the table below shows three significant digits).  The decay sets the time for the amplitude of a voice to drop from the peak value to its sustain level (see below).  Note the amplitude of the voice might never reach the peak value if the "note" ends very quickly (relative to the attack time period).  Note the amplitude of the voice might not have yet "decayed" to the sustain level if the "note" ends very quickly (relative to the sum of attack and decay time periods).  In those cases, sustain is irrelevant.  
 
Assuming the sustain level is reached (see below), the voice will continue at that (relative) amplitude until the "note" of the PLAY statement ends, and then its amplitude will drop to zero (silence) over a period determined by release.  Generally, percussion instruments (drums) and some string instruments (piano and harp) will have a zero sustain level, and thus release is typically irrelevant (unless the "note" ends quickly as described above).  For non-percussion instruments (any non-zero sustain), a large release value will cause the next "note" in a PLAY statement to "blend" with the last; this is because the amplitude of the last note would have hardly dropped at all when the next "note" begins (assuming both notes are using the same voice).
decay
release
NTSC Time PAL Time
0 5.88 ms 6.12 ms
1 23.5 ms 24.5 ms
2 47.1 ms 49.0 ms
3 70.6 ms 73.5 ms
4 112 ms 116 ms
5 165 ms
171 ms
6 200 ms 208 ms
7 235 245 ms
8 294 ms  306 ms
9 735 ms 765 ms
10 1470 ms 1530 ms
11 2350 ms 2450 ms
12 2940 ms 3060 ms
13 8820 ms 9180 ms
14 14700 ms 15300 ms
15 23500 ms 24500 ms
 
The sustain parameter sets the primary amplitude (loudness) of a "note" relative to the current master volume (see VOL).  It is a simple fraction of sutain divided by fifteen (i.e., voice_amplitude = sustain * master_volume / 15).  I've provided a table showing this in percent.  It is used mostly by non-percussion instruments that can sustain a "note" indefinately, like a trumpet (well, a human would run out of breath eventually).  For such instruments, a "note" that is PLAY'd will remain at this relative volume level after the attack and decay time periods until the "note" ends, at which time the release phase begins (see above).  If the "note" plays for a very short duration (see attack and decay above), the voice may never reach the sustain (relative) amplitude.  Most precussion and some string instruments can't sustain the volume of a "note" indefinately; these typically use a zero sustain value.
sustain relative
volume
0 0.000% (silence)
1 6.667%
2 13.33%
3 20.00%
4 26.67%
5 33.33%
6 40.00%
7 46.67%
8 53.33%
9 60.00%
10 66.67%
11 73.33%
12 80.00%
13 86.67%
14 93.33%
15 100.0%
 
The previous four parameters (attack, decay, sustain, and release) define the changes in amplitude for a "note" that is PLAY'd.  They should have a value between 0 and 15, but due to sloppy coding, any integer between 0 and 255 is accepted.  Values greater than 15 will only use the lower 4 bits.  Thus, effective_parameter = given_parameter AND 15.
 
The last two parameters, waveform (and perhaps pulseWidth) control the timbre of the sound, just like a "C" played on flute will sound different than a "C" played on a trumpet (even though they have similar amplitude envelopes).  For waveform, a value of 0 produces a triangle wave which is a poor digital imitation of a sine wave, and sounds similar to some wind instruments, like flutes (it sounds rather "soft", unlike a real sine wave which sounds very "full").  A value of 1 produces a sawtooth waveform and sounds like some brass instruments, like trumpets.  A value of 2 produces a rectangular waveform and is quite versatile because you can control its duty-cycle (described below).  A value of 3 produces a noise waveform which is mostly useful for sound effects like ocean waves and explosions, but might be useful for a precussion instrument like a snare drum.  The final value of 4 is quite special, it produces ring-modulation.
 
With ring-modulation, a voice will produce a triangle wave that is modulated with the frequency of the prior voice (or the last voice if the first is using ring-modulation).  This adds harmonic frequencies and is usefull for bell-like instruments.  However the "other voice" should normally not be played; its frequency (wheather it is playing or not) will affect the harmonics of the voice using ring-modulation.  This makes it difficult to use in a PLAY statement, unless the frequency of the "other voice" can remain fixed.  Assuming you don't want to hear the "other voice", this reduces the number of available voices from 3 to 2. The SID chip has a special bit that can be used to "hide" the output of voice 3, so one possibility is to use voice 3 as the "other voice" and voice 1 as the one using ring-modulation.  This way you can change the frequency of both voices easily with PLAY.  However BASIC provides no way to enable the "voice 3 off" feature.
 
If a rectangular waveform is selected, the final parameter, pulseWidth species the duty-cycle by this equation: dutyCycle = 100% * pulseWidth / 4096.  A pulseWidth of 2048 thus produces a 50% duty-cycle which is a special case of the rectangular waveform known as a square wave.  Using different values for pulseWidth allows a nice variety of sound timbres.  At 50% the sound quality is at its "fullest" sounding like some cross between a stringed instrument and a horn... the classic digital synthesizer sound.  As the duty-cycle moves away from 50%, the sound quality becomes more "reedy" and quieter.  You will hear nothing when the duty-cycle reaches 0% or 100%.  Values below 50% sound the same as their "complement" above 50%; so a 40% duty-cycle sounds the same as a 60% duty-cycle (they are both 10% away from 50%).  This is because the human ear is, by itself, indifferent to phase shifts (a 40% duty-cycle waveform is a 180-degree phase-shifted version of a 60% duty-cycle waveform).  A pair of ears can descriminate between phase shifts in some cases, but only relative to the same sound.
 
ENVELOPE will store the pulseWidth (if given) even if the waveform does not use it.
 
If toneNum is omitted, or any specified parameter has an invalid expression, SYNTAX ERROR is generated.  If any parameter is not numeric, TYPE MISMATCH ERROR occurs; you may manually convert a string with VAL.  Floating-point numbers are converted automatically with INT.  If the resulting parameter is not a Legal Value (see table above) then ILLEGAL QUANTITY ERROR occurs.
 
 
Examples:
ENVELOPE 3, 0,5,0,5, 3 : REM better 'drum' (3), ADSR=0/5/0/5 (no sustain), noise(3)

READY.
ENVELOPE 0, ,,,, ,512 : REM set 'piano' (0) pulse-width to 512 (12.5% duty-cycle)

READY.
ENVELOPE 9, ,,,, 1 : REM change 'xylophone' to sawtooth waveform

READY.
 
  Compare With  
 
  Contrast With  
  See Also  

© H2Obsession, 2014
Comments