CS 312 - Week 8.3 Class
CS 312 Audio Programming Winter 2020

Table of Contents

Final Project Proposal - due week 9.2

Submit your Final Project proposal to me by email before class 9.2.

FinalProjectIdeas_Requirements.html

8.3 Class

Wavetables

When developing audio software or hardware there is always a trade-off between size and time. Hardware and software are limited by processor speed and the amount of memory available. Most audio processing software is done offline where real time issues are not important. Recording and performance software requires nearly instantaneous response between pressing a key down and hearing the sound. There will always be some lag or latency between user interaction and audible results. The following quote is from Acceptable Latency Values written in 2005. Most of today's performance software tries to keep latency under 3 ms.

Acceptable Latency Values
Here are some thoughts on acceptable values for different recording purposes:

 * Vocals: This is the most difficult example, because anyone listening to
their vocals in 'real time' will have headphones on, and therefore have
the sounds 'inside their head'. A latency of even 3ms can be
disconcerting in these conditions.

 * Drums & Percussion: I suspect most drummers will prefer to work with
latencies of 6ms or under, which should provide an 'immediate' response.

 * Guitar:  Electric guitarists generally play a few feet from their
stacks, and since the speed of sound in air is roughly a thousand feet
per second, each millisecond of delay is equivalent to listening to the
sound from a point one foot further away. So if you can play an electric
guitar 12 feet from your amp, you can easily cope with a 12ms latency.

 * Keyboards Even on acoustic pianos there's a delay between your hitting
a key and the corresponding hammer hitting the string, so a smallish
latency of 6ms ought to be perfectly acceptable to even the fussiest
pianists. Famously, Donald Fagen and Walter Becker of Steely Dan claimed
to be able to spot 5ms discrepancies in their performances, but the vast
majority of musicians are unlikely to worry about 10ms, and many should
find a latency of 23ms or more perfectly acceptable with most sounds,
especially pads with longer attacks.

Imagine writing software for a MIDI keyboard controller with 88 keys that plays a band limited sawtooth wave. If you used the Fourier Series to compute a band limited sawtooth every time a key was pressed down you might be hard pressed to achieve real time response not to mention allowing the mouse and keyboard to remain functional while playing the note.

Some possible solutions for the band limited sawtooth might be:

  • Store 88 wav file samples of each note in memory and then play the sample by reading the wav file. That eliminates recomputing the Fourier Series every time at the expense of greatly increasing the memory storage requirements.
  • Store a smaller number of band limited samples based on the number of harmonics used share samples between several piano keys within a given pitch range. That would reduce the storage requirements but you'd have to scan the samples at different rates to match the pitch of the key pressed.
  • Store one period of the waveform at 1 Hz and scan the waveform at different phase increments to match the pitch of the key pressed. Because many of the phase increments fall in between samples you need to compute what the value of that sample would have been based on its location between its lower and upper actual sample neighbors. This is the method used by many hardware keyboards with built in sounds and is the topic of hw831_wavetables.
Sample based libraries

There are many commercial sample based libraries available for use with Digital Audio Workstations (DAWs) as plug-ins. The soundtracks of TVcommercials, shows and independent films can be and are being done on the computer using sample libraries. Orchestral sample libraries range in price from $100 to $14,000. The $14,000 library is probably still cheaper than hiring a professional orchestra and recording studio and the library can be used for more than one project.

Recorded samples of real musical instruments generally have an initial attack portion, a longer sustained portion in the middle and a decay portion at the end of the sound. The sustained portion often has beginning and ending loop points between which the sound repeats until the performer or software says its finished, at which point the decay portion begins. That way a short duration sample can be extended for several seconds. Sample libraries often contain multiple samples of a single note of a single instrument. For example there might be separate samples for very soft, soft, medium soft, medium, medium loud, loud, and very loud. A violin sample might contain an entire set of samples for different bowing techniques for each note, or for the same note played on different strings.

Wavetable synthesis

Wavetable synthesis uses a phase increment approach similar to what we did for waveforms starting in hw812_gensin_phasor.

The phase_increment formula using the phasor approach is

\[{\text{phase_increment = }}\frac{{2\pi f}}{{FS}}{\text{ = }}2\pi fT\]

where FS is the sampling rate and T is the period of one sample.

The phase_increment formula using a wavetable is

\[phase\_increment{\text{ = }}\frac{{table\_length \bullet frequency}}{{FS}} = table\_length \bullet frequency \bullet T\]

The phasor approach incremented the phase through one rotation around the 2π circumference of the unit circle. When the phase became greater than π it was wrapped around by subtracting 2π.

The wavetable approach increments the phase during one cycle through the length of the wavetable. When the phase exceeds the wavetable length it is wrapped around by subtracting table_length.

Wavetable sample calculation

Because phase increments often compute to fractional sample indices and wavetable samples only exist at integer indices there are three general methods of calculating the sample value. In order of least accurate to most accurate they are:

Truncation
The sample value is rounded down to the nearest integer index using std::floor()
Rounding
The sample value is rounded up or down to the nearest integer index using std::round()
Interpolation
The sample value is proportional to the distance between the left and right adjacent sample values using the following formula from https://en.wikipedia.org/wiki/Linear_interpolation.

\[{\text{y}} = {y_0} + \left( {{x} - {x_0}} \right)*\left( {\frac{{{y_1} - {y_0}}}{{{x_1} - {x_0}}}} \right)\]

The y's are sample values and the x's are sample indices. Subscript 0 is the left neighbor sample and subscript 1 is the right neighbor sample.

Homework 8.3

hw831_wavetables

This assignment creates a 1 Hz sine and stores the sample values in tables. It will illustrate how the shape of a sine wave is affected by the table length. Our tables will be powers of two from \({2^1}{\text{ - }}{2^{12}}\). Setup

cd $HOME312/cs312
mkdir hw83

Download this file that contains most of the Qt GUI code.

hw831_wavetables.zip

Unzip the code.
Copy the hw831_wavetables to your hw83 folder.

hw83100.png

Open the hw831_wavetables.pro file in Qt Creator.

IMPORTANT:
Edit the hw831_wavetables.pro file to set your pathnames to:

  • COMMON
  • LSF
  • QPLOT
  • ULL

    hw83100a.png

    IMPORTANT:
    Set the build folder using the Projects view and then run qmake from the Build menu.

    hw83101.png

Choose Clean All and Run qmake from the Build menu.

You should see these files appear in the Edit panel.

hw83102.png

Build and run the program. You should see this.

hw83103.png

I've implemented the GUI interface for you but have not written any code to make it work. Try clicking some buttons and moving sliders. Not much happens except for a few QMessageBox dialogs.

hw83104.png -— hw83105.png

On the plus side I've written pseudo-code for every function you need to develop and a working version of the application you can download below.

Important:
The application must run locally on a lab machine and not run from your courses folder.

There are two versions of the download.

  • This one will/should run on any lab machine that has Qt installed.

hw831_wavetables_noQtLibs.zip

  • This one will/should run on any Mac with OS 10.14+ that does not have Qt installed. It's much larger because it contains all the Qt libraries necessary to run.

hw831_wavetables_withQtLibs.zip

My hw831_wavetables application usage

  • Click the Generate Table button.
  • Move the Table Size slider. All table sizes are powers of 2 from 2-4096. You can see how the number of samples smooths out the sine wave.
  • Set the Table Size to 8.
  • Click the Truncate button.
  • Move the Amplitude and Frequency sliders.
  • Do the same with the Round, and Interpolate buttons.
Create 440 Hz test tones

Truncate

  • Set the Table Size to 32.
  • Set the Frequency to 1.
  • Click Generate Table. The sine wave looks pretty smooth.
  • Click Truncate. Not so smooth after all.
  • Turn on the 440 Test Tone checkbox.
  • Click Truncate again.
  • Click Save.
  • Name the file 440_32_truncate.wav

Round

  • Turn off the 440 Test Tone checkbox.
  • Click Round.
  • Turn on the 440 Test Tone checkbox.
  • Click Save.
  • Name the file 440_32_round.wav

Interpolate

  • Turn off the 440 Test Tone checkbox.
  • Click Interpolate.
  • Turn on the 440 Test Tone checkbox.
  • Click Save.
  • Name the file 440_32_interpolate.wav

Download and open the three files in Audacity

440_32_truncate.wav.zip

440_32_round.wav.zip

440_32_interpolate.wav.zip

A zoomed in view of one period of each waveform looks like this. Truncate

hw831_trunc32.png

Round

hw831_round32.png

Interpolate

hw831_interpolate32.png

The Audacity Spectrum plots show the aliasing levels present around the 440 Hz peak for each interpolation method.

Truncate
Lots of aliasing.

hw831_trunc32spectrum.png

Round
Less aliasing.

hw831_round32spectrum.png

Interpolate
Pretty good.

hw831_interpolate32spectrum.png

Assignment hw831

Your assignment is too implement code necessary to make your app match my app and your 440Hz test files match the pictures above.

hw832_finalProjectProposal

Submit your final project proposal to me by email before class 9.2. Link at top of page.

Submission

Feel free to email jellinge@carleton.edu on any part of the homework that is unclear to you. Chances are if you have questions other students do too. I will answer those questions by email to everyone in the class. The original sender will remain anonymous. I have tried to provide clues to the homework in the web pages, reading assignments, and labs. Sometimes what seems obvious to me is not obvious to students just learning C++.

Create a folder named hwNN_LastnameFirstname_LastnameFirstname.
Substitute your name and your partner's name for LastnameFirstname_LastnameFirstname.

Remember

  • Boilerplate header at top of every file.
  • Make sure your program compiles before submitting.
  • Programs that compile and produce partially correct output will be graded.
  • You can send notes to me in your homework files by enclosing them in block comments.
  • Programs that do not compile get an automatic F (59%).
  • Submit the homework in only one of the partner's folders.
  • Empty your build or build-debug folders using the command emptyBuildFolder.sh
  • Only include .h, .cpp, Makefiles, CMakeLists.txt
  • Do not include these folders/files
    .git
    .vscode
  • Double check for the above two folders using this command

    ls -a hwNN_LastnameFirstname1_LastnameFirstname2
    # if either .git or .vscode exist in the folder you're submitting remove them with
    # rm -fR .git
    # rm -fR .vscode
    

Hand-in folder contents

/common
├── RtAudio
│   ├── RtAudio.cpp
│   └── RtAudio.h
├── RtMidi
│   ├── RtMidi.cpp
│   └── RtMidi.h
├── hw332_CMidiPacket.cpp
├── hw332_CMidiPacket.h
├── hw411_rand_int.cpp
├── hw411_rand_int.h
├── hw421_CDelayMs.cpp
├── hw421_CDelayMs.h
├── hw422_CAppleMidiSynth.cpp
├── hw422_CAppleMidiSynth.h
├── hw423_CMidiTrack.cpp
├── hw423_CMidiTrack.h
├── hw511_CInstrument.cpp
├── hw511_CInstrument.h
├── libsndfile
│   ├── sndfile.h
│   └── sndfile.hh
└── qcustomplot
    ├── qcustomplot.cpp
    └── qcustomplot.h

/hw83
└── hw831_wavetables
    ├── build-debug
    ├── hw831_testWavs
    │   ├── 440_32_interpolate.wav
    │   ├── 440_32_round.wav
    │   └── 440_32_truncate.wav
    ├── hw831_wavetables.pro
    ├── main.cpp
    ├── mainwindow.cpp
    ├── mainwindow.h
    ├── mainwindow.ui
    ├── waveTables.cpp
    └── waveTables.h

Author: John Ellinger

Created: 2020-03-06 Fri 21:15

Validate