4.3 Class
CS 312 Audio Programming Winter 2020
Table of Contents
4.3 Lab Class
Homework notes
Assuming your hand-in folder contained this structure for hw331_checktimestamps
/Users/je/_aGraded312/<HANDIN_FOLDER_NAME> ├── bin │ └── checkTimestamps ├── common │ ├── hw332_CMidiPacket.cpp │ └── hw332_CMidiPacket.h └── hw33 ├── hw331_checkTimestamps │ ├── CMakeLists.txt │ ├── build │ ├── hw331_checkTimestamps.cpp │ ├── hw331_checkTimestamps.h │ ├── hw331_main.cpp │ └── output.txt └── hw332_test_invariants ├── CMakeLists.txt ├── build ├── hw332_main.cpp ├── hw332_testInvariants.cpp └── hw332_testInvariants.h
I copy your hand-in folder to my Mac inside a folder I call _aGraded312.
This is the CMakeLists.txt file I use to compile your assignment.
cmake_minimum_required(VERSION 2.8) set(APPNAME "checkTimestamps") project(${APPNAME}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall ") set(HOME "/Users/je/_aGraded312/<HANDIN_FOLDER_NAME") set(COMMON "${HOME}/common") set(SOURCE_FILES ${COMMON}/hw332_CMidiPacket.cpp hw331_checkTimestamps.cpp hw331_main.cpp ) include_directories(${COMMON}) add_executable(${APPNAME} ${SOURCE_FILES})
You should be able compile your hand-in folder before turning it in by modifying the HOME pathname.
Drum Sequencer
Overview
Hardware and software based sequencers are commonly based on a matrix of rows and columns. Apple's Drum Beat Sequencer is shown below. Each row represents a single drum sound and is divided into 16 columns. Columns represent equally spaced units of time called a tick (like a clock tick.) Ticks move uniformly left to right and apply to all rows in that column. Any row/column intersection can be turned on or off. At every tick an "on" state plays a sound. Off states make no sound. Ticks loop back to the start. After tick 16 the sequence restarts at tick 1. This continues until the user stops the drum machine.
Apple Garage Band IOS Beat Sequencer is an 8x16 software sequencer
8 rows x 16 columns.
- Columns
- The 16 columns are separated by uniformly spaced timestamps called a ticks.
- The tick rate determines the playback speed.
- A short tick rates play fast and long tick rates plays slow.
- The entire column is played on each tick.
- If a cell in the column is highlighted it is played, otherwise it's ignored.
- We'll use the tick rate of 250 ms or one fourth of our standard 1000 ms beat unit.
- Rows
- Each row represents a single drum sound on one MIDI channel 9.
- A different drum sound is assigned to each row.
- Hilighted cells in a row indicate when a sound is played.
- The row contains four beats separated by thick vertical bars
- Each beat divided into 4 subdivisions.
Apple icons for rows 1-8
- Bass drum
- Snare drum
- Clap
- Closed Hi-hat
- Open Hi-hat
- Low Tom
- High Tom
- Sticks
Use your gmdrums tool to lookup these drum note numbers.
For Sticks you can substitute any of these:
side stick, claves, high wood block, low wood block.
My mp3 output
This is the output I get using the drum sounds and pattern sequence shown in the above picture.
CS312 Drum Sequencer
We'll implement two classes, a CDrumMachine class and a CDrumTrack class.
Should CDrumTrack be a subclass of CDrumMachine or a member variable of CDrumTrack?
- There is a well known method to help deciding using "is a" vs. "has a" terminology.
- If you think "CDrumTrack "is a" drum machine you'd implement it as a subclass.
- If you think "CDrumMachine "has a" drum track you'd implement it as a member variable.
- The "has a" method is clearly the correct choice.
- In fact CDrumMachine "has a" eight CDrumTrack variables.
- class CDrumMachine
- contains a vector of eight CDrumTracks
- contains the drum note
- class CDrumTrack
- CDrumTrack is a subclass of CMidiTrack that writes the MIDI messages needed for one row.
- The drum sound used for each row cannot be changed while playing.
- Drum tracks use delta time, the time difference between tick(N) and tick(N-1).
Implementation notes
The sound on/off states can be represented using a std::string of ones and zeros.
Idea 1 - One string per row
These are the strings representing the on/off states of the IOS drum machine shown above.
- "1000100010001000" for row 1
- "0001001000010010" for row 2
- "0000000000000010" for row 3
- etc.
- Cons
- It's hard to see where the four beats per row are using the long string representation.
It does not allow for future implementations to have three or five+ notes per beat.
Idea 2 - One string per beat
In the IOS Drum Machine picture thick vertical bars separated each beat.
We can divide each row into four small strings, one for each beat.
- "1000", "1000", "1000", "1000" for row 1
- "0001", "0010", "0001", "0010" for row 2
- "0000", "0000", "0000", "0010" for row 3
- etc.
- Pros
- The four beats in each row are clear
The number of subdivisions can vary as long as they add up to 1000ms.
2 notes per beat {500 500}
3 notes per beat {334 333 333}
4 notes per beat {250 250 250 250} <== the one we'll be using
5 notes per beat {200 200 200 200 200}
6 notes per beat {167, 167, 166, 167, 167, 166}
7 notes per beat {143, 143, 143, 143, 143, 142, 143}
8 notes per beat {125 125 125 125 125 125 125 125} - Cons
- There is some redundancy, for example one beat with 2 subdivisions could be represented by
"11" or "1010" or "100100" or "10001000".
They all would be equivalent to durations {500 500} the only difference would be the duration of the note which is turned off at the next zero.
Apple icons for rows 1-8
- Bass drum
- Snare drum
- Clap
- Closed Hi-hat
- Open Hi-hat
- Low Tom
- High Tom
- Sticks
Use your gmdrums tool to lookup these drum note numbers.
My mp3 output
Homework 4.3
hw431_drumMachine
In this assignment you'll implement the code needed to play the sound for each hilighted cell in a column during N trips (loops) through the sixteen column sequence.
Setup
Execute in Terminal.
cd $HOME312/cs312 mkdir hw43 cd hw43 mkdir hw431_drumMachine cd hw431_drumMachine mkdir build touch CMakeLists.txt # create files and add boilerplate touch hw431_CDrumTrack.h touch hw431_CDrumTrack.cpp touch hw431_CDrumMachine.h touch hw431_CDrumMachine.cpp touch hw431_main.cpp
Copy this code into their appropriate files.
hw431_CDrumMachine.h
Do not modify.
// hw431_CDrumMachine.h #ifndef hw431_CDRUMMACHINE_H_ #define hw431_CDRUMMACHINE_H_ #ifndef hw431_CDRUMTRACK_H_ #include "hw431_CDrumTrack.h" #endif #include <cstdint> #include <vector> // DO NOT MODIFY // You can add others // Look up drum note numbers using the CS312 tool gmdrums // Note: zero is not the correct number const uint8_t kBASS_DRUM = 36; const uint8_t kSNARE_DRUM = 0; const uint8_t kCLAP = 0; const uint8_t kCLOSED_HIHAT = 0; const uint8_t kOPEN_HIHAT = 0; const uint8_t kLOW_TOM = 0; const uint8_t kHIGH_TOM = 0; const uint8_t kSIDE_STICK = 0; const uint8_t kWOOD_BLOCK = 0; // DO NOT MODIFY class CDrumMachine class CDrumMachine { public: // This vector holds all eight drum tracks (rows) std::vector<CDrumTrack> vDrumTracks; // the big 6 are all default constructed void make_track(const uint8_t note, const std::vector<std::string> &pats); }; #endif // hw431_CDRUMMACHINE_H_
CDrumMachine.cpp
Do not modify.
// hw431_CDrumMachine.cpp #ifndef hw431_CDRUMMACHINE_H_ #include "hw431_CDrumMachine.h" #endif // DO NOT MODIFY void CDrumMachine::make_track(const uint8_t note, const std::vector<std::string> &pats) { CDrumTrack dt; dt.init_note_pats(note, pats); vDrumTracks.push_back(dt); }
hw431_CDrumTrack.h
Do not modify.
// hw431_CDrumTrack.h #ifndef hw431_CDRUMTRACK_H_ #define hw431_CDRUMTRACK_H_ #ifndef hw423_CMIDITRACK_H_ #include "hw423_CMidiTrack.h" #endif #include <iostream> #include <string> #include <cstdint> // DO NOT MODIFY class CDrumTrack : public CMidiTrack { private: uint8_t drum_note; std::vector<std::string> vbeat_pattern; std::vector<uint32_t> vbeat_dur; void write_onebeat(std::string pat); void write_beats(); public: int beat_num; CDrumTrack(); virtual ~CDrumTrack() = default; CDrumTrack(const CDrumTrack &) = default; CDrumTrack(CDrumTrack &&) = default; CDrumTrack &operator=(const CDrumTrack &) = default; CDrumTrack &operator=(CDrumTrack &&) = default; void init_note_pats(const uint8_t note, const std::vector<std::string> &pats); int getDrumNote() const { return drum_note; } void setDrumNote(const int &n) { drum_note = n; }; int getBeatNum() const { return beat_num; } void setBeatNum(const int &m) { beat_num = m; }; void write_track(); void write_track(int num_loops); }; #endif // hw431_CDRUMTRACK_H_
Implementation files
These two files are partially done with sections you have to complete.
hw431_main.cpp
Copy/paste. You complete.
// hw431_main.cpp #ifndef hw431_CDRUMACHINE_H_ #include "hw431_CDrumMachine.h" #endif #ifndef hw423_CMIDITRACK_H #include "hw423_CMidiTrack.h" #endif #ifndef HW421_CDELAYMS_H_ #include "hw421_CDelayMs.h" #endif #ifndef HW422_CAPPLEMIDISYNTH_H_ #include "hw422_CAppleMidiSynth.h" #endif #include <iostream> using namespace CMP33; int main() { // declare the playback vector std::vector<CMidiPacket> vplay; // create the drum machine CDrumMachine dm; // stuff each row into the dm.tracks vector dm.make_track(kBASS_DRUM, {"1000", "1000", "1000", "1000"}); // ... 7 more rows to go // figure them out from the picture of Apple's Drum Beat Sequencer picture on the web page std::cout << "main(): dm.make_track() 7 more rows to go\n"; std::cout << "main(): you need to implement the for loop\n"; for (auto n = 0; n < dm.vDrumTracks.size(); ++n) { dm.vDrumTracks[n].write_track(4); // repeat each row 4x // use std::copy(...) to stuff each of the eight vDrumTracks[n] into vplay std::cout << "main(): use std::copy(...) to stuff every vDrumTracks[n] into vplay\n"; } sort(vplay.begin(), vplay.end()); // use std::sort(...) to sort vplay std::cout << "main(): use std::sort(...) to sort vplay\n"; // write vplay to std::cout std::cout << "main(): write vplay to std::cout\n"; // set the CDelayMs::s_tempo, try 75 std::cout << "main(): set the CDelayMs::s_tempo to 75\n"; CDelayMs::s_tempo = 75; CAppleMidiSynth ams; // ams.send(vplay); };
CDrumTrack.cpp
// hw431_CDrumTrack.cpp #ifndef hw431_CDRUMTRACK_H_ #include "hw431_CDrumTrack.h" #endif CDrumTrack::CDrumTrack() : CMidiTrack(0, 0, 0, 0, 0, 0, 0) { drum_note = 0; vbeat_pattern = {"0000", "0000", "0000", "0000"}; vbeat_dur = {250, 250, 250, 250}; beat_num = 0; } void CDrumTrack::init_note_pats(const uint8_t note, const std::vector<std::string> &pats) { drum_note = note; vbeat_pattern = {pats}; } void CDrumTrack::write_onebeat(std::string pat) { /* beat_num keeps a running count of the drum_machine ticks. In one trip through a drum_machine row, beat_num's will be 0, 1, 2, ... 14, 15 In four trips through a drum_machine row, the starting beat_num of each repeat will be 0, 16, 32, 48 The timestamp of each beat_num = beat_num * 1000 vbeat_dur is a vector of 4 timestamps representing the duration of each beat subdivision {250,250,250,250} vbeat_pattern is a vector of 4 strings representing the on/off state of each beat subdivision {"1000","1000","1000","1000"} pat is one element of the vbeat_pattern vector representing the four subdivisions of a single beat like "1010". vbeat_dur.size() == vbeat_pattern.size() == 4 elemenets in each vector pat.size() == 4 (each element of vbeat_pattern has string length == 4) Every "1" in pat sends a NON message and must be matched with a n NOF 1ms before the next beat subdivision starts. Every "0" in pat is ignored for NON/NOF The timestamp of each beat subdivision is updated by its duration for both "1" and "0". Increment beat_num when all four ones and zeros of the beat subdivision have been processed */ std::cout << "CDrumTrack::write_onebeat(std::string pat) not implementated\n"; } void CDrumTrack::write_beats() { int subdivs = vbeat_pattern.size(); // is always be 4 for this drum machine for (int ix = 0; ix < subdivs; ++ix) write_onebeat(vbeat_pattern.at(ix)); } void CDrumTrack::write_track() { write_beats(); } void CDrumTrack::write_track(int num_loops) { for (auto ix = 0; ix < num_loops; ++ix) write_track(); }
Build and run using CMake
CMakeLists.txt
cmake_minimum_required(VERSION 3.5) set(APPNAME "drum_machine") project(${APPNAME}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall ") # you finish
SOURCE_FILES for cmake
common folder ├── hw332_CMidiPacket.cpp ├── hw423_CMidiTrack.cpp ├── hw421_CDelayMs.cpp └── hw422_CAppleMidiSynth.cpp hw431_drumMachine folder ├── hw431_CDrumMachine.cpp ├── hw431_CDrumTrack.cpp └── hw431_main.cpp
Build and run
You'll need to write code for
- hw431_CDrumTrack.cpp
- write_onebeat(…)
- hw431_main.cpp
- first drumTrack is shown
you need 7 more
Everything else remains unchanged.
Output
You'll get several messages.
As you write the missing code delete the std::cout messages that tell you what to do.
Continue development using Xcode as described below.
je$ ./drum_machine main(): dm.make_track() 7 more rows to go main(): you need to implement the for loop CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated CDrumTrack::write_onebeat(std::string pat) not implementated main(): use std::copy(...) to stuff every vDrumTracks[n] into vplay main(): use std::sort(...) to sort vplay main(): write vplay to std::cout main(): set the CDelayMs::s_tempo to 75 CAppleMidiSynth() success
hw431_drumMachine - Xcode
We'll continue developing the drum_machine project using Apple's development system Xcode. It has an excellent Debugger that allows you to trace into function calls and examine variables as drum_machine is running. It's an excellent way to trace through an unfamiliar program to figure out how it works.
When I was creating this assignment I relied on the Xcode debugger to get the write_onebeat(…) function in hw431_CDrumTrack.cpp working correctly. It's the trickiest part of this homework.
Setup
CMake can generate a ready to run Xcode project file using these commands.
You have to start with an empty build folder.
Execute these commands.
If you haven't created the emptyBuildFolder.sh script (week 2.2) and copied it to your course bin folder do it now.
Note: -4 points if it's not there and working.
cd $HOME312/cs312/hw43 cp -R hw431_drumMachine ./hw431_drumMachine_xcode cd hw431_drumMachine_xcode cd build emptyBuildFolder.sh cmake .. -G Xcode
Output
je$ cmake .. -G Xcode -- The C compiler identification is AppleClang 10.0.1.10010046 -- The CXX compiler identification is AppleClang 10.0.1.10010046 -- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /Users/je/cs312/_cs312/cs312/hw43/hw431_drumMachine_xcode/build
After cmake .. -G Xcode has finished the Xcode project file will be in the build folder.
Open the Xcode project
Either double click in Finder
or
Open from vsCode Terminal.
# cd build/ open drum_machine.xcodeproj
Close vsCode
Xcode Navigator Toolbar
The Project navigator icon is highlighted at the upper left. This icon displays the project source files. Note that the Source Files folder has been expanded.
Click hw431_main.cpp to open it.
The nine icons in the Navigator Toolbar display the following views.
The Heirarchical View displays classes and methods.
Click to navigate to the function.
Viewing header and source files
You can easily view corresponding header files for the currently displayed source file by clicking the Related Items icon.
You can view all source files in the project by clicking the Source Files icon.
Build and Debug in Xcode \\
Click and hold the ALL_BUILD button and choose drum_machine.
You can also access this from the Product menu.
Click the Build and Run button
When the compile finishes any program output will be shown in the right panel at the bottom of the window.
I enlarged the display panel by dragging the gray divider bar upwards.
The drum_machine executable can be found in the Products folder.
Breakpoints
Display hw431_main.cpp and set a breakpoint on line 31 by clicking just to the left of the 31.
Run the program again and it will stop at line 34.
Breakpoint information is highlighted in green on the right.
These are the the debugger commands that allow you to trace through your code line by line.
- Step Into
- If the line about to be execucted is function, step into that function.
- Stop Over
- If the line about to be execucted is function, step over it.
- Step Out
- If you are in a function and want to return to the caller step out.
Use the Step Into, Step Over, and Step Out commands either from the menu
or from the debugger toolbar
or the Shortcut keys: F6, F7, F8 (Shown above in the Debug menu picture).
Choose Step into
When the debugger halts at the first line of CDrumMachine::make_track() you can examine the values of variables in the left panel of at the bottom of the screen. Here I've right clicked the the note variable and am about to change the display from char ('%') to Decimal (37).
Hovering the mouse over the variable in the source code will display its value at that point in the program.
You'll recall we got here from main() where the two variables pasted into dm.make_track() were 37 and {"1000", "1000", "1000", "1000"}.
Step Over three more times until you stop at the closing brace of DrumMachine::make_track().
Expand the variables and you can see the the vDrumTracks vector for the first row of the drum machine has been setup with the drum note number, the beat pattern for the first measure, and the duration of each beat.
You can display either the Variables or Output pane by clicking these icons at the lower right. You can resize them proportionately by dragging the vertical divider separating them.
Stack trace
You can view a stack trace that displays the trail of function calls or "How did I get here?"
Click and hold the Stack Frame icon and the call tree will appear. You can click any one of these functions examine and how variables were changed as you arrived here.
Ending a debug session
Click the Stop button.
Or click the Deactivate breakpoints icon and then the Continue program execution icon.
Xcode is a very deep and comprehensive program. We've only scratched the surface but now have a valuable tool that can step through your code and and help you spot and fix errors.
My output
This is the output I used to create the mp3 file at the beginning of this page.
One cycle through the 16 columns of the drum machine.
# mp3 tempo was 75 bpm 0 99 36 100 500 99 42 100 500 99 43 100 500 99 46 100 500 99 37 100 749 89 37 0 749 89 46 0 749 89 42 0 749 89 43 0 750 99 50 100 750 99 38 100 1000 99 36 100 1249 89 36 0 1250 99 37 100 1499 89 37 0 1500 99 46 100 1500 99 38 100 1500 99 42 100 1749 89 46 0 1749 89 38 0 1749 89 42 0 1750 99 50 100 2000 99 36 100 2249 89 36 0 2250 99 37 100 2499 89 37 0 2500 99 46 100 2500 99 50 100 2500 99 42 100 2749 89 50 0 2749 89 42 0 2749 89 46 0 2750 99 38 100 3000 99 36 100 3249 89 36 0 3250 99 37 100 3499 89 37 0 3500 99 42 100 3500 99 50 100 3500 99 39 100 3500 99 38 100 3500 99 46 100 3749 89 38 0 3749 89 39 0 3749 89 50 0 3750 99 37 100 3750 99 42 100 3750 99 46 100 4000 99 36 100 4249 89 36 0 4500 99 42 100 4500 99 46 100 4500 99 43 100 4500 99 37 100 4749 89 37 0 4749 89 43 0 4749 89 42 0 4749 89 46 0 4750 99 38 100 4750 99 50 100 5000 99 36 100 5249 89 36 0 5250 99 37 100 5499 89 37 0 5500 99 38 100 5500 99 42 100 5500 99 46 100 5749 89 42 0 5749 89 46 0 5749 89 38 0 5750 99 50 100 6000 99 36 100 6249 89 36 0 6250 99 37 100 6499 89 37 0 6500 99 50 100 6500 99 42 100 6500 99 46 100 6749 89 46 0 6749 89 50 0 6749 89 42 0 6750 99 38 100 7000 99 36 100 7249 89 36 0 7250 99 37 100 7499 89 37 0 7500 99 46 100 7500 99 50 100 7500 99 38 100 7500 99 42 100 7500 99 39 100 7749 89 39 0 7749 89 38 0 7749 89 50 0 7750 99 46 100 7750 99 42 100 7750 99 37 100 8000 99 36 100 8249 89 36 0 8500 99 46 100 8500 99 43 100 8500 99 42 100 8500 99 37 100 8749 89 43 0 8749 89 37 0 8749 89 42 0 8749 89 46 0 8750 99 50 100 8750 99 38 100 9000 99 36 100 9249 89 36 0 9250 99 37 100 9499 89 37 0 9500 99 46 100 9500 99 38 100 9500 99 42 100 9749 89 42 0 9749 89 38 0 9749 89 46 0 9750 99 50 100 10000 99 36 100 10249 89 36 0 10250 99 37 100 10499 89 37 0 10500 99 46 100 10500 99 42 100 10500 99 50 100 10749 89 46 0 10749 89 50 0 10749 89 42 0 10750 99 38 100 11000 99 36 100 11249 89 36 0 11250 99 37 100 11499 89 37 0 11500 99 39 100 11500 99 38 100 11500 99 50 100 11500 99 46 100 11500 99 42 100 11749 89 50 0 11749 89 39 0 11749 89 38 0 11750 99 46 100 11750 99 37 100 11750 99 42 100 12000 99 36 100 12249 89 36 0 12500 99 37 100 12500 99 42 100 12500 99 46 100 12500 99 43 100 12749 89 43 0 12749 89 46 0 12749 89 37 0 12749 89 42 0 12750 99 50 100 12750 99 38 100 13000 99 36 100 13249 89 36 0 13250 99 37 100 13499 89 37 0 13500 99 46 100 13500 99 42 100 13500 99 38 100 13749 89 38 0 13749 89 42 0 13749 89 46 0 13750 99 50 100 14000 99 36 100 14249 89 36 0 14250 99 37 100 14499 89 37 0 14500 99 46 100 14500 99 42 100 14500 99 50 100 14749 89 46 0 14749 89 42 0 14749 89 50 0 14750 99 38 100 15000 99 36 100 15249 89 36 0 15250 99 37 100 15499 89 37 0 15500 99 42 100 15500 99 50 100 15500 99 46 100 15500 99 38 100 15500 99 39 100 15749 89 38 0 15749 89 39 0 15749 89 50 0 15750 99 46 100 15750 99 42 100 15750 99 37 100
Submission
Feel free to email jellinge@carleton.edu on any part of the homework that is unclear to you. Chances are if you have questions other students do too. I will answer those questions by email to everyone in the class. The original sender will remain anonymous. I have tried to provide clues to the homework in the web pages, reading assignments, and labs. Sometimes what seems obvious to me is not obvious to students just learning C++.
Create a folder named hwNN_LastnameFirstname1_LastnameFirstname2.
Substitute your name and your partner's name for LastnameFirstname1_LastnameFirstname2.
Remember
- Boilerplate header at top of every file.
- Make sure your program compiles before submitting.
- Programs that compile and produce partially correct output will be graded.
- You can send notes to me in your homework files by enclosing them in block comments.
- Programs that do not compile get an automatic F (59%).
- Each partner must submit identical homework folders to the course Hand-in folder.
- If only one partner submits the homework send me an email explaining why.
- Empty your build or build-debug folders using the command emptyBuildFolder.sh
- Only include .h, .cpp, Makefiles, CMakeLists.txt
- Do not include these folders/files
.git
.vscode Double check for the above two folders using this command
ls -a hwNN_LastnameFirstname1_LastnameFirstname2 # if either .git or .vscode exist in the folder you're submitting remove them with # rm -fR .git # rm -fR .vscode
$HOME312/common ├── hw332_CMidiPacket.cpp ├── hw332_CMidiPacket.h ├── hw423_CMidiTrack.cpp ├── hw423_CMidiTrack.h ├── hw421_CDelayMs.cpp ├── hw421_CDelayMs.h ├── hw422_CAppleMidiSynth.cpp └── hw422_CAppleMidiSynth.h $HOME312/cs312/hw43/hw431_drumMachine ├── CMakeLists.txt ├── build ├── hw431_CDrumMachine.cpp ├── hw431_CDrumMachineh.h ├── hw431_CDrumTrack.cpp ├── hw431_CDrumTrack.h └── hw431_main.cpp