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

Table of Contents

5.2 Class

Announcement Class 5_3 is Quiz 1.

Quiz 1 w2020 review

Test rules

  • Must be done in pencil
  • Bring an eraser
  • No calculators
  • You are allowed to bring one 8.5x11 sheet of paper with HANDWRITTEN notes on each side
  • Time limit is 60 minutes unless a disability exception has been made. Talk to me after class.

Terminal commands

What do these commands do

  • cd
  • pwd
  • ls
  • echo
  • grep
  • sed
  • rm -fR *

C++

What is the difference between

  • #include "file.h"
  • #include <file.h>?

What is a.out?

What is the size in bytes of the following C++ types on mac

  • char
  • short
  • int
  • long
  • above in bits

Write an example of each of these comment types

  • anywhere on single line
  • block comments
  • conditional comments

operators

  • +
  • -
  • *
  • /
  • %
  • Multiple meanings
    • +
    • *
    • &

Terms

  • extern
  • overloaded function
  • narrowing cast
  • default
  • byte
  • high nibble
  • low nibble

Interface and implementation files

  • which is .h and which is .cpp
  • what's the purpose of a .h file
  • what is a header guard and why are they used

Printing char

  • Given this definition
    • char c = 100;
  • You want std::cout to print a number instead of the letter d.
    • What are two C++ ways to do it?

Header guards

  • Why are they used?
  • Given two files myfile.h and myfile.cpp
    • Write an example header guard used in myfile.h
    • Write an example header guard used in myfile.cpp

Bullet proofing CMidiPacket

  • We used three tests to check CMidiPacket for different types of errors
    Explain what each test checked for.
    • googletest
    • invariant_checking
    • check_timestamps

The Big Six

Explain the purpose of

  • Constructor
  • Destructor
  • Copy constructor
  • Assignment operator
  • Move copy constructor (you can ignore for test)
  • Move assignment operator (you can ignore for test)


  • Give an example of each using class object A and B.
  • What does = default mean

What is :

  • an overloaded function
  • a virtual function
  • a pure virtual function
  • an abstract base class

What is a Markov chain?

Arithmetic operations

What is the output of each std::cout statement

void f1(int a)
{
  a += 10;
}
void f2(int &a)
{
  a += 10;
}
int main()
{
  int x = 10;
  f1(x);
  std::cout << x << std::endl;    // ==

  f2(x);
  std::cout << x << std::endl;      // ==
  std::cout << x / 6 << std::endl;  // ==;
  std::cout << x % 6 << std::endl;  // ==;
  return 0;
}

Bit manipulation \\

What is the output of each std::cout statement

#include <iostream>

int main()
{
  int x{0x9C};

  std::cout << std::hex << (0xF0 & x) << std::endl;
  std::cout << (0x0F & x) << std::endl;
}

Memory alignment

What does this code print

#include <iostream>

struct MidiPacket
{
  uint32_t timestamp;
  uint8_t status;
  uint8_t data1;
  uint8_t data2;
};

int main()
{
  std::cout << sizeof(MidiPacket) << std::endl;
}

The Big Six

Explain the purpose of

  • Constructor
  • Destructor
  • Copy constructor
  • Assignment operator
  • Move copy constructor (you can ignore for test)
  • Move assignment operator (you can ignore for test)


  • Give an example of each using class object A and B.
  • What does = default mean

MIDI

What MIDI messages are used to emulate these properties of sound in MIDI

  • pitch
  • duration
  • amplitude
  • timbre
  • location

status bytes and data bytes

  • What is the range of a data byte
  • What is the range of a status bytes
  • How many MIDI channels are available for every status byte
  • How do you tell what MIDI channel the status byte is sending to

What happens if you play these messages in MIDIDisply_DLS

# these are ok
# piano patch
0 c0 0
# organ patch
0 c1 18

# There's a problem here
# What happens?
0 90 60 100
500 91 64 100
1500 90 64 0

MIDI Note numbers

  • Middle C is defined as MIDI note number 60.
    • What is the MIDI note number of the next C on the piano keyboard one octave higher.
  • What is the MIDI note number range of the full 88 key piano keyboard.

MIDI Messages

  • How many instruments can play simultaneously?
  • What two status bytes have only one data byte?
  • How do you tell which MIDI channel the status byte affects?
  • The NON (note on) message has data1 and data2 bytes. Explain what each one does.
  • What are the two forms of a NOF (note off) message
  • What status byte is used to change instruments
  • What MIDI control message changes volume
  • What MIDI control message changes pan
  • What MIDI control message changes expression
  • How many different ways are there to change how loud a note sounds? How do you choose which one to use?

Timestamps

  • CMidiPacket stores all timestamps using a tempo of 60 beats per minute or one beat every 1000 milliseconds. How would you recalculate the timestamps to send the messages at a tempo of 120 bpm, 30 bpm, and 90 bpm. Round to nearest integer if necessary.

    Old timestamp tempo New timestamp
    1000 60 1000
    1800 60 1800
    1000 120  
    1800 120  
    1000 30  
    1800 30  
    1000 90  
    1800 90  
  • CMidiPacket stores timestamps in strictly ascending numerical (chronological) order.
    • Explain why sending of MIDI messages works best with delta times, or difference times.

Strings

  • How do you find the length of a string?
  • Given string s = "abcdefghi"
    • what is s[4]
    • what is the difference between s[10] and s.at(10)

Vector

  • give vector v = {2, 4, 6, 8, 10}
    • print the elements of vector v to std:cout using three different forms of a for loop.
  • how do you add an element to a vector
  • what does v.reserve(size_t n) do
  • when you sort a vector what operator function is used.

RegEx

Your given a list of firstname lastname grade separated by spaces. There are no spaces in any name or grade. Write a find/replace regular expressing to reorder the list as grade lastname firstname

Additional code that can be used in Class project 1

Nothing in this section needs to be turned in as homework.

Setup

Execute these commands in Terminal

cd ~/cs312
mkdir hw52
cd hw52
mkdir class52_examples
cd class52_examples
touch ex1_function_object.cpp
touch ex2_lambda_expression.cpp
touch ex3_lambda_with_function.cpp

std::for_each

This lab will explore the std::for_each(…) function from the STL <algorithm> library.

std::for_each(_InputIterator __first, _InputIterator __last, _Function __f)

for_each(…) applies function __f to every element in an STL container (vector) over the iterator range __first to __last.

The _Function __f is a function object or a lambda expression.

Function object
a C++ class with one class method that overrides the () operator.
exists outside the for_each() expression.
also called a functor.
Lambda expression
an anonymous function (not named).
similar to a function object.
can be defined inside the for_each() expression.
Lambda expression and named function
an existing function called by a lambda expression.

Here are three examples that will help with the homework.

Function object

ex1_function_object.cpp

Example 1 is a simple function object that adds 3 to every element of a std::vector<int>

Copy/paste.

// ex1_funcion_object.cpp
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

// Utility function
void print_vec(const std::string msg, const std::vector<int> &v)
{
  std::cout << msg;
  for (auto itr : v)
    std::cout << itr << " ";
  std::cout << std::endl;
}

// Function object override of operator()
class plus3
{
public:
  void operator()(int &n)
  {
    n += 3;
  }
};

// example using for_each
int main(int argc, char const *argv[])
{
  std::vector<int> v{1, 2, 3, 4, 5};
  print_vec("Before:\t", v);
  std::for_each(v.begin(), v.end(), plus3());
  print_vec("After:\t", v);
}

Build and Run

# cd ~/cs312/hw52_je/class52_examples
cl ex1_function_object.cpp && ./a.out

Output

Before: 1 2 3 4 5
After:  4 5 6 7 8

The plus3 function object
A function object is a simple class that overrides operator()(). The second () is the type of element that for_each() is iterating over. In order for the changed value to be returned it should be declared as a reference.

class plus3
{
public:
  void operator()(int &n)
  {
    n += 3;
  }
};

Lambda Expression

Example 2 converts the plus3 function object into a lambda expression.

Lambda expression for plus3

[](int &n) { n += 3; }

Syntax notes:

[]
represents how local variables are captured
  • [=] capture by value
  • [&] capture by reference
  • [] default, [=]?
(int &n)
the parameters to the lambda expression.
{ n += 3; }
the lambda function body.
Identical to the body of operator()(int &n) in the function object class.

ex2_lambda_expression.cpp

Copy/paste

// ex2_lambda_expression.cpp
#include <iostream>
#include <vector>
#include <algorithm>

// Utility function
void print_vec(const std::string msg, const std::vector<int> &v)
{
  std::cout << msg;
  for (auto itr : v)
    std::cout << itr << " ";
  std::cout << std::endl;
}

// example using lambda expression
int main(int argc, char const *argv[])
{
  std::vector<int> v{1, 2, 3, 4, 5};
  print_vec("Before:\t", v);
  std::for_each(v.begin(), v.end(), [](int &n) { n += 3; });
  print_vec("After:\t", v);
}

Build and Run

# cd ~/cs312/hw52_je/class52_examples
cl ex2_lambda_expression.cpp && ./a.out

Output

Before: 1 2 3 4 5
After:  4 5 6 7 8

Lambda expression with function.

Example 3 uses a lambda expression to call a regular function that takes parameters.

ex3_lambda_with_function.cpp

Copy/paste

// ex3_lambda_with_function.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

// Utility function
void print_vec(const std::string msg, const std::vector<int> &v)
{
  std::cout << msg;
  for (auto itr : v)
    std::cout << itr << " ";
  std::cout << std::endl;
}

// regular function to scale MIDI data1 data2 values
void scaleByPercent(int &n, float p, bool scaleUp = true)
{
  if (scaleUp)
    n += (n * p);
  else
    n -= (n * p);
  // check for min max MIDI data1 data2 limits
  if (n > 127)
    n = 127;
  if (n < 0)
    n = 0;
}

// example lambda expression with function
int main(int argc, char const *argv[])
{
  float pct{.10};
  // data2 velocities
  std::vector<int> v{60, 70, 80, 90, 100, 127};
  print_vec("Original:\t\t", v);
  std::for_each(v.begin(), v.end(), [=](int &n) { scaleByPercent(n, pct); });
  print_vec("Scale up 10%:\t\t", v);
  std::for_each(v.begin(), v.end(), [=](int &n) { scaleByPercent(n, .9, false); });
  print_vec("Scale down 90%:\t\t", v);
}

Build and Run

# cd ~/cs312/hw52_je/class52_examples
cl ex3_lambda_with_function.cpp && ./a.out

Output

Original:               60 70 80 90 100 127
Scale up 10%:           66 77 88 99 110 127
Scale down 90%:         6 7 8 9 11 12

Continue with the homework examples

The remaining hw52 assignments assume you have working copies of these classes (.h and .cpp) in your ~/cs312/common folder.

  • hw331_CMidiPacket
  • hw411_CMidiTrack
  • hw411_randUtils
  • hw423_CDelayMs
  • hw425_CAppleMidiSynth

All homework examples involve using for_each() to modify a std::vector<CMidiPacket>.

c521_splitTracks

This first assignment will read in a MIDIDisplay file with three tracks and split them into individual CMidiTrack's based on the MIDI channel. The pentatonicTrio.txt file I've included is my output from hw426_CScalesTrio using the major pentatonic scale. You'll end up with four tracks to experiment with.

  • v0 (soprano, channel 0, patch 11 vibraphone)
  • v1 (alto, channel 1, patch 12 marimba)
  • v2 (bass, channel 2, patch 32 acoustic bass)
  • vplay (v0+v1+v2 sorted)

Files from hw521_splitTracks will be used in other hw52 homework.

Setup

Execute in Terminal

cd ~/cs312/hw52
mkdir hw521_splitTracks
cd hw521_splitTracks
mkdir build
touch CMakeLists.txt
touch pentatonic_trio.txt
touch hw521_main.cpp
touch hw521_splitTracks.cpp
touch hw521_splitTracks.h

Copy paste these files into their vsCode counterparts. Using common folder files hw521_splitTracks built and ran without errors.

hw521_splitTracks.h

// hw521_splitTracks.h
#ifndef HW521_SPLITTRACKS_H_
#define HW521_SPLITTRACKS_H_

#ifndef HW331_CMIDIPACKET_H_
#include "hw331_CMidiPacket.h"
#endif

#include <vector>
#include <fstream>
#include <string>

using namespace CMP33;

// pentatonic_trio.txt must be in parent folder of build folder

extern std::vector<CMidiPacket> v0;
extern std::vector<CMidiPacket> v1;
extern std::vector<CMidiPacket> v2;

extern void splitTracks(const std::string &filename);

#endif // HW521_SPLITTRACKS_H_

hw521_splitTracks.cpp

#ifndef HW521_SPLITTRACKS_H_
#include "hw521_splitTracks.h"
#endif

#include <string>
#include <fstream>

using namespace CMP33;

// sort into tracks
std::vector<CMidiPacket> v0;
std::vector<CMidiPacket> v1;
std::vector<CMidiPacket> v2;

void splitTracks(const std::string &filename)
{
  std::fstream file;
  file.open(filename);
  if (!file.is_open())
  {
    std::cout << filename << " could not be opened" << std::endl;
  }

  std::string line;
  while (getline(file, line))
  {
    // std::cout << line << std::endl;
    CMidiPacket mp(line);
    // vplay.push_back(mp);
    if (mp.get_midi_channel() == 0)
    {
      v0.push_back(mp);
    }
    else if (mp.get_midi_channel() == 1)
    {
      v1.push_back(mp);
    }
    else if (mp.get_midi_channel() == 2)
    {
      v2.push_back(mp);
    }
  }
}

hw521_main.cpp

#ifndef HW521_SPLITTRACKS_H_
#include "hw521_splitTracks.h"
#endif

#ifndef HW423_CDELAYMS_H_
#include "hw423_CDelayMs.h"
#endif

#ifndef HW425_CAPPLEMIDISYNTH_H_
#include "hw425_CAppleMidiSynth.h"
#endif

#include <fstream>
using namespace CMP33;

int main(int argc, char const *argv[])
{
  std::vector<CMidiPacket> vplay;

  splitTracks("../pentatonic_trio.txt");

  std::copy(v0.begin(), v0.end(), std::back_inserter(vplay));
  std::copy(v1.begin(), v1.end(), std::back_inserter(vplay));
  std::copy(v2.begin(), v2.end(), std::back_inserter(vplay));
  std::sort(vplay.begin(), vplay.end());

  CDelayMs::s_tempo = 100;
  CAppleMidiSynth cams;

  for (auto itr : vplay)
  {
    cams.send(itr);
    std::cout << itr;
  }
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
set(app_NAME "hw521_splitTracks")
project(${app_NAME})

set(HOME "/Users/je")
set(COMMON "${HOME}/cs312/common")
set(app_SOURCES
    ${COMMON}/hw331_CMidiPacket.cpp
    ${COMMON}/hw411_randUtils.cpp
    ${COMMON}/hw423_CDelayMs.cpp
    ${COMMON}/hw425_CAppleMidiSynth.cpp
    hw521_splitTracks.cpp
    hw521_main.cpp
)

add_executable(${app_NAME} ${app_SOURCES})

target_include_directories(${app_NAME} PRIVATE ${COMMON})
target_compile_features(${app_NAME} PRIVATE cxx_std_17)
target_compile_options(${app_NAME} PRIVATE -g -Wall)

target_link_libraries(${PROJECT_NAME} PRIVATE "-framework AudioToolbox")
target_link_libraries(${PROJECT_NAME} PRIVATE "-framework CoreMIDI")
target_link_libraries(${PROJECT_NAME} PRIVATE  "-framework CoreAudio")
target_link_libraries(${PROJECT_NAME} PRIVATE  "-framework CoreFoundation")

pentatonic_trio.txt
Note: This file must use tabs to separate the CMidiPacket data elements. Sometimes browsers change tabs to spaces behind the scenes. This file has tabs on my Mac using Chrome as the browser. You can change runs of spaces to tabs in vsCode using this regular expression.

regEx1.png

Notes:

[^0-9a-fA-F]+
Brackets limit the search to digits 0 to 9 plus hex values a-f or A-F
The + after the brackets means 1 or more
The ^ inside the brackets negates the search, i.e. anything that isn't a digit or hex digit (spaces)
\t
replace selection with \t, a tab character.
0	c0	11
0	c1	12
0	c2	32
0	b2	7	100
0	b0	7	100
0	b1	7	127
0	b0	10	0
0	b2	10	64
0	b1	10	127
0	92	40	65
0	91	62	100
0	90	86	100
333	81	62	0
333	80	86	0
333	91	60	100
333	90	88	100
667	82	40	0
667	80	88	0
667	92	38	65
667	90	84	100
1000	80	84	0
1000	90	93	100
1333	81	60	0
1333	80	93	0
1333	91	64	100
1333	90	91	100
1334	82	38	0
1334	92	43	65
1667	82	43	0
1667	92	38	65
2000	82	38	0
2000	80	91	0
2000	81	64	0
2000	92	48	65
2000	91	69	100
2000	90	88	100
2333	82	48	0
2333	81	69	0
2333	92	45	65
2333	91	67	100
2334	80	88	0
2334	90	88	100
2666	81	67	0
2666	91	67	100
2667	80	88	0
2667	90	84	100
3000	82	45	0
3000	92	43	65
3333	82	43	0
3333	92	40	65
3334	80	84	0
3334	90	88	100
3666	81	67	0
3666	82	40	0
3666	92	38	65
3666	91	64	100
3668	80	88	0
3668	90	86	100
4001	80	86	0
4001	90	96	100
4333	82	38	0
4333	81	64	0
4333	92	36	65
4333	91	60	100
4334	80	96	0
4334	90	93	100
4666	81	60	0
4666	91	62	100
4667	80	93	0
4667	90	91	100
5000	82	36	0
5000	92	36	65
5333	82	36	0
5333	81	62	0
5333	92	40	65
5333	91	67	100
5334	80	91	0
5334	90	91	100
5668	80	91	0
5668	90	88	100
6000	82	40	0
6000	92	40	65
6001	80	88	0
6001	90	93	100
6333	82	40	0
6333	81	67	0
6333	92	48	65
6333	91	72	100
6668	80	93	0
6668	90	91	100
7000	81	72	0
7000	82	48	0
7000	92	45	65
7000	91	72	100
7333	81	72	0
7333	91	69	100
7335	80	91	0
7335	90	88	100
7666	81	69	0
7666	91	67	100
7667	82	45	0
7667	92	40	65
7669	80	88	0
7669	90	86	100
8000	82	40	0
8000	92	38	65
8002	80	86	0
8002	90	86	100
8333	82	38	0
8333	81	67	0
8333	92	36	65
8333	91	64	100
8335	80	86	0
8335	90	84	100
9000	82	36	0
9000	92	36	65
9002	80	84	0
9002	90	84	100
9333	82	36	0
9333	81	64	0
9333	92	36	65
9333	91	60	100
9666	81	60	0
9666	91	62	100
9669	80	84	0
9669	90	88	100
10000	82	36	0
10000	92	40	65
10003	80	88	0
10003	90	96	100
10333	82	40	0
10333	81	62	0
10333	92	48	65
10333	91	69	100
10336	80	96	0
10336	90	96	100
10666	82	48	0
10666	92	45	65
10669	80	96	0
10669	90	93	100
11333	82	45	0
11333	81	69	0
11333	92	43	65
11333	91	69	100
11336	80	93	0
11336	90	91	100
11666	82	43	0
11666	92	43	65
12000	81	69	0
12000	91	72	100
12003	80	91	0
12003	90	88	100
12333	82	43	0
12333	81	72	0
12333	92	40	65
12333	91	69	100
12337	80	88	0
12337	90	86	100
12666	82	40	0
12666	81	69	0
12666	92	38	65
12666	91	67	100
12670	80	86	0
12670	90	86	100
12999	82	38	0
12999	92	36	65
13003	80	86	0
13003	90	84	100
13666	82	36	0
13666	81	67	0
13666	92	38	65
13666	91	64	100
13670	80	84	0
13670	90	86	100
13999	82	38	0
13999	92	38	65
14003	80	86	0
14003	90	84	100
14336	80	84	0
14336	90	86	100
14666	81	64	0
14666	82	38	0
14666	92	43	65
14666	91	64	100
14999	82	43	0
14999	92	40	65
15003	80	86	0
15003	90	86	100
15333	81	64	0
15333	91	62	100
15337	80	86	0
15337	90	91	100
15666	82	40	0
15666	92	40	65
15670	80	91	0
15670	90	96	100
15999	82	40	0
15999	92	38	65
16000	81	62	0
16000	91	60	100
16003	80	96	0
16003	90	93	100
16333	81	60	0
16333	91	64	100
16336	80	93	0
16336	90	91	100
16666	82	38	0
16666	92	36	65
17003	80	91	0
17003	90	91	100
17333	81	64	0
17333	82	36	0
17333	92	40	65
17333	91	64	100
17337	80	91	0
17337	90	88	100
17666	82	40	0
17666	92	45	65
17670	80	88	0
17670	90	86	100
18003	80	86	0
18003	90	84	100
18333	82	45	0
18333	81	64	0
18333	92	45	65
18333	91	69	100
18336	80	84	0
18336	90	88	100
18666	82	45	0
18666	92	48	65
19000	81	69	0
19000	91	72	100
19003	80	88	0
19003	90	88	100
19333	82	48	0
19333	92	45	65
19337	80	88	0
19337	90	93	100
19667	81	72	0
19667	91	69	100
19670	80	93	0
19670	90	96	100
20000	82	45	0
20000	81	69	0
20000	92	43	65
20000	91	62	100
20003	80	96	0
20003	90	93	100
20333	81	62	0
20333	82	43	0
20333	92	40	65
20333	91	60	100
20336	80	93	0
20336	90	91	100
20666	81	60	0
20666	91	67	100
21000	82	40	0
21000	92	40	65
21003	80	91	0
21003	90	88	100
21333	82	40	0
21333	92	38	65
21337	80	88	0
21337	90	88	100
21666	81	67	0
21666	91	72	100
21670	80	88	0
21670	90	86	100
22000	82	38	0
22000	92	36	65
22003	80	86	0
22003	90	84	100
22336	80	84	0
22336	90	91	100
22666	81	72	0
22666	91	72	100
22667	82	36	0
22667	92	40	65
23000	82	40	0
23000	92	45	65
23003	80	91	0
23003	90	96	100
23333	81	72	0
23333	91	72	100
23337	80	96	0
23337	90	96	100
23666	81	72	0
23666	91	69	100
23667	82	45	0
23667	92	45	65
23670	80	96	0
23670	90	96	100
23999	81	69	0
23999	91	67	100
24000	82	45	0
24000	92	48	65
24003	80	96	0
24003	90	93	100
24332	81	67	0
24332	91	64	100
24667	82	48	0
24667	92	45	65
24670	80	93	0
24670	90	91	100
25332	81	64	0
25332	91	64	100
25334	82	45	0
25334	92	43	65
25337	80	91	0
25337	90	88	100
25667	82	43	0
25667	92	40	65
25671	80	88	0
25671	90	86	100
25999	81	64	0
25999	91	62	100
26004	80	86	0
26004	90	86	100
26332	81	62	0
26332	91	60	100
26334	82	40	0
26334	92	40	65
26337	80	86	0
26337	90	84	100
26665	81	60	0
26665	91	67	100
26667	82	40	0
26667	92	38	65
27004	80	84	0
27004	90	88	100
27334	82	38	0
27334	92	36	65
27338	80	88	0
27338	90	86	100
27665	81	67	0
27665	91	62	100
27671	80	86	0
27671	90	84	100
28001	82	36	0
28001	92	43	65
28004	80	84	0
28004	90	84	100
28334	82	43	0
28334	92	48	65
28665	81	62	0
28665	91	62	100
28671	80	84	0
28671	90	93	100
29001	82	48	0
29001	92	48	65
29005	80	93	0
29005	90	93	100
29332	81	62	0
29332	91	72	100
29334	82	48	0
29334	92	48	65
29338	80	93	0
29338	90	96	100
29665	81	72	0
29665	91	69	100
29671	80	96	0
29671	90	93	100
29998	81	69	0
29998	91	67	100
30001	82	48	0
30001	92	45	65
30004	80	93	0
30004	90	93	100
30331	81	67	0
30331	91	64	100
30668	82	45	0
30668	92	43	65
30671	80	93	0
30671	90	91	100
31001	82	43	0
31001	92	40	65
31005	80	91	0
31005	90	88	100
31331	81	64	0
31331	91	64	100
31338	80	88	0
31338	90	86	100
31668	82	40	0
31668	92	40	65
31671	80	86	0
31671	90	84	100
31998	81	64	0
31998	91	62	100
32001	82	40	0
32001	92	45	65
32004	80	84	0
32004	90	84	100
32665	81	62	0
32665	91	60	100
32668	82	45	0
32668	92	43	65
32671	80	84	0
32671	90	96	100
32998	81	60	0
32998	91	69	100
33001	82	43	0
33001	92	40	65
33005	80	96	0
33005	90	86	100
33331	81	69	0
33331	91	69	100
33338	80	86	0
33338	90	96	100
33668	82	40	0
33668	92	40	65
33671	80	96	0
33671	90	93	100
34001	82	40	0
34001	92	38	65
34004	80	93	0
34004	90	91	100
34331	81	69	0
34331	91	64	100
34334	82	38	0
34334	92	36	65
34671	80	91	0
34671	90	91	100
34998	81	64	0
34998	91	72	100
35001	82	36	0
35001	92	45	65
35005	80	91	0
35005	90	88	100
35331	81	72	0
35331	91	69	100
35334	82	45	0
35334	92	45	65
35338	80	88	0
35338	90	86	100
35664	81	69	0
35664	91	67	100
35671	80	86	0
35671	90	84	100
35997	81	67	0
35997	91	64	100
36001	82	45	0
36001	92	36	65
36004	80	84	0
36004	90	96	100
36334	82	36	0
36334	92	48	65
36671	80	96	0
36671	90	96	100
36997	81	64	0
36997	91	64	100
37001	82	48	0
37001	92	45	65
37005	80	96	0
37005	90	93	100
37338	80	93	0
37338	90	96	100
37664	81	64	0
37664	91	62	100
37668	82	45	0
37668	92	43	65
37671	80	96	0
37671	90	93	100
38001	82	43	0
38001	92	40	65
38004	80	93	0
38004	90	91	100
38331	81	62	0
38331	91	60	100
38664	81	60	0
38664	91	60	100
38668	82	40	0
38668	92	40	65
38671	80	91	0
38671	90	88	100
39001	82	40	0
39001	92	38	65
39005	80	88	0
39005	90	88	100
39334	82	38	0
39334	92	36	65
39338	80	88	0
39338	90	86	100
39664	81	60	0
39664	91	62	100
39671	80	86	0
39671	90	84	100
40001	82	36	0
40001	92	48	65
40004	80	84	0
40004	90	93	100
40334	82	48	0
40334	92	48	65
40664	81	62	0
40664	91	60	100
40671	80	93	0
40671	90	84	100
41001	82	48	0
41001	92	45	65
41005	80	84	0
41005	90	84	100
41334	82	45	0
41334	92	48	65
41338	80	84	0
41338	90	96	100
41664	81	60	0
41664	91	72	100
41671	80	96	0
41671	90	93	100
42001	82	48	0
42001	92	45	65
42004	80	93	0
42004	90	91	100
42331	81	72	0
42331	91	69	100
42664	81	69	0
42664	91	69	100
42668	82	45	0
42668	92	43	65
42671	80	91	0
42671	90	88	100
43001	82	43	0
43001	92	40	65
43005	80	88	0
43005	90	88	100
43338	80	88	0
43338	90	86	100
43664	81	69	0
43664	91	67	100
43668	82	40	0
43668	92	40	65
43671	80	86	0
43671	90	84	100
44001	82	40	0
44001	92	38	65
44004	80	84	0
44004	90	86	100
44334	82	38	0
44334	92	36	65
44664	81	67	0
44664	91	64	100
44671	80	86	0
44671	90	86	100
45001	82	36	0
45001	92	43	65
45005	80	86	0
45005	90	96	100
45334	82	43	0
45334	92	36	65
45338	80	96	0
45338	90	96	100
45664	81	64	0
45664	91	62	100
45671	80	96	0
45671	90	93	100
46001	82	36	0
46001	92	36	65
46004	80	93	0
46004	90	91	100
46331	81	62	0
46331	91	62	100
46334	82	36	0
46334	92	48	65
46664	81	62	0
46664	91	60	100
46671	80	91	0
46671	90	88	100
47001	82	48	0
47001	92	45	65
47005	80	88	0
47005	90	88	100
47338	80	88	0
47338	90	86	100
47664	81	60	0
47664	91	62	100
47668	82	45	0
47668	92	43	65
47671	80	86	0
47671	90	84	100
48001	82	43	0
48001	92	40	65
48004	80	84	0
48004	90	88	100
48664	81	62	0
48664	91	60	100
48668	82	40	0
48668	92	40	65
48671	80	88	0
48671	90	86	100
49001	82	40	0
49001	92	38	65
49005	80	86	0
49005	90	96	100
49338	80	96	0
49338	90	96	100
49664	81	60	0
49664	91	72	100
49668	82	38	0
49668	92	36	65
49671	80	96	0
49671	90	93	100
50331	81	72	0
50335	82	36	0
50338	80	93	0

Build and run

je$ cd build
je$ cmake .. && make && ./splitTracks_hw521

Output
The CMidiPacket output should be displayed as the sound is playing.

pentatonic_trio.mp3

c522_setVelocity

The bass track (v2) in pentatonic_trio.mp3 is too soft. Let's use for_each(…) to fix it. We'll need a function object to change the velocity, data2 of a NON message.

Setup

cd ~/cs312/hw52
mkdir hw522_setVelocity
cd hw522_setVelocity
mkdir build
cp ~/cs312/hw52/hw521_splitTracks/CMakeLists.txt .
cp ~/cs312/hw52/hw521_splitTracks/hw521_main.cpp ./hw522_main.cpp

## Remember to change boilerplate for hw522_main.cpp

CMakeLists.txt
Insert this line

set(HW521 "~/cs312/hw52/hw521_splitTracks")

Changes to CMakeLists.txt

  • set app_NAME to hw522_setVelocity
  • create HW521 variable shown above
  • fix pathname to hw521_splitTracks.cpp
  • rename hw521_main.cpp
  • add variable HW521 to target_include_directories

hw522_main.cpp

Copy/paste/fix.

#ifndef HW521_SPLITTRACKS_H_
#include "hw521_splitTracks.h"
#endif

#ifndef HW423_CDELAYMS_H_
#include "hw423_CDelayMs.h"
#endif

#ifndef HW425_CAPPLEMIDISYNTH_H_
#include "hw425_CAppleMidiSynth.h"
#endif

#include <fstream>
using namespace CMP33;

class SetVelocity
{
public:
  void operator()(CMidiPacket &mp)
  {
    std::cout << "You need to implement SetVelocity function object\n";
  }
};

int main(int argc, char const *argv[])
{
  std::vector<CMidiPacket> vplay;

  /*
    you need to call splitTracks with a relative pathname
    This was used in hw521_main:  splitTracks("../pentatonic_trio.txt");
    In this case pentatonic_trio.txt was in the parent folder from where the
    executable was located (build). So ../ referred to the parent folder of build

    In hw522_setVelocity the pentatonic_trio.txt file is still inside hw521_splitTracks
    Hint: ../../ is the parent of the parent folder
*/
  // call splitTracks( RELATIVE_PATHNAME );

  // this is from hw521_main.cpp and will cause an error in hw522_main.cpp
  splitTracks("../pentatonic_trio.txt");

  // ADD
  std::for_each(v2.begin(), v2.end(), SetVelocity());
  // END ADD

  std::copy(v0.begin(), v0.end(), std::back_inserter(vplay));
  std::copy(v1.begin(), v1.end(), std::back_inserter(vplay));
  std::copy(v2.begin(), v2.end(), std::back_inserter(vplay));
  std::sort(vplay.begin(), vplay.end());

// Uncomment when ready to test
#if 0
  CDelayMs::s_tempo = 100;
  CAppleMidiSynth cams;

  for (auto itr : vplay)
  {
    cams.send(itr);
    std::cout << itr;
  }
#endif
  return 0;
}

c523_setVelocity_lambda

Convert the setVelocity function object to a lambda expression and use the lambda expression inside the for_each() statement.

Setup

cd ~/cs312/hw52
mkdir hw523_setVelocity_lambda
cd hw523_setVelocity_lambda
mkdir build
cp ~/cs312/hw52/hw522_setVelocity/hw522_main.cpp hw523_main.cpp
cp ~/cs312/hw52/hw522_setVelocity/CMakeLists.txt .

## Remember to change boilerplate for hw522_main.cpp

CMakeLists.txt

Changes to CMakeLists.txt

  • set app_NAME to hw523_setVelocity_lambda
  • rename hw522_main.cpp

hw523_main.cpp

Copy/paste/fix.

#ifndef HW521_SPLITTRACKS_H_
#include "hw521_splitTracks.h"
#endif

#ifndef HW423_CDELAYMS_H_
#include "hw423_CDelayMs.h"
#endif

#ifndef HW425_CAPPLEMIDISYNTH_H_
#include "hw425_CAppleMidiSynth.h"
#endif

#include <fstream>
using namespace CMP33;

// setVelocity function object removed

int main(int argc, char const *argv[])
{
  std::vector<CMidiPacket> vplay;

  // What worked in hw522_ should also work for hw523_
  //splitTracks("../pentatonic_trio.txt");

  // Uncomment and add lambda function
  // std::for_each(v2.begin(), v2.end(), LAMBDA_FUNCTION_HERE);

// Uncomment when split tracks worked
#if 0
  std::copy(v0.begin(), v0.end(), std::back_inserter(vplay));
  std::copy(v1.begin(), v1.end(), std::back_inserter(vplay));
  std::copy(v2.begin(), v2.end(), std::back_inserter(vplay));
  std::sort(vplay.begin(), vplay.end());

  CDelayMs::s_tempo = 100;
  CAppleMidiSynth cams;

  for (auto itr : vplay)
  {
    cams.send(itr);
    std::cout << itr;
  }
#endif
  return 0;
}

c524_accentEveryNnotes

Use a lambda expression to call regular function to accent every N notes.

Setup

cd ~/cs312/hw52
mkdir hw524_accentEveryNnotes
cd hw524_accentEveryNnotes
mkdir build
cp ~/cs312/hw52/hw523_setVelocity_lambda/hw523_main.cpp hw524_main.cpp
cp ~/cs312/hw52/hw523_setVelocity_lambda/CMakeLists.txt .

## Remember to change boilerplate for hw522_main.cpp

CMakeLists.txt

Changes to CMakeLists.txt

  • set app_NAME to hw524_accentEveryNnotes
  • rename hw523_main.cpp

hw523_main.cpp

Copy/paste/fix.

// hw524_main.cpp
#ifndef HW521_SPLITTRACKS_H_
#include "hw521_splitTracks.h"
#endif

#ifndef HW423_CDELAYMS_H_
#include "hw423_CDelayMs.h"
#endif

#ifndef HW425_CAPPLEMIDISYNTH_H_
#include "hw425_CAppleMidiSynth.h"
#endif

#include <fstream>
using namespace CMP33;

void AccentEveryNnotes(CMidiPacket &mp, int modN, int loud, int soft)
{
  /* 
  create a static variable to keep a running count of every time this function
  has been called. I called it count.

  if mp is a NOF return;
  else if mp is a NON
     set data2 velocity to soft;
     if count mod N is zero set data2 velocity to loud
     increment count 
*/
}

int main(int argc, char const *argv[])
{
  std::vector<CMidiPacket> vplay;

  splitTracks("../../hw521_splitTracks/pentatonic_trio.txt");

  // set velocity for v2 using either method of hw52_ or hw63_

  // write a lambda expression to AccentEveryNnotes in for_each() for v0
  // write a lambda expression to AccentEveryNnotes in for_each() for v1
  // write a lambda expression to AccentEveryNnotes in for_each() for v2

  std::copy(v0.begin(), v0.end(), std::back_inserter(vplay));
  std::copy(v1.begin(), v1.end(), std::back_inserter(vplay));
  std::copy(v2.begin(), v2.end(), std::back_inserter(vplay));
  std::sort(vplay.begin(), vplay.end());

  CDelayMs::s_tempo = 100;
  CAppleMidiSynth cams;

  // you could play individual tracks like (auto itr : v2)
  for (auto itr : vplay)
  {
    cams.send(itr);
    std::cout << itr;
  }

  return 0;
}

Ideas for for_each()

std::for_each(v0.begin(), v0.end(), [](CMidiPacket &mp) { AccentEveryNnotes(mp, 3, 127, 65); });
std::for_each(v1.begin(), v1.end(), [](CMidiPacket &mp) { AccentEveryNnotes(mp, 3, 127, 65); });
std::for_each(v2.begin(), v2.end(), [](CMidiPacket &mp) { AccentEveryNnotes(mp, 3, 127, 65); });
std::for_each(v0.begin(), v0.end(), [](CMidiPacket &mp) { AccentEveryN(mp, 6, 127, 65); });
std::for_each(v1.begin(), v1.end(), [](CMidiPacket &mp) { AccentEveryN(mp, 9, 127, 65); });
std::for_each(v2.begin(), v2.end(), [](CMidiPacket &mp) { AccentEveryN(mp, 3, 127, 65); });
std::for_each(v0.begin(), v0.end(), [](CMidiPacket &mp) { AccentEveryN(mp, 3, 127, 65); });
std::for_each(v1.begin(), v1.end(), [](CMidiPacket &mp) { AccentEveryN(mp, 7, 127, 65); });
std::for_each(v2.begin(), v2.end(), [](CMidiPacket &mp) { AccentEveryN(mp, 4, 127, 65); });

Submission Format

Nothing needs to be turned in. You can use examples in your class project 1 if you choose to.

Author: John Ellinger

Created: 2020-02-05 Wed 13:19

Validate