Guitar Hero
Being a client of linear collections to implement interfaces.1
Table of contents
In this assignment, we will write a program to simulate plucking a guitar string using the Karplus–Strong algorithm. This algorithm played a key role in the emergence of electronic sound synthesis.
Guitars and sound
Before getting started with this assignment, watch the following video from 1:47–6:24 for an introduction to digital audio.
When a guitar string is plucked, the string vibrates and creates sound. The length of the string determines its fundamental frequency of vibration. We model a guitar string by sampling its displacement (a real number between -1/2 and +1/2) at N equally spaced points in time, where N equals the sampling rate (44,100Hz) divided by the fundamental frequency of the string, rounded to the nearest integer. We store these displacement values in a structure that we will refer to as a ring buffer.
Plucking a string moves it and gives it energy. The excitation of the string can contain energy at any frequency. We simulate the excitation by filling the ring buffer with white noise. In other words, we set each of the N sample displacements to a random real number between -1/2 and +1/2.
After the string is plucked, the string vibrates. The pluck causes a displacement which spreads wave-like over time. The Karplus-Strong algorithm simulates this vibration by maintaining a ring buffer of the N samples: for each step the algorithm deletes the first sample from the ring buffer and adds to the end of the ring buffer the average of the first two samples, scaled by an energy decay factor of 0.996.
GuitarString
Implement a GuitarString
class that models a vibrating guitar string of a given frequency. GuitarString
instances will need to keep track of a ring buffer.
Represent the ring buffer as a queue using only a single LinkedList<E>
Java object declared with the interface type Queue<E>
. Use only the following Queue<E>
methods:
add
remove
isEmpty
size
peek
Once the GuitarString
class has been implemented, run GuitarHero
using GuitarLite
and listen to the sound!
Method summary
public GuitarString(double frequency)
- Constructs a
GuitarString
of the given frequency. It creates a ring buffer of the desired capacity N (sampling rate divided by frequency, rounded to the nearest integer), and initializes it to represent a guitar string at rest by enqueueing N zeros. The sampling rate is specified by the constantStdAudio.SAMPLE_RATE
. If the frequency is less than or equal to 0 or if the resulting size of the ring buffer would be less than 2, this method should throw anIllegalArgumentException
public GuitarString(double[] init)
- Constructs a
GuitarString
and initializes the contents of the ring buffer to the values in the array. If the array has fewer than two elements, this constructor should throw anIllegalArgumentException
. This constructor is used only for testing purposes. public void pluck()
- Replaces the N elements in the ring buffer with N random values between -0.5 inclusive and +0.5 exclusive, i.e.
-0.5 <= value < 0.5
. Use thenextDouble
method in the JavaRandom
class to generate random values, notMath.random
. public void tic()
- Apply the Karplus-Strong update once (performing one step) by deleting the sample at the front of the ring buffer and adding to the end of the ring buffer the average of the first two samples multiplied by the energy decay factor (0.996). Use a public constant for the energy decay factor.
public double sample()
- Returns the current sample (the value at the front of the ring buffer).
Implementation details
Remember to include this import declaration at the beginning of the class: import java.util.*;
A testing program is provided for verifying that GuitarString
has the basic functionality required. The testing program will not check for correct/efficient use of the queue or exception handling.
Normally, we encourage writing a single constructor and using the this(...)
notation to have one constructor call another. That won’t be possible for the GuitarString
class because the two constructors are completely different.
For documenting the GuitarString
class, it’s difficult to know what constitutes an implementation detail versus what is okay to discuss in client comments. Assume that a client of the GuitarString
class is familiar with the concept of a ring buffer and the Karplus-Strong algorithm. The fact that we are implementing it as a queue is an implementation detail, so don’t mention it but do discuss the ring buffer itself and the changes that each method makes to the state of the ring buffer. This might include describing the movement of values from the front of the ring buffer to the back of the ring buffer.
Guitar and GuitarHero
This section describes the important supporting files and how to run the program. There are no deliverables for this section.
In the next part of the assignment, we’ll build on the GuitarString
class to write a class that keeps track of a musical instrument with multiple strings. There could be many possible guitar objects with different kinds of strings. As a result, we introduce a Guitar
interface that each guitar object implements.
public interface Guitar {
public void playNote(int pitch);
public boolean hasString(char key);
public void pluck(char key);
public double sample();
public void tic();
public int time();
}
The interface allows a client to specify what to play in one of two ways. A client can specify exactly which note to play by calling the playNote
method passing it a pitch. Pitch is specified as an integer where the value 0 represents concert-A and all other notes are specified relative to concert-A using what is known as a chromatic scale. Not every value of pitch can be played by any given guitar. If it can’t be played, it is ignored.
Additionally, a client can also specify a character that indicates which note to play by calling the pluck
method. Different guitar objects will have different mappings from characters to notes. The interface includes a method called hasString
that is paired with pluck that lets a client verify that a particular character has a corresponding string for this guitar. The pluck
method has a precondition that the key is legal for this guitar.
The Guitar
interface also has methods for getting the current sound sample (the sum of all samples from the strings of the guitar), to advance the time forward one tic
, and a method for determining the current time (the number of times tic
has been called). The sample GuitarLite
class implements the Guitar
interface. GuitarLite
has only two strings: “a” and “c”.
Guitar37
Implement the Guitar37
class, which is a 37-string implementation of the Guitar
interface.
Because the GuitarLite
class uses just two strings, it stores them as two separate fields. Since our Guitar37
instrument has 37 strings, use an array of strings instead. Each of the operations defined in the Guitar
interface needs to be generalized from using two specific strings to using an array of strings. For example, the sample method returns the sum of the current samples. GuitarLite
does this by adding together two numbers. Guitar37
will have to use a loop to find the sum of all 37 samples.
Once Guitar37
has been implemented, change GuitarHero
to use Guitar37
instead of GuitarLite
and play the full instrument!
Keyboard
The Guitar37
class has a total of 37 notes on the chromatic scale from 110Hz to 880Hz. Clients can play the guitar by using their computer’s keyboard.
This use of keyboard characters imitates a piano keyboard, making playing songs a little easier for people used to a piano keyboard. The white keys are on the qwerty and zxcv rows while the black keys on the 12345 and asdf rows of the keyboard.
This mapping is stored as the KEYBOARD
constant at the top of the Guitar37
class.
public static final String KEYBOARD = "q2we4r5ty7u8i9op-[=zxdcfvgbnjmk,.;/' ";
The i-th character of the string corresponds to a frequency of 440 × 2(i - 24) / 12, so that the character “q” is 110Hz, “i” is 220Hz, “v” is 440Hz, and “ “ (space) is 880Hz.
A pitch of 0 is supposed to correspond to concert-A, which corresponds to the character “v” at index 24 in the KEYBOARD
string. We can convert from a pitch value to an index into the string by adding 24 to the pitch value.
Key | “q” | “2” | “w” | “e” | … | “v” | … | ”/” | ”’” | ” “ |
---|---|---|---|---|---|---|---|---|---|---|
Pitch | -24 | -23 | -22 | -21 | … | 0 | … | 10 | 11 | 12 |
Implementation details
Note that the GuitarLite
class is not well documented. Also, it does not handle illegal keys or implement the time
method. Guitar37
should include complete comments. The pluck
method should throw an IllegalArgumentException
if the key is not one of the 37 keys it is designed to play (as noted above, this differs from the playNote
method that simply ignores notes it can’t play).
Grading
Use the testing program Test37
in the test37
folder. To use it, copy the Guitar37
class to this folder, run it, and then compare against the sample output produced using the Output Comparison Tool.
In terms of external correctness, the GuitarString
and Guitar37
classes must provide all of the functionality and satisfy the constraints described above. In terms of style, we will be grading on use of comments, good variable names, consistent indentation and good coding style to implement these operations.
- Commenting errors
- Implementation details included in comments for a class or its public methods.
- Readability errors
- Method errors
- Class design errors
- Miscellaneous errors
- Unnecessarily inefficient or otherwise redundant code. For example, constructing a new object on every iteration of a loop when it could have been constructed once before the loop.
- Not using interfaces when possible to refer to variables, parameters, and return values.
- Not using generic types properly. For example, manipulating a
Stack
instead of aStack<Integer>
.
Reflection
Create a new file reflection.txt
and write a paragraph-long reflection answering the following questions (along with anything else you find appropriate):
- What did you learn this week?
- What did you enjoy in the course this week?
- What did you find challenging or frustrating this week?
- What did you find particularly helpful for your learning this week?
Submission
Submit GuitarString.java
, Guitar37.java
, and reflection.txt
to Grade-It!
Kevin Wayne. 2012. Guitar Heroine. http://nifty.stanford.edu/2012/wayne-guitar-heroine/ ↩