$3
Programming Project: Functions
CPSC 298-6 Programming in C++
Introduction
In this programming project, you'll update your Programming Project "Frequencies of
Musical Notes with Loops and Arrays" to introduce functions to compute the frequency
and wavelength of a musical note. You'll also introduce a function to return the name of
the note given its octave number and halftone index value. Additionally, you'll create a
header file to hold the definition of your functions as well as the definitions of a few
constant values.
In addition to learning about functions, you'll also learn how to check their input values;
in particular, you'll learn about function preconditions.
The framework for the project will be supplied in the form of two source files, a header
file MusicalNoteApi_incomplete.h and an implementation file,
MusicalNoteImpl_incomplete.cpp. As the names suggests, these are not complete,
working programs.
The files contain comments similar to the following showing you the sections of code
that you need to add.
The Background section below gives you some background information on the C
Preprocessor and the role it plays in making sure your header files (the .h files) compile
correctly. You can skip it if you're short of time.
Background
This project introduces you C++ header files and to a common usage of the C
Preprocessor. The C Preprocessor plays an important role in ensuring your header files
are not included multiple times (thus causing compilation errors).
Header File Preprocessor Sentinel
C and C++ header files all use C Preprocessor sentinels to avoid there being included
multiple times and causing syntax errors (due to duplicate declarations). A sentinel
ensures that your include file is included at most once. The idiom for a sentinel is shown
below. Generally, the defined macro, in this case MUSICAL_NOTE_API_H mimics the
name of the header file, in this case MusicalNoteApi.h.
2
The header file's code falls after the #define line and before the #endif line. The
preprocessor says to only render the code if the macro MUSICAL_NOTE_API_H is not
defined (The ! means not in the C Preprocessor language just as it does in C and C++.)
Once it is defined, the preprocessor ignores the code (doesn't insert it), so it can only ever
be inserted once.
The included header file is literally inserted into what is called an intermediate file (or
translation unit) and it is this file, with the header included at most once, that is presented
to the compiler after preprocessing.
An alternative to the C Preprocessor syntax shown is to use the #pragma once directive.
This does the same thing but is a more recent addition and may not be supported by the
C++ compiler.
You just type
#pragma once
at the top of your header file and you're done.
The Assignment
In this assignment, you'll modify two incomplete files, MusicalNoteApi_incomplete.h
and MusicalNoteImpl_incomplete.cpp by adding code. The files implement the familiar
Musical Notes project, but this time using functions.
The sections below take you through the changes you need to make step by step.
Alternatively, you can just scan the two files, search for the TODO comments and make
the described changes.
Copy or Rename Files
Rename MusicalNoteApi_incomplete.h to MusicalNoteApi.h.
Rename MusicalNoteImpl_incomplete.cpp to MusicalNoteImpl.cpp.
Place both files in the same directory. (If you are using an alternate development
environment, such as Microsoft Visual Studio on Windows, see the appendices.)
3
MusicalNoteApi.h Header File
First, observe that the contents of the header file is encapsulated in a preprocessor
sentinel to prevent the header from being included multiple times. This isn't a concern on
this project, but on larger projects headers can be included many times if not protected by
a preprocessor sentinel, resulting in syntax errors.
#if !defined(MUSICAL_NOTE_API_H)
#define MUSICAL_NOTE_API_H // Sentinel
<your header file code>
#endif
All the C++ header files you implement from now on (in this course and beyond) should
have a preprocessor sentinel.
Header File Preamble
Remember to insert your name or email address in the file preamble in the header file:
/// @brief Musical Notes Application Programming Interface (API) Header File
/// CPSC-298-6 Programming in C++ Project Musical Note Frequencies with Functions
/// @author outstanding.student@chapman.edu
Header File Constants
The header file contains a number of constant values that you can use in your
implementation file.
Function Preamble Comments
The header file provides function preamble comments that explain how the function
works, what input parameters should be supplied and what the function returns. It also
specifies restrictions on the function's input called preconditions, identified by the @pre
notation.
4
The function preambles are written for you in this assignment, but you'll need to read
them to complete several other steps. Also, you'll write your own function preambles
from now on in the course.
Function Prototype
You'll need to write the function prototype for the function "computeFrequency."
(Incidentally, observe that all of the function names have the form verbObject. The verb
indicates what the function does and the next word indicates what it acts on, the object (in
the grammar sense). This naming convention is called camel case.)
Notice the other prototypes in the file. For example, here's the preamble and prototype for
getNoteName:
Write a prototype for computeFrequency based on the preamble for compute frequency.
The prototype will resemble that for getNoteName, but the return value will not be a
string. (The preamble tells you what the function return type and arguments should be.)
Write the code for the computeFrequency function prototype right after the TODO
comment.
5
That's it; you're done with the changes to the header file!
MusicalNoteImpl.cpp Implementation File
You'll now make modifications to the implementation file.
Implementation File Preamble
As you did for the header file, put your name or email in the @author entry in the file
preamble comments for the Implementation file.
Include MusicalNoteApi.h Header File
Next, include the MusicalNoteApi.h header file, remember to use double quotes
("MusicalNoteApi.h") rather than angle brackes <MusicalNoteApi.h>.
Place your #include directive right after the TODO comments.
Complete Function computeFrequency
You'll make two additions to functions computeFrequency.
First, you'll write a conditional statement that implements the input checks on the
function's arguments. These checks are called "preconditions." The preconditions ensure
that the input values, nu and k, are correct. For instance, the user might have entered -1
for nu when nu must be >= 0.
The precondition check will have the form
if ((? >=0) && (? < ?) && (?? > = 0)) where the question marks correspond to nu, k and
the constant k_nHalfTonesInOctave.
6
The second change, also shown above, is to calculate the frequency in Hertz (Hz) based
on the value of nu and k. You've already done this calculation in earlier assignments and
just need to insert it here at the point f = /* ???? */
Note that the function returns f, the frequency. (What does it return in the event of an
error?)
Complete Function computeWavelengthInCm
Next, you'll complete function computeWavelengthInCm by implementing the
computation for the wavelength in centimeters. The precondition checks have already
been implemented, you just need to insert your calculation of the wavelength from your
previous assignments.
7
Complete Function getNoteName
Next, you'll complete function getNoteName.
getNoteName returns the name of a note as a string given the values of nu and k for the
note. The function allows you to build the string for a note name in an arbitrary octave,
not just 0 though 8.
For instance, the string "C#0" can be formed as follows by combining "C#" with a
"stringized" form of the integer 0. "Stringize" means to convert the integer 0 to its
representation as a string,"0". "C#0" is jut the concatenation of "C#" and "0".
8
You're almost done, just one more function to go.
Complete Function Main
Finally, you'll complete the main function by calling your three new functions.
First, you'll call them in the nested for loop used to compute the frequency and
wavelengths of the notes from octave 0 through octave 10.
When you execute the program, this portion will produce output similar to the following:
9
The last note whose frequency and wavelength are computed is "B10":
10
Lastly, you'll call the functions again outside of the nested for loop. You'll only call each
once and will pass erroneous input in all cases.
11
Assign the return values of the functions to appropriately named variables so that the
values can be printed out:
When you execute the program, this portion will produce output similar to the following:
Notice that the errors are reported and that values are returned (such as "UNK" and -1 )
indicating errors occurred in the function invocations.
You've now completed all of the changes to both the header file and the implementation
file. It's time to compile, build and run.
Building the Program
When building using the Chapman FSE Linux image running in a Docker container,
place both the MusicalNoteApi.h and MusicalNoteImpl.cpp files in the same directory.
This allows the compiler to find the header file (it's in the current working directory).
If they weren't in the same directory, you can use the -I option to tell the compiler where
to find them. The example below shows the -I option with an argument of ./, which
simply tells the compiler the header files are in the current directory. However, the
argument could just as easily be any other directory.
If you had multiple header files scattered in different directories throughout a large
project, you could specify multiple -I options so that the compiler could find them all.
Running the Program
To run the program, type ./music at the command prompt.
12
That's it; you're done!
13
Appendix A: Adding Header Files in the Microsoft Visual
Studio Integrated Development Environment
You may be using the Microsoft Visual Studio Integrated Development Environment
(IDE) in lieu of the standard Chapman FSE Linux Image running in a Docker container.
If so, you'll need to add the MusicalNotesApi.h header file to your project.
In the Solution Explorer window on the right hand side (typically) of the Visual Studio
IDE find the Header Files folder icon.
Right Click on the Header files Folder.
In the pop-up menu that appears, select Add, then select New Item from the Add submenu as shown below.
14
The Add New Item dialog window appears.
Click on Header File (.h) as shown above.
15
Next, enter a name for your header file in the Name textbox at the bottom of the dialog
window as shown in the figure beow.
Now, press the Add button.
The new header file, MusicalNoteApi.h appears under the Header files folder.
Double click to open the MusicalNoteApi.h header file in the editor.