-- Main.arthur - 25 Jan 2023

Project 1

Objectives:

Project 1 consists of writing software to produce an audio file.

After completing the Project you will be familiar with:
  1. Creating, compiling and running C++ projects
  2. Using C++ arrays
  3. Using functions in C++
  4. Basics of Digital Signal Processing (DSP)

To Submit:

  • Submit three C++ source files: submit one *.cpp file for Core, one for Completion and one for Challenge.
  • Your Reflection.pdf file - can be one file. Please label the Core, Completion, and Challenge sections.

Theory

Waveform of a single-tone sound:

tone1.png

We can calculate required instant air pressure of sound wave using the following formula:
 \begin{displaymath}a_i = A \cdot sin(2 \pi f t_i) \end{displaymath}
where
 \begin{displaymath} t_{i} = i \cdot dt \end{displaymath}
is current time for this sample
 \begin{displaymath}  dt \end{displaymath}
is time interval between samples
 \begin{displaymath} f \end{displaymath}
is current frequency of the sound
 \begin{displaymath} A \end{displaymath}
is volume of the sound

Core [55% for working code, 10% for reflection]: Generate a harmonic tone

Make a new project

  • Start Geany
  • Create a new file and save it with extension .cpp
  • Write an empty int main() function
  • Compile and build the file to check that Geany is working

You can use this template as starting point for Core

Copy the wav.hpp file into same folder where your program is. This file contains class which implements saving data in the sound format. You can find this file in Table of Attachments at the bottom of this page.
#include <iostream> // input-output library
#include <math.h>  // library for sin function
#include <vector>  // if using vectors
#include "wav.hpp" // make sure to include this helper library
// " " instead of <> means that library is in the same folder as your program

using namespace std;

int main(){
   int sample_rate = ...; // samples per second, select value which provides good quality sound 
   double duration=...; // how long [seconds] it will sound
   ... n_samples = ...; // if sound is "duration" seconds long and there are "sample_rate" samples per second
                        // - how many samples are there altogether? What type should this variable be?
   ... dt = ...; // time between samples
   int* waveform = new int[n_samples]; // creates the array
   // or you can use vector
   std::vector<int> waveform;
   int frequency= ....// pitch of the sound
   int volume= ...// 6000 is loud enough
  
   for ( int i_sample = 0; i_sample < n_samples ; i_sample++){ 
       // if using array
       waveform[i] = volume*sin(...);//
       // if using vector
       waveform.push_back(....);
       //cout an be used here to check values of "waveform"
   }
   // generates sound file from waveform array, writes n_samples numbers 
   // into sound wav file
   // should know sample_rate for sound timing
   MakeWavFromInt("tone1.wav",sample_rate, waveform, n_samples); //file name can be changed but keep extension .wav
   // if using vector
   MakeWavFromVector("tone1.wav",sample_rate, waveform); //file name can be changed but keep extension .wav
   delete[] (waveform); //if using array
   // or
   waveform.clear(); //if using vectors
   return 0;
}
Fill the blanks in code template. Compile and build.

Run the code. There is line in the code: MakeWavFromInt("tone1.wav",sample_rate, waveform, n_samples); which saves "waveform" into sound file. Name of the file ("tone1.wav") is first argument of the function. You can change the name, but please make sure that extension wav is used.
If you used vector then function is MakeWavFromVector("tone1.wav",sample_rate, waveform);. It does not need number of samples - this information can be obtained using size() function.

Inspect the produced file. If you saved the file correctly it is possible to inspect the sound waveform using Audacity or Kwave sound editors, which you can find under the Multimedia menu on our system. If you are using your own compute, please install some sound editor.

Play the audio. Please use headphones to avoid disturbing others.

Reflection

  • Explain your reasoning for your selected sampling rate
  • Explain how you calculated the total number of samples
  • Explain your reasoning for your selection of the types of all variables
  • Include a screenshot of the waveform obtained with SonicVisualizer. Does the waveform like what you intended?

(Completion)[10% for working code, 5% for reflection]: generate an ambulance Sound

Write a program which can generate an ambulance siren sound - made of two frequencies repeating a number of times.

fire.png

Code

  • Make new project. You can also save your previous project with new name and modify it.
  • There is no fixed way to complete this task. You can take different approaches to the one described below. As long as it works, there is no reduction in marks.
  • Select the duration of the one tone sound.
  • Select how many times the two tones will be repeated.
  • Now you calculate how many samples in total there will be in the waveform.
  • Reserve memory for the waveform samples.
  • Run the cycle for the number of repeats.
  • For an odd cycle number select one frequency, for even number select a different frequency.
  • Inside run another cycle generating an audio signal of a certain frequency. After completing that, change the frequency and run another cycle.
  • Save the generated waveform as wav file.

Reflection

  • Find and describe an alternative way to decide when to change the frequency. No need to code, just describe an algorithm.

(Challenge) [10% for working code, 10% for reflection]: Generate a Grand Piano (or another instrument) sound

Write a program which can:
1 Read a music score sheet (greatly simplified) (about 2.5% with regard to the marks) File is of the following format:
174.6
174.6
195.996
... where number is frequency of the note in Hz. The number of lines equals number of notes in the melody. We don't know in advance how many notes the melody contains. It would be beneficial if your program can read a file of any length.

There are two melody files - odetojoy.txt and anotherbrickinthewall.txt (we like the lyrics).

2 Play the melody (about 2.5% of marks) You can choose any tempo you like (note duration) If the amplitude of the waveform is constant, the music will sound artificial.

3 Make your program produce a sound like a real musical instrument. (about 5% of the marks) There is an artistic licence in this part. This part is the hard. To make audio sound somewhat similar to a real instrument, the amplitude of the sound has to change while the note is playing. It can follow:

adsr.png

Image from: https://www.teachmeaudio.com/recording/sound-reproduction/sound-envelopes
A piano, for example, will produce a sharp "attack", no "sustain", a long "decay", and no "release". Trumpet - slow "attack", "sustain", no "decay", slow "release"

You may want to investigate how higher-order harmonics contribute to the sound quality too: https://method-behind-the-music.com/mechanics/physics/

Reflection

Explain your choice of note amplitude shape: attack, sustain, decay and release parameters.
I Attachment Action Size Date Who Comment
adsr.pngpng adsr.png manage 4 K 22 Feb 2023 - 10:32 Main.arthur  
anotherbrickinthewall.txttxt anotherbrickinthewall.txt manage 291 bytes 13 Mar 2023 - 10:47 Main.arthur  
fire.pngpng fire.png manage 37 K 22 Feb 2023 - 10:32 Main.arthur  
odetojoy.txttxt odetojoy.txt manage 228 bytes 13 Mar 2023 - 10:28 Main.arthur  
tone1.pngpng tone1.png manage 41 K 22 Feb 2023 - 10:31 Main.arthur  
wav.hpphpp wav.hpp manage 6 K 01 Mar 2023 - 14:22 Main.arthur