The purpose of this assignment is to introduce you to programming with functions and to survey some of the key ingredients of sound synthesis. You will create a library of functions to synthesize sound for an electronic synthesizer.

Building blocks.  Here are some of the sound waves most commonly used in electronic synthesizers:



Digital audio.  In digital audio, we represent a sound wave as an array of real numbers between –1 and +1, with 44,100 samples per second. That is, to represent each of the sound waves above, sample the function 44,100 times per second at the values \(t = \frac{0}{44100}, \frac{1}{44100}, \frac{2}{44100}, \ldots \). If the audio is \(d\) seconds long, you will have a total of \( n = \lceil 44100 \times d \rceil \) samples. Here, \( \lceil x \rceil\) denotes the ceiling function of \(x\), which is the smallest integer greater than or equal to \(x\).

For example, the following diagram illustrates a sine wave (whose frequency is 2048 Hz) for \(d = \frac{1}{512}\) seconds. We represent it digitally as an array of length \( \lceil 44100 \times \frac{1}{512} \rceil = 87\), with sample \(i\) taken at time \(t = \frac{i}{44100}\).

digital audio: sampling a sine wave 44,100 times per second



Manipulating sound waves. Synthesizers produce richer sounds by combining sound waves in different ways. Here are a few simple and important mechanisms.


  1. Synthesizer. Write a program Synth.java that implements a library of synthesizer functions, as described above. To do so, organize your program according to the following public API:
    public class Synth {
    
        // Returns the number of samples for the given duration.
        public static int length(double duration)
    
        // Returns the sine function of given frequency at time t.
        public static double sine(double frequency, double t)
    
        // Returns the square function of given frequency at time t.
        public static double square(double frequency, double t)
    
        // Returns the sawtooth function of given frequency at time t.
        public static double saw(double frequency, double t)
    
        // Returns a sine wave of the specified frequency, amplitude, and duration.
        public static double[] sineWave(double frequency, double amplitude, double duration)
    
        // Returns the square wave of given frequency, amplitude, and duration.
        public static double[] squareWave(double frequency, double amplitude, double duration)
    
        // Returns a sawtooth wave of the specified frequency, amplitude, and duration.
        public static double[] sawWave(double frequency, double amplitude, double duration)
    
        // Returns white noise of the specified amplitude and duration.
        public static double[] whiteNoise(double amplitude, double duration)
    
        // Returns a new array that is the sum of a[] and b[].
        public static double[] add(double[] a, double[] b)
    
        // Returns a new array that is the product of a[] and b[].
        public static double[] multiply(double[] a, double[] b)
    
        // Returns the wave that results from applying an exponential fade
        // to a[] with decay rate lambda.
        public static double[] fade(double[] a, double lambda)
    
        // Tests each public method.
        public static void main(String[] args)
    }
    
    Here is some more information about the required behavior:


    Here are some examples of the expected behavior:

    ~/Desktop/functions> javac-introcs Synth.java
    
    ~/Desktop/functions> jshell-introcs
    ~/Desktop/functions> /open Synth.java
    
    jshell> double[] y = Synth.sineWave(440, 0.25, 5.0)
    jshell> StdAudio.play(y)
    
    
    
    
    jshell> double[] y = Synth.squareWave(440, 0.25, 5.0)
    jshell> StdAudio.play(y)
    
    
    
    
    jshell> double[] y = Synth.sawWave(440, 0.25, 5.0)
    jshell> StdAudio.play(y)
    
    
    
    
    jshell> double[] y = Synth.whiteNoise(1.0, 5.0)
    jshell> StdAudio.play(y)
    
    
    
    jshell> StdAudio.play(Synth.fade(y, 10.0))
    
    
    
    
    jshell> double[] wave1 = Synth.sineWave(220.0, 1.0, 10.0);
    jshell> double[] wave2 = Synth.sineWave(  1.0, 1.0, 10.0);
    jshell> double[] tremolo = Synth.multiply(wave1, wave2)
    jshell> StdAudio.play(tremolo)
    
    
    
    


  2. Client. In this open-ended exercise, you will create your own sound wave by calling various functions in Synth and creating additional functions of your own.

    Here are the requirements to earn full credit:

    You are welcome to use one of the following concrete ideas or do something entirely on your own:


Submission. Submit the Java files Synth.java and MySound.java. Also submit a MySound.txt file if your MySound.java program reads from standard input. Finally, submit a readme.txt file and answer the questions.


Grading.
File Points
Synth.java 28
MySound.java 7
readme.txt 5
Total 40

This assignment was developed by Kevin Wayne.
Copyright © 2024.