Project 2: Envelopes and Scores
Project 2 due: Monday, February 3, 2025 by 11:59PM Eastern
Peer grading opens: Tuesday, February 4, 2025 by 11:59PM Eastern
Peer grading due: Monday, February 10, 2025 by 11:59PM Eastern
Download
First, download p2.zip which you will need for this project.
Envelopes
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
- a table created as shown in the lectures using the build-harmonic function and containing at least 8 harmonics,
- an oscillator (use osc), and
- 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), wherevel
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. Note that C4 is an example of a step-symbol, which is a global variable that is bound to corresponding step numbers; C4 is bound to 60.
- 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 p2.zip 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
. You must use load "tap-detect.sal"
(e.g. do not specify any path such as load "p2/tap-detect.sal"
), which makes the functions listed in tapcomp.sal
, such as extract-taps
, available in this file. 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.
In particular, note that taptest
does not return a value, unlike extract-taps
. Additionally, note that any changes you make to tap-detect.sal
will remain local and not be available on the autograder; you can assume the autograder has its own copy of tap-detect.sal
.
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. Score event times should match the tap times, and score event :vel
attributes should vary up and down as a function of tap amplitudes. The exact velocity mapping is up to you, and the score event :pitch
property should be generated by any process you choose.
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. It is recommended that your function is iterative and not recursive.
NOTE 2: Note duration and pitch are up to you. Either can be random, cyclical, related to the tap times or inter-onset times, or any other algorithm. But pitches should not all be the same.
Please feel free to refer to the Nyquist Reference Manual for lists and loops.
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
.
In this file, please add consent information for highlighting your composition in class or on the website. Choose True/False for each of the following:
- Share audio: True/False
- Share name: True/False
- Share text for intent and description: True/False
- Share code: True/False
Submission
Submit files in a zip file using the Project tab in 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 totap-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.
Decibels
You have probably already run across the term decibel. Decibels (abbreviated dB) are a unit-less measure of the ratio of power. A bel represents a factor of 10 in power. 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 20 dB.
A very useful number is: A factor of 2 in amplitude is very approximately 6 dB. Remember that 6 dB represents a factor of 2 in amplitude!
We will learn more about amplitude, decibels and loudness later (see Chapter 10 of Introduction to Computer Music).
Grading Criteria
Here are some things you might want to check before your final submission.
- 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 callssimple-note
wheninstr.sal
is loaded. tapping.wav
contains at least 10 taps.*tapscore*
, generated by loadingtapcomp.sal
, should be a valid Nyquist score. (You can usescore-print
to see it nicely formatted.)- Your submission should be complete.
- The audio should have acceptable quality (no clipping or unintended distortion, no bad splices, adequate overall level, etc.)