CS 312 - Week 2.2 Class
CS 312 Audio Programming Winter 2020

Table of Contents

2.2 Class

I've graded and returned all homework in the Hand In folder that was there at 8:00am Wed Jan 15.
Graded homework is found in the Return folder.
I will no longer empty the the Hand In folder after today.

Requests
Review your homework in the the Return folder.
Copy it to your CMC /Accounts/home folder or other storage device.
Delete it from the Return folder.
Delete it from the Hand In folder.

Boilerplate

Boilerplate is meant to be copied to the top of every homework file you turn in. Here's an example.

/***************************************************************
hw111_hello.cpp
Copyright (c) Carleton College CS312 free open source
Assignment: hw111
Duck Donald dduck@carleton.edu
Mouse Minny mmouse@carleton.edu
DATE: 2019-12-15
TIME: 14:46:25
****************************************************************/

#include <iostream>

int main()
{
    std::cout << "hello, world" << std::endl;
}

When you complete the hw211_boilerplate homework you'll be able to execute boilerplate with two parameters and paste the result directly into your source code. No more editing.

# boilerplate <assignment> <filename> | pbcopy
#example
boilerplate hw111 hw111_hello.cpp | pbcopy
# Paste directly into your source code

hw22 Setup


Mount your course folder using the Go menu in Mac Finder

smb://courses.ads.carleton.edu/COURSES/cs312-00-w20

Execute in Mac Terminal

setup312 <your_carleton_email_name>

Folder structure
After you've mounted your cs312 course folder the mount point is

/Volumes/cs312-00-w20/StuWork/email_name
$HOME312 = /Volumes/cs312-00-w20/StuWork/email_name (same as above)
Inside $HOME312 are these folders
bin common cs312 googletest (the big download from class 3.2)
# anything else is ignored in assignment setups

Execute in Mac Terminal.

## JE TESTING
cd $HOME312/cs312
mkdir hw22
cd hw22
mkdir c221_argc_argv
cd c221_argc_argv
touch c221_argc_argv.cpp
cd ..
mkdir hw221_boilerplate #empty for now
mkdir hw222_CMidiPacket
cd hw222_CMidiPacket
cp  $HOME312/cs312/hw21/hw212_CMidiPacket/hw212_CMidiPacket.h ./hw222_CMidiPacket.h
cp  $HOME312/cs312/hw21/hw212_CMidiPacket/hw212_CMidiPacket.cpp ./hw222_CMidiPacket.cpp
cp  $HOME312/cs312/hw21/hw212_CMidiPacket/hw212_main.cpp ./hw222_main.cpp
touch hw222_test_CMidiPacket.h
touch hw222_test_CMidiPacket.cpp

for file in hw222*;
do
 sed -i '' 's/HW212/HW222/g' $file;
 sed -i '' 's/hw212/hw222/g' $file;
 sed -i '' 's/CMP21/CMP22/g' $file;
done

ls -lR $HOME312/cs312/hw22 # minus ell R

Folder structure

$HOME312/cs312/hw22
├── c221_argc_argv
│   └── c221_argc_argv.cpp
├── hw221_boilerplate (empty)
└── hw222_CMidiPacket
    ├── hw222_CMidiPacket.cpp
    ├── hw222_CMidiPacket.h
    ├── hw222_main.cpp
    ├── hw222_test_CMidiPacket.cpp
    └── hw222_test_CMidiPacket.h

c221_argc_argv

This section will help you complete hw221_boilerplate.cpp. This c221_argc_argv section does not have to be turned in but hw221_boilerplate.cpp dies.

Quit vsCode if it is open.

Execute these commands in Mac Terminal. You do not have to type the comments.

# make sure you're in the correct directory
cd $HOME/cs312/hw22
mkdir c221_argc_argv
# change the working directory to $HOME/cs312/hw22/c22_argc_argv
cd c221_argc_argv
# create a new file argc_argv.cpp
touch argc_argv.cpp
code .

What's this argc_argv stuff anyway?
Open argc_argv.cpp and type main. After a very slight pause the Snippet popup will appear and the line for main is highlighted.

c22001.png

Type Enter and you should see this.

c22002.png

This is the original C main(…) function carried over into C++.

Note the white dot in the filename tab that indicates the file is not saved.

argc and argv[] describe additional parameters that are passed on the command line into into the main() function.
The shell interprets these parameters using argc and the array argv[ ].

int argc
The number of parameters passed in.
char const *argv[ ]
An array of strings from argv[0] to argv[argc]
argv[0] is the name of the command
argv[1] is the first parameter

argv[argc] is the final parameter

Parameters are parsed by white space.
If any parameter contains white space it must be quoted.

What does char const *argv[ ] mean?
It basically means you cannot change the parameters in main().

Replace/copy/paste

// argc_argv.cpp
#include <iostream>

int main(int argc, char const *argv[])
{
        std::cout << "argc\t\t" << argc << std::endl;
        for (int ix = 0; ix < argc; ++ix)
            std::cout << "argv[" << ix << "]\t" << argv[ix] << std::endl;
    return 0;
}

Compile

# compile
cl argc_argv.cpp

Run

./a.out

Output

argc            1
argv[0] ./a.out
Notes
argc: There is one parameter, the name of the program. argv[0]: is always the program name.

Run again
This time with eight parameters.

./a.out 1 2 "buckle my shoe" 3 4 shut the door

Output

argc            9
argv[0] ./a.out
argv[1] 1
argv[2] 2
argv[3] buckle my shoe
argv[4] 3
argv[5] 4
argv[6] shut
argv[7] the
argv[8] door

Note: argc is always one more than the number of parameters because arg[0] is the command name.

hw222_CMidiPacket

Overview

In this assignment we're going to learn about three different build systems for C++ projects.

command line
This is the one we've been using. It's best suited for quick tests and projects with a very small number of files. It's not efficient for large projects because you, the programmer, have to keep track of which files need to be recompiled in addition to all files that depend on those files. You generally recompile everything.
make and Makefile
The make tool and the Makefile text file are available on virtually every platform with a C or C++ compiler. Make was included with early versions of Unix in the late 1970's and is still being used today. Makefiles have a specific language syntax that specifes dependencies between header files and source files and between object files and executable files.It became the de facto build system for almost 4 decades because it sped up the build-run-test cycle by only recompiling files that were changed and those affected by the change.
CMake and CMakeLists.txt
CMake appeared in 2000 and has become the modern standard for large software projects. CMake uses a CMakeLists.txt file to build a Makefile that is then used to build the program. CMake can do its work in separate build directory so your source directory stays clean. While cmake can become complex, it is very flexible. The CMakeLists.txt syntax is clearer than the Makefile. CMake will become our build tool of choice for the next several weeks and is the build system of many major open source projects.

Compile / Link
The compiler compiles source files and outputs machine code object files having a .o extension. The linker combines the .o files along with any needed libraries to produce the program output. The clang++ tool does both the compile and link steps. The output object could be an application, a command line tool, or a library.

Copy paste this content into your corresponding files

Build 1 - Command Line

We'll begin with the command line compile. We need to compile three .cpp files. If these are the only .cpp files in the current directory you can use this short form to compile the project. However, if there were other .cpp files in other directory you'd need to specify the files needed.

Build and run

cl hw222_CMidiPacket.cpp hw222_test_CMidiPacket.cpp hw222_main.cpp && ./a.out

Output
The compile must be successful and produce output.
The output will depend on the the progress made in your hw212_CMidiPacket homework.

This is the output you want to see.

0 80  0 0
# length 3
0 c0  11
# length 2
0 90  67  100
# length 3
900 80  67  0
# length 3
1000  90  76  100
# length 3
1900  80  76  0
# length 3
2000  90  72  100
# length 3
2900  80  72  0
# length 3
# 0xFn status not processed
# length 0

Build 2 - Make

The make command gets its instructions from a plain text file named Makefile. If Makefile exists in the project directory you can compile your project with a simple make commad. Makefile must begin with capital M and does not have a file extension. You can name the makefile something else like make-osx but then you'll need to use the command make -f make-osx to specify the makefile name.

As part of the compile phase the compiler produces intermediate object files with the extension .o.
As part of the link phase the compiler combines the .o files into the application.

The make file has to specify

  • the object files needed by the application
  • the .cpp and .h files needed by each object file

Example project files
This hypothetical example contains five files.

Two header files
  • file1.h
  • file2.h
Three source files
  • file1.cpp
  • file2.cpp
  • main.cpp

The contents of the files are not important.
It's the #include dependencies between header and source files that matter.

file1.h

// file1.h
...

file1.cpp

// file1.cpp
#include "file1.h"
...

file2.h

// file2.h
...

file2.cpp

// file2.cpp
#include "file2.h"
#include "file1.h"
...

main.cpp

// main.cpp
#include "file2.h"
...

In order to write a Makefile you need to know:

  • the object/source/header file dependencies for the compile phase
  • the object file dependencies for the link phase.

Compile phase dependencies
Dependencies travel left to right.

OBJECT FILE DEPENDS ON SOURCE DEPENDS ON HEADER
file1.o file1.cpp file1.h
file2.o file2.cpp file2.h, file1.h
main.o main.cpp file2.h

Link phase dependencies

EXECUTABLE DEPENDS ON OBJECT FILES
myapp file1.o, file2.o, main.o

Makefile syntax rules

  • Non indented lines are dependency rules.
  • Indented lines are commands.
  • Indented lines must begin with a tab character
  • # is a comment.
  • variables are defined like this APPNAME=this_app_name_is_very_very_long
  • defined variables appear like this: $(APPNAME)

This Makefile describes these dependencies.

# Define application name
APPNAME=myapp

# define the compiler to use
CC=clang++

#define the compiler parameters
CFLAGS=-c -std=c++17 -Wall
# the variables $(CC) $(CFLAGS) expand to clang++ -c -std-c++17 -Wall
# -c  Only run preprocess, compile, and assemble steps but do not link

# define the make command parameter option all, as in: make all
all: $(APPNAME)

# line 1: cmp221 depends on all three object files
# line 2: single TAB followed by linker command, no $(CFLAGS)
$(APPNAME): main.o file2.o file1.o
  $(CC) -g -o $(APPNAME) main.o file2.o file1.o

# line 1: main.o depends on file2.h
# line 2: single TAB followed by compile command
main.o: main.cpp file2.h
   $(CC) $(CFLAGS) main.cpp

# line 1: file2.o depends on file2.h and 1.h
# line 2: single TAB followed by compile command
file2.o: file2.cpp file2.h file1.h
   $(CC) $(CFLAGS) file2.cpp

# line 1: file1.o depends on file1.h
# line 2: single TAB followed by compile command
file1.o: file1.cpp file1.h
   $(CC) $(CFLAGS) file1.cpp

# define make command option clean, as in: make clean
# removes all the .o object files
clean:
  rm *.o
  rm ${APPNAME}

Create the Makefile for hw222_CMidiPacket

It's no coincidence that the Makefile we need has the same dependencies as the example Makefile above.

Setup
In vsCode create a new file called Makefile.

c22101.png

Copy/paste the Makefile example above into Makefile.

Makefile is very picky about syntax. A common error is not using a tab character for the indented lines. To view invisible characters in vsCode choose Render Whitespace from the View menu.

c22102.png

You'll need to check for tabs after you've pasted the text. VSCode displays spaces as dots, "tab stops" as vertical bars, and tabs as right pointing arrows.

c22103.png

If you see vertical bars and and the tab arrow as the first character in all indented lines you have tab indentation. Skip to the Find and Replace section below.

c22107.png

If you see vertical bars and dots between beginning each indented line you'll need to convert the spaces to tabs following these steps.

Choose Command Palette… from the View menu.
Shortcut: Shift-Cmd-P
Type the word tab in the text entry box and choose Convert Indentation to Tabs.

c22104.png

You should now see the tab arrow as the the first character in all indented lines. In the picture below one tab equals two spaces. It's a Preference setting in vsCode. Your setting may be different.

Important:
In a Makefile, all indented lines must begin with a tab character.

c22107.png

Save.

Find and Replace

The next task is to change the example names to the CMidiPacket names using Find/Replace.

Example name CMidiPacket name
file1 hw222_CMidiPacket
file2 hw222_test_CMidiPacket
main hw222_main
myapp cmp22

Use the vsCode Find/Replace panel.
Shortcut: Opt-Cmd-F

CodeScreenSnapz078.png

Find: file1
Replace: hw222_CMidiPacket
Click the Replace All icon.

c22106.png

All file1's have been changed.

Replace All: file2 with hw222_test_CmidiPacket

c22108.png

Replace All: main with hw222_main

c22109.png

Replace All: myapp with cmp22

c22110.png

compile

make and run

make && ./cmp22

You should see the same output you saw in the Build 1 - Command Line section.

make clean
A side effect of running make leaves the .o object files in the project directory.

c22112.png

Once the program is working the .o object files are no longer needed you can remove them with the make clean command.

c22113.png

If you do not want to remove the executable along comment the rm ${APPNAME} line.

clean:
  rm *.o
# rm $(APPNAME)

This is my working Makefile. It had tabs when I saved it but they often get changed to spaces when copying and pasting from a web page. You may have to convert spaces to tabs again.

# Define application name
APPNAME=cmp22

# define the compiler to use
CC=clang++

#define the compiler parameters
CFLAGS=-c -std=c++17 -Wall
# the variables $(CC) $(CFLAGS) expand to clang++ -c -std-c++17 -Wall
# -c  Only run preprocess, compile, and assemble steps but do not link

# define the make command parameter option all, as in: make all
all: $(APPNAME)

# line 1: cmp221 depends on all three object files
# line 2: single TAB followed by linker command, no $(CFLAGS)
$(APPNAME): hw222_main.o hw222_test_CMidiPacket.o hw222_CMidiPacket.o
  $(CC) -g -o $(APPNAME) hw222_main.o hw222_test_CMidiPacket.o hw222_CMidiPacket.o

# line 1: hw222_main.o depends on hw222_test_CMidiPacket.h
# line 2: single TAB followed by compile command
hw222_main.o: hw222_main.cpp hw222_test_CMidiPacket.h
   $(CC) $(CFLAGS) hw222_main.cpp

# line 1: hw222_test_CMidiPacket.o depends on hw222_test_CMidiPacket.h and 1.h
# line 2: single TAB followed by compile command
hw222_test_CMidiPacket.o: hw222_test_CMidiPacket.cpp hw222_test_CMidiPacket.h hw222_CMidiPacket.h
   $(CC) $(CFLAGS) hw222_test_CMidiPacket.cpp

# line 1: hw222_CMidiPacket.o depends on hw222_CMidiPacket.h
# line 2: single TAB followed by compile command
hw222_CMidiPacket.o: hw222_CMidiPacket.cpp hw222_CMidiPacket.h
   $(CC) $(CFLAGS) hw222_CMidiPacket.cpp

# define make command option clean, as in: make clean
# removes all the .o object files
clean:
  rm *.o
  rm ${APPNAME}

Output
Same as in Build 1

Use sed for Find/Replace

I wanted you to have practice with the Find/Replace panel in vsCode but it's quicker to use sed (stream editor). Admittedly the time it takes to create the sed command might take longer than the vsCode approach but I think it's more fun.

Replace the contents of the Makefile you just created with the earlier example Makefile that used file1 and file2.

Convert spaces to tabs and save.

Now you can make the changes to the Makefile and make and run the program with these two commands.

sed -i '' 's/file1/hw222_CMidiPacket/g
   s/file2/hw222_test_CMidiPacket/g
   s/main/hw222_main/g
   s/myapp/cmp22/g' ./Makefile

make && ./cmp22

Build 3 - CMake

CMake generates makefiles along with project files for Xcode and Visual Studio and many others. You can view a list of the 20+ generators at
https://cmake.org/cmake/help/v3.0/manual/cmake-generators.7.html

The CMakeLists.txt syntax is clearer and cleaner than the Makefile. We'll be using cmake in a basic way. It will become our build tool of choice for the next several weeks and is the build system that is used by many open source projects.

The CMakeLists.txt file provides source file names (.cpp) and compiler flags to the cmake command. The cmake command scans the listed source files and figures out the dependency relationships for you.

In large projects there are often separate CMakeLists.txt files project subdirectories. In CS 312 our needs are simple and we'll use a single top level CMakeLists.txt file.

CMake projects require two additional items in your project source directory.

  • a CMakeLists.txt file
  • a build directory

Create them now.

# cd $HOME312/cs312/hw12/hw222_CMidiPacket
mkdir build
touch CMakeLists.txt

CMakeLists.txt

Copy/paste.

cmake_minimum_required(VERSION 2.8)
set(APPNAME cmp22)
project(${APPNAME})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall")
set(
  SOURCE_FILES
  hw222_CMidiPacket.cpp
  hw222_test_CMidiPacket.cpp
  hw222_main.cpp
  )
add_executable(${APPNAME} ${SOURCE_FILES})

CMakeLists.txt syntax

  • parameters are enclosed in parentheses ( )
  • individual parameters within parentheses are separated by white space
  • parameters containing white space must be quoted
  • variables are defined with set as in set(VAR_NAME what_it_represents)
  • variables when used are prefixed with $ and enclosed in curly braces { } as in ${VAR_NAME}

Here's additional explanation for each of the lines in CMakeLists.txt.

c22117.png

1 cmake_minimum_required(VERSION 2.8)
This first line is required for all CMake projects in the top level CMakeLists.txt file. CS312 labs are version 3.15+
2 set(APPNAME cmp22)
The name of the executable.
3 project(${APPNAME})
The project name is the same as the executable name but doesn't have to be.
4 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall"}
set the C++ flags (parameters). They're the same parameters we used in the .bash_aliases file in week1_1.
alias cl "clang++ -std/c++17 -Wall "
5-10 set(SOURCE_FILES…)
Define the variable SOURCE_FILES. When used as ${SOURCE_FILES} it expands to the three .cpp files needed to compile the project. Note the opening parenthesis after the word set, and the closing parenthesis after all files have been listed.
11 add_executable(${APPNAME} ${SOURCE_FILES})
The executable cmp22 depends on ${SOURCE_FILES}

CMake build and run

Run these commands

cd build
move to the build directory
so the .o object files and other cmake intermediate files don't pollute the source file directory
cmake ..
../ refers to the parent directory where CMakeLists.txt is located.
cmake reads the CMakeLists.txt file and generates a Makefile.
make
Execute the Makefile cmake generated.
./cmp22
Run the application produced by make.

If you're in the build directory this can be done on one line if there are no errors to fix.

cmake .. && make && ./cmp22

Output
Same as in Build 1

You should always run cmake from a folder inside your source code folder. It's normally called build. If you run cmake directly from your source code folder you'll end up with lots of files polluting your source code folder.

cd build
ls -R build

If you want to do a fresh recompile you'll need to empty the build folder before running cmake. We'll write a script to do it.

emptyBuildFolder.sh

Setup

cd $HOME312/bin
touch emptyBuildFolder.sh
# make it executable
chmod 755 emptyBuildFolder.sh
# open in vsCode
code emptyBuildFolder.sh

Copy/paste this code int emptyBuildFolder.sh. Read the comments to see how it works.

#!/bin/bash

# `pwd` in backquotes represents the output of the command pwd

# if true it then execute rm -fR build/*
# if the command had said rm -fR build without the /* it would have removed the build folder and its contents
# the /* removes contents of build but does not remove build
if [ -d "`pwd`/build" ]
# -d is a test whether the build folder exists
# if you were already in the build folder the above command would return false
# unless you had a build folder inside your build folder
then
# -f = force, R = recursive to delete everything inside build.
  rm -fR build/*
elif [ -d ../build ]
# this -d checks for a build folder in the parent folder of the working directory
# if you're in the the source folder then you'll have a build folder
then
  rm -fR ../build/*
elif [ -d "`pwd`/build-debug" ]
# later classes will use build for release version and build-debug for debug version
then
  rm -fR build-debug/*
elif [ -d ../build-debug ]
then
  rm -fR ../build-debug/*
else
  echo  "no build or build-debug folder found"
fi
  exit 0

CMake produces a very complex Makefile. You can find it in the build directory.

Test emptyBuildFolder.sh
Display the contents of the build folder in vsCode EXPLORER.
Execute emptyBuildFolder.sh in vsCode Terminal.
Watch the files disappear.

CMake Documentation
These commands provide built in help for CMake.

cmake --help #shorter
man cmake    #longer

The CMake web page https://cmake.org/ has extensive documentation.

If you still have time in lab go to hw220_boilerplate.

Reading

There's quite a lot of reading/doing here. Most of it is aimed at making you more productive in Terminal and vsCode. Be sure to work through the entire vsCode section.

TCPP

16.2.4
16.2.5
16.2.8
16.2.9
16.2.11

Essential commands

Command help

Almost every command accepts parameters that modify the output of the command in different ways. Most commands support the -h or /–help option to display help for that command. If not try

Try this in Apple Terminal

clang++ --help

I got 376 lines of help. Use the scrollbar to navigate.

Try it again using this command.

clang++ --help | more

more is a text reader that displays one page of text at a time. You can navigate through the pages using these commands.

  • Page forward: press space bar or type Ctrl-f
  • Page backward: type Ctrl-b
  • To quit: type q or Ctrl-c

less is another popular text reader with similar commands. Get it, more or less.

man pages

Extensive documentation is also available by typing man followed by the command name. Try this.

man bash

Navigation commands ::

  • Page forward: press space bar or type Ctrl-f
  • Page backward: type Ctrl-b
  • To quit: type q= or =Ctrl-c

Deleting files and folders

Testing each of these commands assume that the folder ddd exists and contains the file delete_me.cpp. This folder and file will be deleted and recreated in following tests.

Delete file commands

  • Terminal
    rm
    In 1.2 Lab you created a .bash_alias file that aliased rm= to run in Interactive mode (/rm/rm -i). This is a safety option that asks for a yes/no before removing the file.
# vsCode Terminal
cd ddd
rm delete_me.cpp
# remove ddd/delete_me.cpp?
# respond with y or yes
ls # verify delete
# recreate for next test
touch delete_me.cpp
ls # verify it's back
rm -f
The -f option force removes the file without asking. This can be useful when you're trying to remove many files at once.
# vsCode Terminal
cd ddd
rm -f delete_me.cpp
ls # verify delete
# recreate for next test
touch delete_me.cpp
ls #verify it's back

Delete folder commands

  • Terminal
    rm
    rm is for files with one exception you'll see later
# vsCode Terminal
pwd
# you need to be in $HOME312/cs312/hw222_CMidiPacket
rm ddd
# rm: ddd: is a directory
# doesn't work
rmdir
rmdir is for ReMove DIRectory (but it must be empty)
# vsCode Terminal
pwd
# you need to be in $HOME312/cs312/hw222_CMidiPacket
rmdir ddd
# rmdir: ddd: Directory not empty
# remove delete_me.cpp
rm ddd/delete_me.cpp
# ddd is now empty
rmdir ddd
ls # verify
# setup for next test
mkdir ddd
touch ddd/delete_me.cpp
rm -fR
DANGER DANGER!
-f= is force and =-fR is recursive. It will delete every file and subdirectory without asking.
# vsCode Terminal
# you need to be in this directory
cd $HOME312/cs312/hw222_CMidiPacket
# verify  ddd/delete_me.cpp exists
ls ddd/delete_me.cpp
# if not recreate ddd and delete_me.cpp using mkdir and touch

rm -fR ddd
ls # verify they're gone
# setup for next test
mkdir ddd
touch ddd/delete_me.cpp

Visual Studio Code Tips

Your productivity as programmer in any language is directly related to your facility with and familiarity with the features supplied by your editor. Visual Studio Code comes out on top as the most popular editor in a 2019 survey:

https://insights.stackoverflow.com/survey/2019#development-environments-and-tools

VsCode is a very deep program. Browsing items in the Help menu on a regular basis will always lead to new insights.

vsc22219.png

vsCode cheat sheet

Make a link or even better print a copy of this page of keyboard shortcuts for the Mac.

https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf

Ignore the color differences between my screenshots and your monitor. My colors indicate the state of the file in the git repository and were taken during different git commits.

Create files/folders in EXPLORER

Click the New Folder icon.

vsc22202.png

Name the new folder atest and type Return.

vsc22203.png

The atest folder should appear and should be selected.
Click the New File icon.

vsc22204.png

Name the file please_dont_delete_me.cpp.

vsc22205a.png

New files are created inside a selected folder.

vsc22205b.png

Rename a file

Select please_dont_delete_me.cpp in the EXPLORER view.
Type Return.
The filename will change to enter text mode and is ready ready to be changed.

vsc22206a.png

Rename the file.

vsc22206b.png

Press Return

vsc22206c.png

Move files/folders in EXPLORER

Drag the delete_me.cpp file name down and to the right. A small blue icon will tear off as you drag. Drag outside of the atest folder and release the mouse button.

vsc22207a.png

A dialog will appear asking if you're sure you want to move delete_me.cpp. Click move. Note that you can click the "Do not ask me again" checkbox when you're comfortable with this approach.

vsc22207b.png

You now have an empty atest folder and a delete_me.cpp file in the hw222_CMidiPacket folder

vsc22207c.png

Delete a file

Right click the delete_me.cpp file. Choose Delete from the popup menu that appears.
Shortcut: Cmd-Delete/Cmd-Backspace

vsc22208a.png

A dialog will appear asking if you're sure you want to delete delete_me.cpp. Click move Move to Trash. Note that you can click the "Do not ask me again" checkbox when you're comfortable with this approach.

Use drag and drop to insert text into Terminal

In Mac OS X you can drag the icon of a file from Finder into Apple's Terminal window and the full path name will appear in Terminal when you release the mouse button. This also works in vsCode from EXPLORER into vsCode Terminal.

In vsCode Terminal type

# cd followed by space
cd

Drag the build folder into vsCode Terminal. Release the mouse button when you reach the space after cd.

vsc22209a.png

The full pathname for build should appear in the Terminal.

vsc22209b.png

Copy full path names in EXPLORER

You can the same thing using a right click and choosing Copy Path and then paste it into Terminal.

vsc22210.png

Choosing Copy Relative Path copies just the filename.

vsCode Breadcrumbs

The term Breadcrumbs is used in the sense of following a trail.

Choose Toggle Breadcrumbs from the View Menu. The checkmark indicates its been activated. It's a toggle menu item. You may have to click the menu a second time to see if the checkmark is present.

CodeScreenSnapz074.png

The Breadcrumb line is the middle line in the picture below. The two small symbols on the right toggle popup menus.

vsc22211a.png

The > symbol toggles a popup menu that lists all files in the current folder. Files can be selected and opened using this popup.

vsc22211b.png

The symbol toggles popup menu that lists the functions used in that file. It's a quick way to navigate to other functions.

vsc22211c.png

Intellisense

Intellisense is a vsCode extension that should already be installed. It's a brilliant piece of code written by C++ experts to help mere mortals from making PEBCAC errors (Problem Exists Between Computer And Chair).

You can find out a lot more about Intellisense by clicking the Extensions icon on the left, selecting C/C++ Intellisense and reading about it.

vsc22212.png

Testing Intellisense
Create a new file named intellisense.cpp.

vsc22213.png

Copy this code into intellisense.cpp.
Save it.
We'll use it for practice.

// intellisense.cpp
#ifndef C221_CMIDIPACKET_H
#include "hw222_CMidiPacket.h"
#endif

#include <iostream>
#include <string>

void CreateMidiPacketString(std::string s)
{
  uint16_t status
  uint16_t data1;
  uint16_t data2;
  uint16_t length;
}

int main()
{
  CreateMidiPacketString("0\t90\t60\t100);
  CreateMidiPacketString("0\t80\t60\t0");
  CreateMidiPacketString("0\t90\t62\t100")
    CreateMidiPacketString("0\t80\t62\t0");
  CreateMidiPacketString("0\t90\t64\t100");
  CreateMidiPacketString("0\t80\t64\t0");
}

Code Issues
The red squiggles you see under text indicate problems in the code. Open the vsCode Terminal and click PROBLEMS. You'll see the the problems you need to fix.

vsc22214.png

The two numbers in brackets may be different on your computer depending on the Tab key number of spaces setting.
The first number is the line number. I'm not sure what the second number refers to.

The line number is usually correct but sometimes refers to the previous line. In problem 1 the semicolon is missing at the end of line 11.

Problem 1
/expected a ';' [12,7] A semicolon is missing at the end of line 11 Add the semicolon and Save.
You're now down to three problems.
Problem 2
missing closing quote [19,26]
Line 19 (or maybe 18) is missing a closing quote (std::string must be quoted).
In fact it is line 19 where the std::string is missing the closing double quote. Add the closing double quote and Save.
You're now down to one problem.
Last problem
expected a ';' [22,7]
Similar to problem 1.
A semicolon is missing at the end of line 21. Add the semicolon and Save.
Problems gone.

Auto-completion
Still in intellisense.cpp.
Add a new line at the end of main(). Type Cr <slight pause> and a popup menu will appear giving options for any terms Intellisense has learned about. In this case the one we want is already selected.

CodeScreenSnapz096.png

Type Return and the full term will be entered automatically.

CodeScreenSnapz097.png

Type the opening parenthesis and the parameters of the function will be displayed.

CodeScreenSnapz098.png

Type ESC and delete line 24.

Multiple Cursors

Still in intellisense.cpp.
Copy/Paste lines 18-23 into a block comment section starting at line 26.
We'll use this as our playground.

CodeScreenSnapz099.png

We're going to convert lines 26-31 into valid MIDIDisplay_DLS formatted MIDI messages.

This is the complete set of keyboard shortcuts for Multiple Cursors. The funny looking symbol is the =Alt/Option/ key.

vsc22215.png

Let's try a few.

Modifier Keys + Arrow Keys
Click just before Create in line 26.

CodeScreenSnapz100.png

Hold down Opt-Cmd and type the down arrow five times

CodeScreenSnapz100a.png

Hold down Shift-Opt and type the right arrow once.

CodeScreenSnapz101.png

Release Opt.= Hold down =Shift and type the right arrow twice.

CodeScreenSnapz102.png

Type delete

CodeScreenSnapz103.png

Remove the Tabs

Type right arrow three times

CodeScreenSnapz104.png

Type Delete twice and Tab once

CodeScreenSnapz105.png

Type the right arrow four times

CodeScreenSnapz106.png

Type Delete twice and Tab once

CodeScreenSnapz107.png

Type the right arrow four times

CodeScreenSnapz108.png

Type Delete twice and Tab once

CodeScreenSnapz109.png

Select lines 26-31

CodeScreenSnapz110.png

Type Shift-Opt-i to place a cursor at the end of each line.

CodeScreenSnapz111.png

Type Delete three times.

CodeScreenSnapz112.png

Click anywhere and we're done.

CodeScreenSnapz113.png

Replace all occurrences of a word
Double click the word "CreateMidiPacketString" in line 9 to select the whole word.

CodeScreenSnapz114.png

If you refer to the Keyboard Shortcut table above you will see that:

  • Shift-Opt-L will select a strings matching the selection.
  • Cmd-F2 will select all words matching the selection.

Either one will work here. The difference is that strings can contain spaces, words can't.

Type either command. All occurrences of that word will be selected.

CodeScreenSnapz115.png

Start typing the new word and all selections will change as you type.

CodeScreenSnapz116.png

Change all uint16_t= to =uint8_t

CodeScreenSnapz117.png

More Multi-Cursor information can by found by choosing Interactive Playground from the Help. When the playground window opens click the Multi-cursor Editing link and read it.

Indent/Outdent

Select lines 26-31.

CodeScreenSnapz118.png

Type Cmd-] to outdent the selection.

CodeScreenSnapz118a.png

Type Cmd-[ to indent the selection.

CodeScreenSnapz118b.png

Click at a random place within the selection.

CodeScreenSnapz119.png

Type Cmd-] to outdent the line with the cursor.

CodeScreenSnapz119a.png

Type Cmd-[ to indent the line with the cursor.

CodeScreenSnapz120.png

Bracketed words

  • Select any word by double clicking
  • While it's selected type any one of these characters and that character and its matching end character will surround the word.
    '
    single quote
    "
    double quote
    (
    left parenthesis
    [
    left bracket
    {
    left curly brace

Eye Candy

Open a .cpp file.
Choose Preferences/Color Theme from the Code menu.
Shortcut: Cmd-K-T= (Hold =Cmd down and type k followed by t)

CodeScreenSnapz121.png

Use the Up/Down arrow keys to preview the theme.

CodeScreenSnapz122.png

I'm using the Dark+ (default dark) theme for all screenshots in these web pages. You're free to use any theme you like. There are hundreds available. You can view some more at:
https://vscodethemes.com/

Homework 2.2

hw221_boilerplate.cpp

The only two items that ever change can be passed as parameters to boilerplate
assignment
filename.ext
These items can be const std::string
Copyright
LastFirst1 email
LastFirst2 email

The date and time are calculated in the code.

The c221_argc_argv.cpp section has the answers.

Assignment hw221

Rewrite boilerplate to accept two parameters, assignment and filename.

This command

boilerplate hw111 hw111_hello.cpp

would produce this output

/***************************************************************
hw111_hello.cpp
Copyright (c) Carleton College CS312 free open source
Assignment: hw111
<Last First> <email>
<Last First> <email>
DATE: 2020-01-13
TIME: 20:46:25
****************************************************************/

You must display a usage message if there are not exactly two parameters.

std::cout << "** Usage:  " << "boilerplate <hwNNN> <filename.extension>\n";

Rename and copy to $HOME312/bin

When you're satisfied that a.out works rename it as boilerplate and move it to $HOME/bin/.
Both partners do this.

mv a.out $HOME312/bin/boilerplate

Execute in vsCode terminal and paste its output at the top of every homework assignment from now on. example

boilerplate hw11 hw11_hello.cpp | pbcopy

pbcopy is an Apple command that copies text to the clipboard ready to be pasted into your source code.

hw222_CMidiPacket

This homework assumes you've complete the hw222 section shown above in the class lab.

Quit vsCode.

Setup

In Mac Finder drag the $HOME312/cs312/hw22/hw222_CMidiPacket icon into the main window of vsCode.

vsc22218.png

Open vsCode and then open hw222_CMidiPacket.h.
Make these two changes.

hw22201.png

Save and close all open hw222_CMidiPacket.h and any other open files.
Make sure you're in the hw222_CMidiPacket directory in vsCode Terminal.

Private class variables are often suffixed with an underscore.
Run these commands to change them.

# suffix private variables with underscore
# https://stackoverflow.com/questions/1032023/sed-whole-word-search-and-replace
cd $HOME312/cs312/hw22/hw222_CMidiPacket
sed -i '' 's/[[:<:]]timestamp[[:>:]]/timestamp_/g
  s/[[:<:]]status[[:>:]]/status_/g
  s/[[:<:]]data1[[:>:]]/data1_/g
  s/[[:<:]]data2[[:>:]]/data2_/g
  s/[[:<:]]length[[:>:]]/length_/'  hw222_CMidiPacket*

Assignment hw222

Because we made the class data variables private other classes will not be able to access them. The standard way to deal with that is to implement "getter" and "setter" functions to access the private data. This is a recommended practice called encapsulation or data hiding that prevents other classes from modifying the data directly.

hw222_CMidiPacket.h
Replace/copy/paste

// hw221_CMidiPacket.h

#ifndef HW221_CMIDIPACKET_H_
#define HW221_CMIDIPACKET_H_

#include <iostream>
#include <string>

namespace CMP22
{
class CMidiPacket
{
private: // not really needed because they're private by default
  // MidiPacket2 data
  uint32_t timestamp_;
  uint8_t status_;
  uint8_t data1_;
  uint8_t data2_;
  uint8_t length_;

public:
  // from class snippet
  CMidiPacket();                                         // constructor
  ~CMidiPacket();                                        // destructor
  CMidiPacket(const CMidiPacket &) = default;            // copy constructor
  CMidiPacket(CMidiPacket &&) = default;                 // move constructor
  CMidiPacket &operator=(const CMidiPacket &) = default; // assignment
  CMidiPacket &operator=(CMidiPacket &&) = default;      // move assignment

  // three overlaoded constructors
  // construct a CMidiPacket for a one data byte message
  CMidiPacket(uint32_t ts, uint8_t st, uint8_t d1);

  // construct a CMidiPacket for a two data byte message
  CMidiPacket(uint32_t ts, uint8_t st, uint8_t d1, uint8_t d2);

  // construct a CMidiPacket from a valid MIDIDisplay string
  CMidiPacket(const std::string &str);

  // return a string from this CMidiPacket data
  std::string to_string() const;

  // print this CMidiPacket data to std::cout
  // in MIDIDisplay format accounting for message lengths of 2 or 3
  void print() const;

  // getters
  uint32_t get_timestamp() const;
  uint8_t get_status() const;
  uint8_t get_data1() const;
  uint8_t get_data2() const;
  uint8_t get_length() const;
  uint8_t get_midi_channel() const;

  // setters
  void set_timestamp(const uint32_t &ts);
  // status determines the length
  void set_status(const uint8_t &st);
  // length cannot be set without knowing status
  void set_status_length();
  void set_data1(const uint8_t &d1);
  void set_data2(const uint8_t &d2);
  void set_midi_channel(const uint8_t &chan);

  // Utility functions
  bool is_status_8n() const;
  bool is_status_9n() const;
  bool is_status_An() const;
  bool is_status_Bn() const;
  bool is_status_Cn() const;
  bool is_status_Dn() const;
  bool is_status_En() const;
  bool is_status_Fn() const;
  bool is_note_off() const;
  bool is_note_on() const;
};
} // namespace CMP22
#endif // HW221_CMIDIPACKET_H

Added functions

  // getters
  uint32_t get_timestamp() const;
  uint8_t get_status() const;
  uint8_t get_data1() const;
  uint8_t get_data2() const;
  uint8_t get_length() const;
  uint8_t get_midi_channel() const;

  // setters
  void set_timestamp(const uint32_t &ts);
  // status determines the length
  void set_status(const uint8_t &st);
  // length cannot be set without knowing status
  void set_status_length();
  void set_data1(const uint8_t &d1);
  void set_data2(const uint8_t &d2);
  void set_midi_channel(const uint8_t &chan);

  // Utility functions
  bool is_status_8n() const;
  bool is_status_9n() const;
  bool is_status_An() const;
  bool is_status_Bn() const;
  bool is_status_Cn() const;
  bool is_status_Dn() const;
  bool is_status_En() const;
  bool is_status_Fn() const;
  bool is_note_off() const;
  bool is_note_on() const;
};
} // namespace CMP22
#endif // HW221_CMIDIPACKET_H

hw222_CMidiPacket.cpp
Replace/copy/paste the print() function.

// Do not change print()
// Send a MIDIDisplay string to std::cout using toString()
void CMidiPacket::print() const
{
  std::cout << to_string() << std::endl;
}

Note:
You'll have to implement the getter, setter, and utility functions in hw222_CMidiPacket.cpp.

hw222_test_CMidiPacket.h
Replace/copy/paste

// hw222_test_CMidiPacket.h
#ifndef HW222_TEST_CMIDIPACKET_H_
#define HW222_TEST_CMIDIPACKET_H_

void run_CMidiPacket_tests();

#endif // HW222_TESTCMIDIPACKET_H_

hw222_test_CMidiPacket.cpp
Replace/copy/paste

// hw222_test_CMidiPacket.cpp
#ifndef HW222_TEST_CMidiPacket_H_
#include "hw222_test_CMidiPacket.h"
#endif

#ifndef HW222_CMidiPacket_H_
#include "hw222_CMidiPacket.h"
#endif

#include <iostream>
#include <sstream>
#include <string>

using namespace CMP22;

void print_main_message(const std::string &msg, CMidiPacket mp)
{
  std::cout << "\n===> " << msg << std::endl;
  mp.print();
}

void print_sub_message(const std::string &msg, CMidiPacket mp)
{
  std::cout << "----\n"
            << msg << std::endl;
  mp.print();
}

void print_length_message(const std::string &msg, CMidiPacket mp)
{
  std::cout << "----\n"
            << msg << std::endl;
  std::cout << +mp.get_length() << std::endl;
}

void test_default_constructor()
{
  CMidiPacket mp;
  print_main_message("test_default_constructor()\n(0, 80, 0, 0)", mp);
}

void test_constructor_one_data_byte()
{
  CMidiPacket mp{100, 0xc0, 11};
  print_main_message("test_constructor_one_data_byte\n(100, 0xc0, 11)", mp);

  CMidiPacket mp1{100, 0xF2, 11};
  print_sub_message("(100, 0xF2, 11)", mp1);
}

void test_constructor_two_data_bytes()
{
  CMidiPacket mp{1001, 0x91, 61, 101};
  print_main_message("test_constructor_ts_two_data_bytes\n(1001, 0x91, 61, 101)", mp);

  CMidiPacket mp1{100, 0xB4, 11, 0};
  print_sub_message("(100, 0xB4, 11, 0)", mp1);
}

void test_constructor_string()
{
  CMidiPacket mp("100\tc0\t11");
  print_main_message("test_constructor_string\n(100\tc0\t11)", mp);

  CMidiPacket mp1("1001\t91\t61\t101");
  print_sub_message("(1001\t91\t61\t101)", mp1);

  CMidiPacket mp2("1002 B2 7 102");
  print_sub_message("NO TABS: (1002 B2 7 102)", mp2);
}

void test_to_string()
{
  CMidiPacket mp(100, 0xC0, 11);
  print_main_message("test_to_string\n(100, 0xC0, 11)", mp);

  CMidiPacket mp1(1001, 0x91, 60, 101);
  print_sub_message("(1001, 91, 60, 101)", mp1);

  CMidiPacket mp2(2002, 0xB2, 7, 102);
  print_sub_message("(2002, 0xB2, 7, 102)", mp2);
}

void test_print()
{
  CMidiPacket mp(100, 0xC0, 11);
  print_main_message("test_print\n(100, 0xC0, 11)", mp);

  CMidiPacket mp1(1001, 0x91, 60, 101);
  print_sub_message("(1001, 91, 60, 101)", mp1);

  CMidiPacket mp2(2002, 0xB2, 7, 102);
  print_sub_message("(2002, B2, 7, 102)", mp2);
}

// getters
void test_get_timestamp()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  print_main_message("test_get_timestamp(1001, 91, 60, 101)", mp1);
}
void test_get_status()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  print_main_message("test_get_status(1001, 91, 60, 101)", mp1);
}
void test_get_data1()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  print_main_message("test_get_data1(1001, 91, 60, 101)", mp1);
}
void test_get_data2()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  print_main_message("test_get_data2(1001, 91, 60, 101)", mp1);
}

void test_get_length()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  print_main_message("test_get_length(1001, 91, 60, 101)", mp1);
}

// setters
void test_set_timestamp()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  mp1.set_timestamp(999);
  print_main_message("test_set_timestamp(999)", mp1);
}
void test_set_status_length()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  mp1.set_status_length();
  print_main_message("test_set_status_length(1001, 0x91, 60, 101)", mp1);
  print_length_message("length(1001, 0x91, 60, 101)", mp1);

  CMidiPacket mp2(1001, 0xC1, 60, 100);
  mp2.set_status_length();
  print_sub_message("USING BAD INPUT: test_set_status_length(1001, 0xC1, 60, 100)", mp2);
  print_length_message("USING BAD INPUT: length(1001, 0xC1, 60, 100)", mp2);
}

void test_set_data1()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  mp1.set_data1(99);
  print_main_message("test_set_data1(1001, 0x91, 60, 101) -> 99", mp1);
}
void test_set_data2()
{
  CMidiPacket mp1(1001, 0x91, 60, 101);
  mp1.set_data2(99);
  print_main_message("test_set_data2(1001, 0x91, 60, 101) -> 99", mp1);
}

// Utility functions
void test_is_status_8n()
{
  std::cout << "\n===> test_is_status_8n" << std::endl;
  CMidiPacket mp1(1001, 0x81, 60, 101);
  std::cout << std::boolalpha << mp1.is_status_8n() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x91, 60, 101);
  std::cout << std::boolalpha << mp2.is_status_8n() << std::endl;
  mp2.print();
}

void test_is_status_9n()
{
  std::cout << "\n===> test_is_status_9n" << std::endl;
  CMidiPacket mp1(1001, 0x91, 60, 101);
  std::cout << std::boolalpha << mp1.is_status_9n() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x81, 60, 101);
  std::cout << std::boolalpha << mp2.is_status_9n() << std::endl;
  mp2.print();
}

void test_is_status_An()
{
  std::cout << "\n===> test_is_status_An" << std::endl;
  CMidiPacket mp1(1001, 0xA1, 60);
  std::cout << std::boolalpha << mp1.is_status_An() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x91, 60, 101);
  std::cout << std::boolalpha << mp2.is_status_An() << std::endl;
  mp2.print();
}

void test_is_status_Bn()
{
  std::cout << "\n===> test_is_status_Bn" << std::endl;
  CMidiPacket mp1(1001, 0xB1, 60, 101);
  std::cout << std::boolalpha << mp1.is_status_Bn() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x91, 60, 101);
  std::cout << std::boolalpha << mp2.is_status_Bn() << std::endl;
  mp2.print();
}

void test_is_status_Cn()
{
  std::cout << "\n===> test_is_status_Cn" << std::endl;
  CMidiPacket mp1(1001, 0xC1, 60);
  std::cout << std::boolalpha << mp1.is_status_Cn() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x91, 60, 101);
  std::cout << std::boolalpha << mp2.is_status_Cn() << std::endl;
  mp2.print();
}

void test_is_status_Dn()
{
  std::cout << "\n===> test_is_status_Dn" << std::endl;
  CMidiPacket mp1(1001, 0xD1, 60, 101);
  std::cout << std::boolalpha << mp1.is_status_Dn() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x91, 60, 101);
  std::cout << std::boolalpha << mp2.is_status_Dn() << std::endl;
  mp2.print();
}

void test_is_status_En()
{
  std::cout << "\n===> test_is_status_En" << std::endl;
  CMidiPacket mp1(1001, 0xE1, 60, 101);
  std::cout << std::boolalpha << mp1.is_status_En() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x91, 60, 101);
  std::cout << std::boolalpha << mp2.is_status_En() << std::endl;
  mp2.print();
}

void test_is_status_Fn()
{
  std::cout << "\n===> test_is_status_Fn" << std::endl;
  CMidiPacket mp1(1001, 0xF1, 60, 101);
  std::cout << std::boolalpha << mp1.is_status_Fn() << std::endl;
  mp1.print();
}

void test_is_note_off()
{
  std::cout << "\n===> test_is_note_off" << std::endl;
  CMidiPacket mp1(1001, 0x81, 60, 101);
  std::cout << std::boolalpha << mp1.is_note_off() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x92, 60, 0);
  std::cout << std::boolalpha << mp2.is_note_off() << std::endl;
  mp2.print();

  CMidiPacket mp3(1001, 0x93, 60, 101);
  std::cout << std::boolalpha << mp3.is_note_off() << std::endl;
  mp3.print();

  CMidiPacket mp4(1001, 0xA3, 60, 101);
  std::cout << std::boolalpha << mp4.is_note_off() << std::endl;
  mp4.print();
}

void test_is_note_on()
{
  std::cout << "\n===> test_is_note_on" << std::endl;
  CMidiPacket mp1(1001, 0x92, 60, 101);
  std::cout << std::boolalpha << mp1.is_note_on() << std::endl;
  mp1.print();

  CMidiPacket mp2(1001, 0x92, 60, 0);
  std::cout << std::boolalpha << mp2.is_note_on() << std::endl;
  mp2.print();

  CMidiPacket mp3(1001, 0xB3, 60, 101);
  std::cout << std::boolalpha << mp3.is_note_on() << std::endl;
  mp3.print();
}

void run_CMidiPacket_tests()
{
  test_default_constructor();
  test_constructor_one_data_byte();
  test_constructor_two_data_bytes();
  test_constructor_string();
  test_to_string();
  test_print();
  test_get_timestamp();
  test_get_length();
  test_get_status();
  test_get_data1();
  test_get_data2();
  test_set_timestamp();
  test_set_status_length();
  test_set_data1();
  test_set_data2();
  test_is_status_8n();
  test_is_status_9n();
  test_is_status_An();
  test_is_status_Bn();
  test_is_status_Cn();
  test_is_status_Dn();
  test_is_status_En();
  test_is_status_Fn();
  test_is_note_off();
  test_is_note_on();
}

hw222_main.cpp
Replace/copy/paste

// hw222_main.cpp

#ifndef HW222_CMIDIPACKET_H_
#include "hw222_CMidiPacket.h"
#endif

#ifndef HW222_TEST_CMidiPacket_H_
#include "hw222_test_CMidiPacket.h"
#endif

using namespace CMP22;

int main()
{
  run_CMidiPacket_tests();
}

CMake, Make, Run

# build, make, and run
cd build
cmake .. && make && ./cmp22

Fix any errors.

My output is shown below.
Function parameters are shown in ( ).
Function output is the following line with numbers separated by tabs.
Carefully read through the output looking for errors in output.

===> test_default_constructor()
(0, 80, 0, 0)
0       80      0       0

===> test_constructor_one_data_byte
(100, 0xc0, 11)
100     c0      11
----
(100, 0xF2, 11)
# 0xFn status_ not processed

===> test_constructor_ts_two_data_bytes
(1001, 0x91, 61, 101)
1001    91      61      101
----
(100, 0xB4, 11, 0)
100     b4      11      0

===> test_constructor_string
(100    c0      11)
100     c0      11
----
(1001   91      61      101)
1001    91      61      101
----
NO TABS: (1002 B2 7 102)
1002    b2      7       102

===> test_to_string
(100, 0xC0, 11)
100     c0      11
----
(1001, 91, 60, 101)
1001    91      60      101
----
(2002, 0xB2, 7, 102)
2002    b2      7       102

===> test_print
(100, 0xC0, 11)
100     c0      11
----
(1001, 91, 60, 101)
1001    91      60      101
----
(2002, B2, 7, 102)
2002    b2      7       102

===> test_get_timestamp(1001, 91, 60, 101)
1001    91      60      101

===> test_get_length(1001, 91, 60, 101)
1001    91      60      101

===> test_get_status(1001, 91, 60, 101)
1001    91      60      101

===> test_get_data1(1001, 91, 60, 101)
1001    91      60      101

===> test_get_data2(1001, 91, 60, 101)
1001    91      60      101

===> test_set_timestamp(999)
999     91      60      101

===> test_set_status_length(1001, 0x91, 60, 101)
1001    91      60      101
----
length(1001, 0x91, 60, 101)
3
----
USING BAD INPUT: test_set_status_length(1001, 0xC1, 60, 100)
1001    c1      60
----
USING BAD INPUT: length(1001, 0xC1, 60, 100)
2

===> test_set_data1(1001, 0x91, 60, 101) -> 99
1001    91      99      101

===> test_set_data2(1001, 0x91, 60, 101) -> 99
1001    91      60      99

===> test_is_status_8n
true
1001    81      60      101
false
1001    91      60      101

===> test_is_status_9n
true
1001    91      60      101
false
1001    81      60      101

===> test_is_status_An
true
1001    a1      60
false
1001    91      60      101

===> test_is_status_Bn
true
1001    b1      60      101
false
1001    91      60      101

===> test_is_status_Cn
true
1001    c1      60
false
1001    91      60      101

===> test_is_status_Dn
true
1001    d1      60      101
false
1001    91      60      101

===> test_is_status_En
true
1001    e1      60      101
false
1001    91      60      101

===> test_is_status_Fn
# 0xFn status_ not processed
true
# 0xFn status_ not processed

===> test_is_note_off
true
1001    81      60      101
true
1001    92      60      0
false
1001    93      60      101
false
1001    a3      60      101

===> test_is_note_on
true
1001    92      60      101
false
1001    92      60      0
false
1001    b3      60      101

Submission Format

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
    

hw22_LastnameFirstname_LastnameFirstname

vsc22_submit.png

Author: John Ellinger

Created: 2020-01-30 Thu 15:38

Validate