CS 312 - Week 1.2
CS 312 Audio Programming Winter 2020

Table of Contents

1.2 Class

Notes for CMC labs

Shell prompt

The default shell prompt does not indicate what your current working directory is. You can change your shell prompt like this. It won't become permanent until you add it to your .bashrc file using the export term as shown in the last example. You can test various prompts by executing the following commands. The changes will appear instantly.

Mac Terminal

echo $PS1
# CMC

Set shell prompt to full pathname.

PS1="\w $"

Set shell prompt to last directory in full pathname.

PS1="\W $"

Set shell prompt to Volume:last directory user.

PS1="\h:\W \u\$"

In CMC you can append this to your .bashrc file.
No spaces surrounding =.

export PS1="<your_choice>"

Other choices from man bash.

When executing interactively, bash displays the primary prompt PS1 when it is ready to
read  a  command, and the secondary prompt PS2 when it needs more input to complete a
command. Bash displays PS0 after it reads a command but before executing it. Bash displays
PS4 as described above before  trac- ing each command when the -x option is enabled. Bash
allows these prompt strings to be customized by inserting a number of backslash-escaped
special characters that are decoded as follows:
  \a     an ASCII bell character (07)
  \d     the date in "Weekday Month Date" format (e.g., "Tue May 26")
  \D{format}
      the format is passed to strftime(3) and the result is inserted into the prompt  string;
     an  empty  format  results  in  a  locale-specific time representation.  The braces are
     required
  \e     an ASCII escape character (033)
  \h     the hostname up to the first `.'
  \H     the hostname
  \j     the number of jobs currently managed by the shell
  \l     the basename of the shell's terminal device name
  \n     newline
  \r     carriage return
  \s     the name of the shell, the basename of $0 (the portion following the final slash)
  \t     the current time in 24-hour HH:MM:SS format
  \T     the current time in 12-hour HH:MM:SS format
  \@     the current time in 12-hour am/pm format
  \A     the current time in 24-hour HH:MM format
  \u     the username of the current user
  \v     the version of bash (e.g., 2.00)
  \V     the release of bash, version + patch level (e.g., 2.00.0)
  \w     the current working directory, with $HOME abbreviated with a tilde
         (uses the  value  of the PROMPT_DIRTRIM variable)
  \W     the basename of the current working directory, with $HOME abbreviated with a tilde
  \!     the history number of this command
  \#     the command number of this command
  \$     if the effective UID is 0, a #, otherwise a $
  \nnn   the character corresponding to the octal number nnn
  \\     a backslash
  \[     begin  a  sequence  of non-printing characters, which could be used to embed a terminal
         control sequence into the prompt
  \]     end a sequence of non-printing characters

Class folder desktop icons

WCC startup scripts in detail

There were some issues in class 1.1 with the WCC setup. I've written the link below to explain in detail the scripts I created to setup the WCC lab environment for CS312. I'm unable to directly test your student accounts in WCC so I need your help in validating my approach.

Open and the link below and follow the directions.
Notify me if things you see are different from what I've written.

WCC startup.html

Continue with the Lab 1.2 section for this class.

Lab 1.2

Applications used in this lab

  • /Applications/Utility/Terminal
  • /Applications/Visual Studio Code
  • /Applications/MIDIDisplay_DLS

Open each of these Applications. They'll stay in the Dock until you logout.

hw11201.png

MIDIDisplay_DLS

Written by John Ellinger for CS312. You'll have the skills to write this by the end of the term. DLS refers to DownLoadable Sounds, a sample sound format that can be used in Audio plugins. Apple licensed a General MIDI sound set from Roland Corporation to use in its built in MIDI synthesizer.

I did not write this app with the degree of error checking and reporting necessary for a commercial program. It was designed a a tool for experimenting with MIDI messages in the Carleton Music Technology classes I've taught in the past. Feel free to send me an email or talk to me in class if you discover a reproducible error. Reproducible means you can write down the steps that produce the error.

Open MIDIDisplay_DLS

hw11204.png

Time Base

Leave at default Chronological Ms.

MIDI Inputs

Leave at default IAC Driver Bus 1.

MIDI Outputs

Leave at default IAC Driver Bus 1.

PPQ menu

Leave at default 480.

Tempo Slider

Changes the tempo (playback speed). Tempo changes are accurate only if the timestamp data was entered based on a tempo of 60 bpm.

Test Button

Non functional at this time. Will crash.

Record Button

Non functional unless a MIDI keyboard is connected and setup properly for Mac OS.

Play Button

Plays the MIDI messages in the window.

Stop Button

Sends a NOF message to notes 0-127 on all 16 MIDI channels. This command takes about four seconds to complete. The delay happens because MIDI can only send a a certain number of messages per millisecond. Sending all the messages at once could cause a "MIDI log jam."

Data Entry Area
The main window area is a text editor where you can enter MIDI data. It responds to the usual text editing commands.
Status Header

The status header above the Data Entry Area reminds you that each MIDI message must be entered in a specific number base. The status number is a hex value but is not prefixed by 0x. Data2 is in parentheses because some MIDI messages do not use it.

time status data1 (data2)
decimal hex decimal decimal
Conventions
  1. The MIDIDisplay_DLS data entry tempo is always 60 beats per minute.
  2. Rows beginning with a # are comments and will be ignored.
  3. One quarter note beat is 1000 milliseconds.
  4. MIDIDisplay_DLS does minimal error checking and expects your data to be error free.

MIDIDisplay_DLS test

Test 1
Copy/replace/paste into MIDIDisplay_DLS.
The # is a comment and only used visually separate the NON-NOF pairs. Click the Play button.

0  90  60  100
1000 80  60  0
#
1000  90  62  100
2000 80  62  0
#
2000  90  64  100
3000 80  64  0
#
3000  90  60  100
4000 80  60  0

If you don't hear any sound

  1. Check that the volume control on the computer is turned up.
  2. Occasionally a MIDI note gets "stuck" and remains sounding after you click the Stop button. \ The only remedy is to Quit MIDIDisplay_DLS and reopen.
  3. Ask me.

Play your hw112_helloMidi.cpp

Delete all text from MIDIDisplay_DLS.

Recompile hw112_helloMidi.cpp in Mac Terminal.

cd $HOME312/cs312/hw11
cl hw112_hellomidi.cpp
# Copy the output of a.out to the clipboard
./a.out | pbcoppy

Switch to MIDIDisplay_DLS and immediately paste. It should work.

Notes:

pbcopy, pbpaste
Apple commands for copying and pasting. pb refers to pasteboard an internal buffer that holds the text copied.
|
the pipe operator. The output of the command on the left becomes the input to the command on the right.

Play my hw111_helloMidi.txt

Copy/paste my helloMidi.txt into MIDIDisplay.

# A MIDI message contains three or four numbers separated by a single tab character
# number 1 is a time stamp in milliseconds in decimal format
# number 2 is a MIDI status message in hexadecimal format without the 0x prefix (range 0x80 - 0xFF)
# number 3 is a MIDI data1 message in decimal format (range 0 - 127)
# number 4 is a MIDI data2 message in decimal format (range 0 - 127)

# status 0xC0 begins a a patch change message
# indicating which instrument sound to use
# patch change messages do not use data2
# data1 is the instrument number.
0 c0  0

# status 0x90 begins a Note On (NON) message
# NON messages use both data1 and data2
# data1 is the MIDI note number that corresponds to
# keys on a piano where Middle C is note number 60
# data2 is the velocity or how loud or soft the note sounds
0 90  60  110

# status code 0x80 begins a Note Off (NOF) message
# NOF messages use both data1 and data2
# data1 is the MIDI note number that corresponds to
# keys on a piano where Middle C is note number 60
# data2 should be set to zero
900 80  60  0

# Every NON must be followed by a NOF with a later time stamp
1000  90  55  80
1400  80  55  0

# You can also send a NOF using a NON with a velocity of 0
1500  90  55  60
1900  90  55  0

# More NON-NOF pairs
2000  90  56  100
2900  80  56  0
3000  90  55  80
4200  80  55  0

# Another patch change
4999  c0  56

# More NON-NOF pairs
5000  90  59  110
5900  80  59  0
6000  90  60  127
8000  80  60  0

Set the tempo to around 160.
Click the Play button.
Play again and try changing the tempo while it's playing.

There are two patch change messages in helloMidi

time status data1 instrument
0 0xC0 0 piano
4999 0xC0 56 trumpet

General MIDI sound set

Edit in MIDIDisplay_DLS and change instruments as desired.
Remember to use zero based numbers.
Here's a list.
https://en.wikipedia.org/wiki/General_MIDI

Six properties of sound

Physics Music MIDI
Fundamental Frequency Pitch Note number
Duration Note Value Timestamp difference NON-NOF
Amplitude, Intensity, Power Dynamics Velocity, Volume Ctrl, Expression Ctrl
Spectrum, Fourier Analysis Timbre Patch Change
Stereo field Location Pan Ctrl
Envelope Articulation Built in, Volume Ctrl, Expression Ctrl

The following examples are meant to demonstrate using MIDI messages to modify the six properties of sound. Copy/replace/paste each example into MIDIDIsplay_DLS and play it.

Reset all controllers message

If you do these examples one after the other the changes made to Volume, Pan, Expression and Patch would carry over into the the next example. The Reset All Controllers (0xBn 121 0) message is used to return to a default state at the beginning of each example.

Pitch/frequency

The MIDIDisplay_DLS test demonstrated pitch using the first four notes of Frere Jacques.

# Reset all controllers
0  B0  121 0
#
0  90  60  100
1000 80  60  0
#
1000  90  62  100
2000 80  62  0
#
2000  90  64  100
3000 80  64  0
#
3000  90  60  100
4000 80  60  0

Frequency and pitch are often thought to be synonymous. However, there is a subtle distinction between them. A pure sine wave is the only sound that consists of one and only one frequency. Most musical sounds we hear contain a mix of several harmonically related frequencies. Jean Baptiste Fourier in the 1820's stated that every mathematical function f(x) can be expressed as a series of of sinusoids of integer multiples of x. The formula below is called the Fourier Series. We'll be using it later in the term to construct different types of waveforms.

\[anySound = \sum\limits_{n = 1}^\infty {{A_n}\sin (2\pi n{f_0} + {\theta _n})} \]

"F zero" or "f naught" is called the fundamental frequency. All other frequencies are integer multiples of f0 with different Amplitudes and phases.

Duration

The duration of each note in the first example was 1000 ms. (Legato in music).
In this example each note lasts 50 ms. (Staccato in music).

# Reset all controllers to default state
0  B0  121 0
#
0  90  60  100
50 80  60  0
#
1000  90  62  100
1050 80  62  0
#
2000  90  64  100
2050 80  64  0
#
3000  90  60  100
3050 80  60  0

Dynamics

In this example the notes gradually get softer using MIDI data2.
Dynamics in music use fff ff f mf mp p pp ppp from loudest to softest.

# Reset all controllers to default state
0  B0  121 0
#
0  90  60  127
500 80  60  0
#
1000  90  62  100
1500 80  62  0
#
2000  90  64  80
2500 80  64  0
#
3000  90  60  60
3500 80  60  0

Using the MIDI Control message (OxBn 7 data2) for volume with data2 kept constant.

# Reset all controllers to default state
0  B0  121 0
#
0  B0  7    127
0  90  60  100
500 80  60  0
#
1000  B0  7    100
1000  90  62  100
1500 80  62  0
#
2000  B0  7    80
2000  90  64  100
2500 80  64  0
#
3000  B0  7    60
3000  90  60  100
3500 80  60  0

Timbre

Pronounced "tam-burr" and refers to the tone color, or why the same note sounds different when played on a violin or clarinet. In digital audio it's because the amplitudes and phases of each sinusoid are different but the fundamental frequency is the same.

Using the MIDI patch change (0xCn data1) to change instruments.

# Reset all controllers to default state
0  B0  121 0
#
0  C0  11
0  90  60  127
800 80  60  0
#
1000  C0  17
1000  90  62  127
1800 80  62  0
#
2000  C0  66
2000  90  64  127
2800 80  64  0
#
3000  C0  100
3000  90  60  127
3800 80  60  0

Location/Stereo panorama

Using the MIDI control message for stereo panorama (0xBn 10 data2).
Usually referred to as pan control, or L/R balance. Far left = 0.
Center = 64.
Far right = 127.

# Reset all controllers to default state
0  B0  121 0
#
0  C0  11
0  B0  10  0
0  90  60  127
800 80  60  0
#
1000  C0  17
1000  B0  10  64
1000  90  62  127
1800 80  62  0
#
2000  C0  66
2000  B0  10  127
2000  90  64  127
2800 80  64  0
#
3000  C0  100
3000  B0  10  64
3000  90  60  127
3800 80  60  0

Envelope

The envelope of a sound is the outline of the waveform's amplitude changing over time. A guitar has a loud attack and dies away quickly. Strings, brass, and wind instruments can sustain a note and increase or decrease using pressure. Using the MIDI Control message for Expression (0xBn 11 data2).
The timestamp and data2 series between NON and NOF was created in Microsoft Excel using Fill/Series in the Edit menu.
In music this would be indicated by the terms crescendo, decrescendo.

# Reset all controllers to default state
0  B0  121 0
#
# cello
0  C0  42
0  B0  11  0
0  90  60  127
#
66  B0 11 63
132  B0 11 66
198  B0 11 69
264  B0 11 72
330  B0 11 75
396  B0 11 78
462  B0 11 81
528  B0 11 84
594  B0 11 87
660  B0 11 90
726  B0 11 93
792  B0 11 96
858  B0 11 99
924  B0 11 102
990  B0 11 105
1056  B0 11 108
1122  B0 11 111
1188  B0 11 114
1254  B0 11 117
1320  B0 11 120
1386  B0 11 123
1452  B0 11 126
1518  B0 11 127
1584  B0 11 123
1650  B0 11 120
1716  B0 11 117
1782  B0 11 114
1848  B0 11 111
1914  B0 11 108
1980  B0 11 105
2046  B0 11 102
2112  B0 11 99
2178  B0 11 96
2244  B0 11 93
2310  B0 11 90
2376  B0 11 87
2442  B0 11 84
2508  B0 11 81
2574  B0 11 78
2640  B0 11 75
2706  B0 11 72
2772  B0 11 69
2838  B0 11 66
2904  B0 11 63
2970  B0 11 60
#
3000 80  60  0

Playing a chord

# Reset all controllers to default state
0  B0  121 0
#
0  C0  0
0  90  60  100
0  90  64  100
0  90  67  100
0  90  72  100
#
2000  80  60  0
2000  80  64  0
2000  80  67  0
2000  80  69  0

Playing multiple channels

This example uses two MIDI channels out of a total of 16 available. Channel 10 (zero based 9) is reserved for drums. Channel 1 (zero based 0) is flute and channel 2 (zero based 1) is bassoon.

# Reset all controllers to default state
0  B0  121 0
#
0  C0  73
0  C1  70
#
0	90	67	100
0	91	55	100
#
900	80	67	0
900	81	55	0
#
1000	90	69	100
1000	91	53	100
#
1900	80	69	0
1900	81	53	0
#
2000	90	71	100
2000	91	50	100
#
2900	80	71	0
2900	81	50	0
#
3000	90	72	100
3000	91	48	100
#
3900	80	72	0
3900	81	48	0

Quit MIDI Display_DLS

If you still have time in class continue to the Homework section and start with vsCode settings.

Reading

MIDI

The MIDI Specification appeared in 1983 as a music industry hardware/software standard that allowed MIDI hardware devices made by different manufacturers (Roland, Yamaha, Korg …) to communicate directly with each other as well as communicate with different PC operating systems (DOS, Windows, Mac, Linux…). MIDI version 1 has been around for 37 years. In 2019 the MIDI version 2 specification was announced but hardware and software have yet to appear. It will be backward compatible with MIDI version 1.

My first computer was a Mac Plus that I purchased one week after it was introduced in 1986. Within a year I had written my first MIDI program. Two years later I was selling my first commercial MIDI program for jazz improvisiation on the Mac. It was written in Pascal, the language of the Mac operating system in those days.

MIDI Message Format

The official MIDI v.1 standard defines all MIDI messages to consist of a status byte followed by one or more data bytes.

A MIDI byte is an 8 bit unsigned integer. There are two types of bytes defined in MIDI: data bytes and status bytes.

Data bytes
have the range 0-127 (0x0-0x7F)
The MSB (Most significant bit in binary) is 0.
Example b01111111 = 0x7F
Status bytes
have the range 128-255 (0x80-0xFF).
The MSB (Most significant bit in binary) is 1.
Example b10000000 = 0x80

Status bytes

Eight types of status bytes are defined for particular message types. The n refers to one of the sixteen (0 - 0xF) MIDI channels the status byte affects.

Status Message type Number data bytes
0x8n Note Off (NOF) 2
0x9n Note On (NON) 2
0xAn Aftertouch 2
0xBn Control 2
0xCn Patch Change 1
0xDn Channel Pressure 1
0xEn Pitch Bend 2
0xFn System variable

The high four bits of a byte, called the high nibble, refer to the status message type.
The lower four bits, low nibble, refer to the MIDI channel.
A nibble is a small bite (byte). Get it?

You'll get used to thinking in hex for all status bytes. Its much easier to interpret 0x93 as a NON message for channel 3 (zero based) than seeing decimal 147.

MIDI Channels

There are sixteen MIDI channels available. MIDI allows you to write and play a song that uses sixteen different instruments simultaneously.

Users and user manuals prefer one based MIDI channels, 1 - 16.
Programmers use zero based hex value MIDI channels, 0-0xF (0-15).

Examples

A user would read "Set MIDI channel 1 to flute".
A programmer would code this MIDI message 0xC0 75.

Programmers send and receive zero based MIDI messages but should display user interface settings as one based.

Common MIDI messages

The MIDI messages we'll use the most often in CS312 are

0x8n Note Off (NOF) n is MIDI channel, 0 - 0xF
0x9n Note On (NON) n is MIDI channel, 0 - 0xF
0xBn Control n is control type, Volume, Pan, Mod Wheel, etc.
0xCn Patch Change n is instrument sound piano, trumpet, cello, etc.

The smallest C++ data type for an unsigned (non negative) 8 bit integer type is unsigned char. However, as you discovered in hw111 the char type outputs text by default. It's not the easiest way to display numbers. We'll deal with that later.

General MIDI sounds

General MIDI defines 128 different instruments and specifies the MIDI patch change number from 0-127 that is used to access each of them. Manufacturers use the GM defined numbers for each instrument but can implement the sounds how they choose.

DLS sounds

Apple's built in synthezier uses a sample based format called Downloadable Sounds (DLS). Apple licensed a complete set of General MIDI from Roland corporation.

Samples and MIDI

Imagine creating a MIDI piano sample library where every key on a concert piano was recorded in high quality stereo at eight different loudness levels from extremely soft to extremely loud. That would take 704 separate recordings referred to as samples. If each sample was five seconds long the sample library could easily be over 1.2 gigabytes.

When a MIDI keyboard key is pressed down, the software would have to determine the key number pressed and the force used in order to match it with the correct sample at the appropriate volume level. Each individual sample would have an attack section, sustain section, and release section. These sections would be marked and located by known sample offsets from the beginning of the sample. The attack section is played when the key goes down, the sustain section loops as long as the key is held down, and the release section is played when the key comes up. That's a lot of work, both in recording and editing the audio, and writing the software. For the best realtime performance you'd want to load the entire sample library in memory.

There are very high quality orchestral sample libraries used by TV and film composers that can cost upwards of $10,000. That's still cheaper than renting an orchestra and recording studio.

Mac Finder

Quicklook

Select any text file in Finder and press the spacebar to see it's contents. Type down arrow or up arrow to display the next file. I often use this to quickly look at source code files in a folder.

Hide/Show Dot files

Unix systems (Mac OS) have a number of files and directories that are normally hidden from the user because their filename begins with a dot (a period), for example .bash_profile that we'll see later. You can view hidden files in the Terminal using these commands. # is a comment, don't bother typing it.

cd # cd without arguments goes to your home directory
pwd # print working directory - the full pathname to your home directory
ls -a # list all (including invisible) files

At the top of the output there are probably a number of files and directories beginning with a dot.

Show hidden files

This lab will be much easier if we can make these files visible in the Mac Finder.

Keyboard shortcut
Cmd-Shift-. (Cmd-Shift-Period)

I've use these commands to always show hidden files.

defaults write com.apple.finder AppleShowAllFiles -boolean true
killall Finder

To make dot files hidden again, execute this command, but not now.

defaults write com.apple.finder AppleShowAllFiles -boolean false
killall Finder

Homework

This homework is to be done in the CMC labs.
Before starting the homework:

Reading

This Class 1.2 page, especially the MIDI and Mac Finder sections.

TCPP2
char § 1.4
Template § 6.1, 6.2
static_cast p. 53
formatting § 10.6
bitset § 13.4.2

vsCode settings

Choose Command Palette from the View menu.
Shortcut: Command-Shift-P

hw11205.png

Enter settings in the search bar and then select /Preferences: Open Settings (JSON)

hw11206.png

Note
If the settings.json window that opens is empty copy/paste the code below.
If the settings.json window already contains code between curly braces leave it there and append the statements between the curly braces just above the closing curly brace.
{
    "editor.multiCursorModifier": "ctrlCmd",
    "editor.formatOnPaste": true,
    "editor.formatOnSave": true,
    "editor.fontSize": 14,
    "window.zoomLevel": 0,
    "terminal.integrated.shell.osx": "/bin/bash",
    "terminal.integrated.fontSize": 14,
    "terminal.integrated.scrollback": 32000,
    "C_Cpp.clang_format_style": "Visual Studio",
    "C_Cpp.clang_format_path": "/usr/local/bin/clang-format",
    "terminal.integrated.cursorStyle": "line",
    "editor.tabSize": 2,
    "editor.insertSpaces": false,
    "[cpp]": {},
    "editor.defaultFormatter": "ms-vscode.cpptools",
    "clang-format.executable": "/usr/local/bin/clang-format",
    "clang-format.language.cpp.fallbackStyle": "LLVM",
    "clang-format.fallbackStyle": "LLVM",
    "window.restoreWindows": "none",
    "editor.minimap.enabled": false
}

Homework 1.2 Setup

First we'll turn your boilerplate executable into a command line tool.

Recompile hw111_boilerplate.cpp with this command.

cd $HOME312/cs312/hw11
cl hw111_boilerplate.cpp -o boilerplate
./boilerplate

You should see the output of boilerplate in the terminal.

Move boilerplate into the $HOME312/bin directory.

mv boilerplate $HOME312/bin/

Execute the boilerplate command.

boilerplate

You should see the text appear. This works because $HOME312/bin has been added to the $PATH environment variable.

Create the hw12 folders and files Execute these commands in Terminal.
You can copy the entire contents and paste into Terminal.

cd $HOME312/cs312
mkdir hw12
cd hw12
touch hw121_charOutput.cpp
touch hw122_charOutputTemplate.cpp
touch hw123_charLoop.cpp
touch hw124_asciiTool.cpp
touch hw125_printMajorScale.cpp
code . # . refers to the current directory, in this case

Vscode should open the $HOME312/cs312/hw12 directory with the five source files displayed on the left.

Now try this in Terminal

boilerplate | pbcopy
pbpaste >> hw121_charOutput.cpp

Open hw12_charOutput.cpp in vsCode and you should see your boilerplate text appear.
Edit the filename and the assignment lines.
The date and time should be current.
If the file on the right of >> doesn't exist it will be created.

You can use this method to add boilerplate to the other four homework files.

Notes:

>>
the redirection operator. \ The output of the command on the left (must be text) is redirected to the file on the right.
A double angle >> appends the text at the end of the file.
A single angle > deletes the content of the file before appending.
Be careful when you use the single angle for redirection.
pbcopy, pbpaste
Apple commands for copying and pasting.
pb refers to pasteboard, an internal buffer that holds the copied text.
|
the pipe operator.
The output of the command on the left becomes the input to the command on the right.

hw121_charOutput.cpp

Copy/paste this code. Add the code below the boilerplate header.

#include <iostream>

int main()
{
  // MIDI message
  unsigned char status = 144;
  char data1 = 60;
  char data2 = 100;

  std::cout << "status: = " << status << std::endl;
  std::cout << "data1: = " << data1 << std::endl;
  std::cout << "data2: = " << data2 << std::endl;
}

Open the vsCode Terminal with Ctrl-` (Control-backtick).

Compile and run the program in vsCode terminal.
Try this shortcut: type cl hw121<TAB>.
The TAB key auto-completes file and command names.

cl hw121_charOutput.cpp -o hw121_charOutput && ./hw121_charOutput

Output
You'd expect to see numbers but instead you see this.

hw11202.png

Assignment hw121

Modify the program to display the actual number assigned to the three variables. You must keep the type char. You want the program to display the output shown below.

hw11203.png

Question: Why did this happen?
Append a block comment at the end of your source code and explain.

hw122_charOutputTemplate.cpp

Assignment hw122

Implement the template void print(T x, std::string msg) to display each char type as:

  • decimal
  • hexadecimal
  • hexadecimal with 0x prefix
  • binary
#include <iostream>
#include <string>
#include <bitset>

template <typename T>
void print(T x, std::string msg) {
 // you write
 }

int main() {
  char c = 9;
  signed char sc = 250;
  unsigned char uc = 144;

  print(c, "c: = ");
  print(sc, "sc: = ");
  print(uc, "uc: = ");
}

Hint: I used these.

  • static_cast<type>(value)
  • std::hex
  • std::dec
  • std::showbase
  • std::noshowbase
  • std::bitset<8>

The reading assignment above and Google will help. Use Google to figure out what std libraries to include for the above statements.

Why use a template
The reason is to avoid writing three separate functions that would all use the same code in the function body.

void print(char x, std::string msg);
void print(signed char x, std::string msg);
void print(unsigned char x, std::string msg);

Compile and run
You'll get a compiler warning but you'll still get output.

warning: implicit conversion from 'int'
     to 'signed char' changes value from 250 to -6 [-Wconstant-conversion]
 signed char sc = 250;

Output

c: = 9
c: = 9
c: = 0x9
c: = 00001001

sc: = -6
sc: = fffffffa
sc: = 0xfffffffa
sc: = 11111010

uc: = 144
uc: = 90
uc: = 0x90
uc: = 10010000

Warnings are good but they need to be fixed.
Fix the error by changing the signed char value to 50.

Output

c: = 9
c: = 9
c: = 0x9
c: = 00001001

sc: = 50
sc: = 32
sc: = 0x32
sc: = 00110010

uc: = 144
uc: = 90
uc: = 0x90
uc: = 10010000

When you use a plain char type to represent numbers there is no range checking. Using signed char and unsigned char incorrectly will issue a warning when you compile the program but it will still run. You should make it a habit to fix compiler warnings.

hw123_charLoop.cpp

This program is supposed to print the ascii characters from 0 to 127 but instead goes into an infinite loop.

#include <iostream>

int main() {
  for (char c = 0; c <= 127; ++c)
    std::cout << static_cast<int>(c) << " = " << c << std::endl;
}
Compile and run

Press Ctrl-C to exit the loop.

Assignment hw123

Fix it.

Output when fixed

0 =
1 =
2 =
3 =
4 =
5 =
6 =
7 =
8 =
9 =
10 =

11 =

12 =

13 =
14 =
15 =
16 =
17 =
18 =
19 =
20 =
21 =
22 =
23 =
24 =
25 =
26 =
27 =
8 =
29 =
30 =
31 =
32 =
33 = !
34 = "
35 = #
36 = $
37 = %
38 = &
39 = '
40 = (
41 = )
42 = *
43 = +
44 = ,
45 = -
46 = .
47 = /
48 = 0
49 = 1
50 = 2
51 = 3
52 = 4
53 = 5
54 = 6
55 = 7
56 = 8
57 = 9
58 = :
59 = ;
60 = <
61 = =
62 = >
63 = ?
64 = @
65 = A
66 = B
67 = C
68 = D
69 = E
70 = F
71 = G
72 = H
73 = I
74 = J
75 = K
76 = L
77 = M
78 = N
79 = O
80 = P
81 = Q
82 = R
83 = S
84 = T
85 = U
86 = V
87 = W
88 = X
89 = Y
90 = Z
91 = [
92 = \
93 = ]
94 = ^
95 = _
96 = `
97 = a
98 = b
99 = c
100 = d
101 = e
102 = f
103 = g
104 = h
105 = i
106 = j
107 = k
108 = l
109 = m
110 = n
111 = o
112 = p
113 = q
114 = r
115 = s
116 = t
117 = u
118 = v
119 = w
120 = x
121 = y
122 = z
123 = {
124 = |
125 = }
126 = ~
127 =

Question: What caused the infinite loop?/
Append your answer in a block comment at the end of your source code.

hw124_asciTool.cpp

This program will create a useful tool called ascii that you'll copy to your ~/bin folder.

Assignment hw124

Paste your corrected code from hw123_charLoop.cpp into hw124_asciiTool.cpp. Then modify it to produce the ASCII chart shown below. The chart displays the decimal value, hexadecimal value, and printed character for each ascii character 0-127.

Compile using this command to save the ascii tool directly to your ~/bin folder

cl hw124_asciiTool.cpp -o $HOME312/bin/ascii

Test it Execute

ascii

Output

0 (0) = 
1 (0x1) = 
2 (0x2) = 
3 (0x3) = 
4 (0x4) = 
5 (0x5) = 
6 (0x6) = 
7 (0x7) = 
8 (0x8) = 
9 (0x9) =
10 (0xa) =

11 (0xb) = 
12 (0xc) = 
13 (0xd) =
14 (0xe) = 
15 (0xf) = 
16 (0x10) = 
17 (0x11) = 
18 (0x12) = 
19 (0x13) = 
20 (0x14) = 
21 (0x15) = 
22 (0x16) = 
23 (0x17) = 
24 (0x18) = 
25 (0x19) = 
26 (0x1a) = 
27 (0x1b) = 
28 (0x1c) = 
29 (0x1d) = 
30 (0x1e) = 
31 (0x1f) = 
32 (0x20) =
33 (0x21) = !
34 (0x22) = "
35 (0x23) = #
36 (0x24) = $
37 (0x25) = %
38 (0x26) = &
39 (0x27) = '
40 (0x28) = (
41 (0x29) = )
42 (0x2a) = *
43 (0x2b) = +
44 (0x2c) = ,
45 (0x2d) = -
46 (0x2e) = .
47 (0x2f) = /
48 (0x30) = 0
49 (0x31) = 1
50 (0x32) = 2
51 (0x33) = 3
52 (0x34) = 4
53 (0x35) = 5
54 (0x36) = 6
55 (0x37) = 7
56 (0x38) = 8
57 (0x39) = 9
58 (0x3a) = :
59 (0x3b) = ;
60 (0x3c) = <
61 (0x3d) = =
62 (0x3e) = >
63 (0x3f) = ?
64 (0x40) = @
65 (0x41) = A
66 (0x42) = B
67 (0x43) = C
68 (0x44) = D
69 (0x45) = E
70 (0x46) = F
71 (0x47) = G
72 (0x48) = H
73 (0x49) = I
74 (0x4a) = J
75 (0x4b) = K
76 (0x4c) = L
77 (0x4d) = M
78 (0x4e) = N
79 (0x4f) = O
80 (0x50) = P
81 (0x51) = Q
82 (0x52) = R
83 (0x53) = S
84 (0x54) = T
85 (0x55) = U
86 (0x56) = V
87 (0x57) = W
88 (0x58) = X
89 (0x59) = Y
90 (0x5a) = Z
91 (0x5b) = [
92 (0x5c) = \
93 (0x5d) = ]
94 (0x5e) = ^
95 (0x5f) = _
96 (0x60) = `
97 (0x61) = a
98 (0x62) = b
99 (0x63) = c
100 (0x64) = d
101 (0x65) = e
102 (0x66) = f
103 (0x67) = g
104 (0x68) = h
105 (0x69) = i
106 (0x6a) = j
107 (0x6b) = k
108 (0x6c) = l
109 (0x6d) = m
110 (0x6e) = n
111 (0x6f) = o
112 (0x70) = p
113 (0x71) = q
114 (0x72) = r
115 (0x73) = s
116 (0x74) = t
117 (0x75) = u
118 (0x76) = v
119 (0x77) = w
120 (0x78) = x
121 (0x79) = y
122 (0x7a) = z
123 (0x7b) = {
124 (0x7c) = |
125 (0x7d) = }
126 (0x7e) = ~
127 (0x7f) = 

Question: Why is the ASCII chart is discontinuous at numbers 10, 11, 12, and 27?
Append a block comment at the end of your source code to explain why.
Add your boilerplate header and turn in as asciiTool_124.cpp

When your compile succeeds try these examples in a Terminal

grep (General Regular Expression Parser)

ascii | grep A

Output is not what's expected.

Binary file (standard input) matches

From man grep

Normally grep will simply print
``Binary file ... matches'' if files contain binary characters.

Also from man grep describing the -a or --text option

Treat all files as ASCII text...Use of this option forces grep
to output lines matching the specified pattern

Search for ascii value of A

ascii | grep --text
ascii | grep -a A
65 (0x41) = A
65 (0x41) = A

Search for ascii value a.

ascii | grep -a a

grep found every a in the file

10  (0xa)  =
26  (0x1a)  =
42  (0x2a)  =  *
58  (0x3a)  =  :
74  (0x4a)  =  J
90  (0x5a)  =  Z
97  (0x61)  =  a
106  (0x6a)  =  j
122  (0x7a)  =  z

Searching for <space>a or <space>A will work. The -i flag is case insensitive.

ascii | grep -ai " a"
65  (0x41)  =  A
97  (0x61)  =  a
ascii | grep -a 0
0 (0) =
1 (0x1) =
2 (0x2) =
3 (0x3) =
...
127 (0x7f) =
ascii | grep -a "= 0"
48 (0x30) = 0

hw125_printMajorScale.cpp

Assignment 1.2.5

Write a program to print the notes in MIDIDisplay_DLS format needed to play a major scale on any starting note. Then test your output in MIDIDisplay to verify that it works. Here's the outline of the program.

#include <iostream>

void print_major_scale( int start_note) {
  // you write
}

int main() {
  // whatever's needed
  int note = 60; // starting pitch
  print_major_scale( note );
}

Rules

timestamp
every NON (note on) is separated by 500 ms
every NOF (note off) timestamp occurs 400 ms after its corresponding NON
status (hex value without 0x)
use 90 for the NON status byte
use 80 for the note off NOF status byte
data1 (decimal value)
The pattern for the major scale starting at note zero is: 0, 2, 4, 5, 7, 9, 11, 12.
The same pattern could be expressed as: 0, 2, 2, 1, 2, 2, 2, 1 where those numbers were understood to be the differences between adjacent numbers in the pattern above.
If you add these offsets to any starting note it will form a major scale.
data2 (decimal value)
use 100 for all NON velocities
use 0 for all NOF velocities
NON and NOF pairs
every note on (NON) message MUST be followed by a matching note off (NOF).

Example
If you wanted to play a major scale starting on MIDI note number 60 (middle C) the notes (data1) used would be:

# using offsets from starting note 0 2 4 5 7 9 11 12
60 + 0 = 60
60 + 2 = 62
60 + 4 = 64
60 + 5 = 65
60 + 7 = 67
60 + 9 = 69
60 + 11 = 71
60 + 12 = 72
# using adjacent differences after starting note 2 2 1 2 2 2 1
60 = 60 # starting note
60 + 2 = 62
62 + 2 = 64
64 + 1 = 65
65 + 2 = 67
67 + 2 = 69
69 + 2 = 71
71 + 1 = 72

Here's the beginning of the correct output.

0       90      60      100
400     80      60      0
500     90      62      100
900     80      62      0
1000    90      64      100
1400    80      64      0

Test it in MIDIDisplay_DLS to make sure it works.

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
    

Code to turn in

hw11_LastnameFirstname1_LastnameFirstname2
\342\224\234\342\224\200\342\224\200 hw121_charOutput.cpp
\342\224\234\342\224\200\342\224\200 hw122_charOutputTemplate.cpp
\342\224\234\342\224\200\342\224\200 hw123_charLoop.cpp
\342\224\234\342\224\200\342\224\200 hw124_asciiTool.cpp
\342\224\234\342\224\200\342\224\200 hw125_printMajorScale.cpp

Example boilerplate header. Use yours not my example.

/***************************************************************
hw111_boilerplate.cpp
Copyright (c) Carleton College CS312 free open source
Assignment: hw111_boilerplate
Man Super sman@carleton.edu
Woman Wonder wwoman@carleton.edu
DATE: 2019-12-15
TIME: 14:46:25
****************************************************************/

Author: John Ellinger

Created: 2020-01-08 Wed 20:25

Validate