Link Search Menu Expand Document

Guitar Hero

Being a client of linear collections to implement interfaces.1

ed Workspace

Table of contents

  1. Guitars and sound
  2. GuitarString
    1. Method summary
    2. Implementation details
  3. Guitar and GuitarHero
  4. Guitar37
    1. Keyboard
    2. Implementation details
  5. Grading
  6. Reflection
  7. Submission

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.

Sampling from Karplus-Strong

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.

White noise

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.

Karplus-Strong update

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 constant StdAudio.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 an IllegalArgumentException
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 an IllegalArgumentException. 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 the nextDouble method in the Java Random class to generate random values, not Math.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.

Piano 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-210101112

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

Reflection

Create a new file reflection.txt and write a paragraph-long reflection answering the following questions (along with anything else you find appropriate):

  1. What did you learn this week?
  2. What did you enjoy in the course this week?
  3. What did you find challenging or frustrating this week?
  4. What did you find particularly helpful for your learning this week?

Submission

Submit GuitarString.java, Guitar37.java, and reflection.txt to Grade-It!

  1. Kevin Wayne. 2012. Guitar Heroine. http://nifty.stanford.edu/2012/wayne-guitar-heroine/