This C++ program is capable of turning a text file describing the notes of a piece of music into an audio file (.wav). The program reads the contents of the input file i.e. input.txt, constructs Song, Voice and Note objects describing the notes in the file, and call the different functions of Song and Voice and Note C++ classes.
The input file has a minimum of two lines, but it can have more than two lines. The first line contains a single integer number representing the tempo of the music. The source code parses that integer to an argument to a function later in the code. Second and subsequent lines contain sequence of words representing music.
If you are not sure how file handling works, have comprehensive tutorials on File handling in C and File handling in C++.
Text File Structure
These lines contain a sequence of words where a space character separate them. Each word on these lines represents one music note. These notes have a specific structure i.e. the first 1 or 2 characters represent the pitch of the note, the next character is a single digit representing the octave for the note, and the final 1 or 2 characters represent the duration of the note.
The pitch of the note has one of the following values:
R, A, B, C, D, E, F, G, Ab, Bb, Db, Eb, Gb, A#, C#, D#, F#, or C#.
R stands for REST, while A#, C#, D#, F#, and G# correspond to Bb, Db, Eb, Gb, and Ab, respectively. The octave is a number in the range 0-7, and stored this in the octave field. Finally, the duration is one of the letters q, h, w, e, or s, possibly followed by a period. The letters q, h, w, e, and s correspond to durations of 1, 2, 4, 0.5, and 0.25, respectively. We multiply any duration by 1.5, which is followed by a period (.) e.g., “e.” will have a duration of 0.75.
Wave File Writer C++ Program
In this program, we implement three C++ classes: Song, Voice, and Note. Specifically, we implement much of the functionality in constructors for these three functions and implement three overloaded print functions, which we describe below.
Note::Note(const string& str): This constructor uses the given string to initialize the pitch, octave, and duration of the note.
Voice::Voice(const string& str, double vol, instrument_t instr): This constructor takes in a line of the input file (the first argument) and uses it to initialize a vector of Notes. It uses the second and third arguments to initialize the volume and instrument.
Song::Song(const string& file): This constructor opens the file with the given name and reads in the tempo and note information to initialize the song
ostream& operator<<(ostream& out, const Note& n): Overloaded function that prints the given note to out, in the same format as it is stored in the file. For example, a C on octave 3 with duration 1.0 prints as “C3q”.
ostream& operator<<(ostream& out, const Voice& v): Overloaded function that prints all of the Notes in the given Voice to out, separated by spaces.
ostream& operator<<(ostream& out, const Song& s): Overloaded function that prints to out the tempo on a line, followed by each Voice in the Song, one per line. The output is identical to the input file, with the exception that sharp notes (A#, C#, etc.) are replaced with their equivalent flat notes i.e. Bb, Db, etc.
We used g++ to compile the source code in Linux environment i.e., g++ -g song-driver.cpp song.cpp wavfilewriter.cpp