Project 2

Due Sep 26, Peer grading due Oct 3



Envelopes are very important in sound synthesis. Envelopes are the primary way to “shape” sounds from various sound sources so that the sounds do not suddenly pop on and off or blast at a constant level.

You should have learned to use both “pwl” and “env” for envelopes in the on-line lessons. Hint: Look up “pwl” and “env” in the Nyquist Reference Manual and pay attention to their behaviors under different stretch environments.

Composition Programming

The following code creates a short score and plays it when you click the “F2” button in the Nyquist IDE (maybe your keyboard F2 key will work too):

variable *ascore* =
      {{0 1 {note pitch: c2 vel: 50}}
       {1 0.3 {note pitch: d2 vel: 70}}
       {1.2 0.3 {note pitch: f2 vel: 90}}
       {1.4 0.3 {note pitch: g2 vel: 110}}
       {1.6 0.3 {note pitch: a2 vel: 127}}
       {1.8 2 {note pitch: g2 vel: 100}}
       {3.5 2 {note pitch: d2 vel: 30}}
       {3.7 2 {note pitch: d4 vel: 70}}
       {3.9 2 {note pitch: d5 vel: 70}}
       {4.1 2 {note pitch: d6 vel: 50}}
       {4.9 0.5 {note pitch: g4 vel: 40}}
       {5.2 2.5 {note pitch: a4 vel: 30}}}
function f2() play timed-seq(*ascore*)

variable *bscore* ; to be initialized from *ascore*

function f3() play timed-seq(*bscore*)

Create a file named instr.sal, paste this code in, and try it.

Define an Instrument

Your first task is to define a new instrument, also in the file instr.sal, that multiplies the output of a table-lookup oscillator by an envelope. The instrument should consist of

  1. a table created as shown in the lectures using the build-harmonic function and containing at least 8 harmonics,
  2. an oscillator (use osc), and
  3. an envelope.

The instrument should be encapsulated in a function named simple-note that at least has the two keyword parameters seen in *ascore* (pitch: and vel:). The vel: parameter represents velocity, a loudness control based on MIDI key velocity which ranges from 1 to 127. Convert MIDI key velocity to amplitude using the vel-to-linear function (see the Nyquist Reference Manual). Your simple-note instrument function should satisfy these requirements:

  • starting time is of course the default start time from the environment,
  • duration is determined by the stretch factor in the environment, e.g. simple-note(pitch: c2, vel: 100) ~ 2.6 should have a duration of 2.6s,
  • maximum amplitude is proportional to vel-to-linear(vel), where vel is the value of the vel keyword parameter,
  • pitch is controlled by the pitch keyword parameter, which gives pitch in “steps”, e.g. C4 produces middle-C.
  • Any “instrument” function should return a sound (and not play the sound).

Play *ascore* with your instrument

To show off your instrument, transform *ascore* using one of the score-* functions to use your instrument rather than note. (It is your task to become familiar with the score-* functions and find the one that replaces function names.) Assign the transformed score to *bscore* at the top level of instr.sal; for example, you might have something like the following in your code:

set *bscore* = function-to-transform-a-score(*ascore*, perhaps-other-parameters)

You may add one or more additional functions to instr.sal as needed.

Now, F3 (as defined above) should play the altered score, and it should use your simple-note instead of the built-in piano note function note. The resulting sound should demonstrate your instrument playing different pitches, durations, and velocities.

Record Tapping

Record a short period of rhythmic tapping sound (<10 sec) and save as tapping.wav. This can be your own tapping or some other source.

Tap Detection

Download the file, which contains code, a test sound, and some documentation.

You will now create a new file named tapcomp.sal, which will use the tapping.wav data to create a composition. In tapcomp.sal, load the given code tap-detect.sal to detect a list of tap times and tap amplitudes of tapping.wav. Refer to the HTML documentation for tap-detect and inspect the tap-detect code to get an idea of how you can generate a score based on this code.

Convert Taps to Score

Add your own functions to tapcomp.sal to map the list of tap times and amplitudes into a Nyquist score named *tapscore* that plays your instrument from instr.sal (so of course, you should have the statement load "instr.sal" to define your instrument). When you are done, loading tapcomp.sal should immediately run your code and produce *tapscore*, which should be a direct 1-to-1 translation of the taps to a score.

NOTE 1: Do NOT use score-gen. Instead, you must use loop and list primitives to construct a score. You may use the linear-to-vel function to convert tap strength to a velocity parameter.

NOTE 2: Note duration is up to you. It fixed, random, or related to the tap inter-onset times.

Make Music

Create between 20 and 40 seconds of music using your code. You can create new scores based on your tapscore (but please do not modify *tapscore*), mix multiple sounds or “tracks,” you can create sounds by other means (as long as at least one “track” is derived according to the recipe above), and you can manipulate your results in an audio editor (again, as long as the tap-driven instrument is clearly heard). Keep all the code for your piece in tapcomp.sal, but do not compute your piece immediately when the code is loaded (at least not in the version you hand in). It may be convenient to use F4 and other buttons in the IDE to run different pieces of your code. E.g. you could add something like this to tapcomp.sal:

function F4() play compute-my-tap-piece(*tapscore*)

Do NOT write any play command or commands to compute your piece at the top-level. E.g. do NOT write something like

play compute-my-tap-piece(*tapscore*)

unless it is inside a function (like F4 above), and the function does not get called when the file is loaded.

Name your composition sound file p2comp.wav (AIFF format is acceptable too.)

Describe Your Intentions

Create a simple ASCII text file p2comp_README.txt or pdf file p2comp_README.pdf with a sentence or two describing your goals or musical intentions in creating p2comp.wav.


Submit files in a zip file to ATutor. The following files should be at the top level in your zip file (you may use .aiff sound files instead of .wav sound files):
instr.sal: A SAL program implementing your table-lookup instrument,
tapping.wav: The recorded taps used as input to tap-detect.sal,
tapcomp.sal: A SAL program to convert tap times to a Nyquist score.
p2comp.wav: Your project 2 composition (at least 20 seconds).
p2comp_README.txt: Optional additional info on your composition.


Since you are reading this, you should now be familiar with Decibels. You can (re)read “The Bell Scale”, “The Decibel Scale (dB),” and “Decibels for Comparing Amplitude Levels” in Loudness Concepts and Panning Laws, but to summarize some important points:

  • Decibels are a unit-less measure of the ratio of power. Each Bel represents a factor of 10.

  • Since power increases with the square of amplitude, a factor of 10 change in amplitude gives a factor of 100 in power, which is 2 Bels (log10(100) = 2), which is 20dB.

  • A very useful number is: A factor of 2 in amplitude is very nearly 6dB.

Remember that 6 dB represents a factor of 2 in amplitude!

Grading Criteria

Here are some things you might want to check before your final submission. Some criteria will be checked automatically. Some will be the basis of peer grading:

  • Your simple-note is as directed, accepts 2 keyword parameters, and has proper pitch, amplitude, time and duration control.
  • You define and convert *ascore* to *bscore* that calls simple-note when instr.sal is loaded.
  • tapping.wav contains at least 10 taps.
  • *tapscore*, generated by loading tapcomp.sal, should be a valid Nyquist score. (You can use score-print to see it nicely formatted.)
  • Your submission should be complete and anonymous.
  • The audio should have acceptable quality (no clipping or unintended distortion, no bad splices, adequate overall level, etc.)