Uploaded by Jack Gala

Matlab Markov Music

advertisement
EE 305: Applied Probability
MATLAB Project: Markov Music - Fall 2019
Assigned: Friday, Nov. 8
Due: Friday, Dec. 6
1
Introduction
1.1
Project Overview
In this project, you will do the following:
1. Conduct a self-study on discrete-time Markov chains.
2. Create random music in MATLAB using discrete-time Markov chains.
1.2
MATLAB Learning Outcomes
While completing this assignment, you will learn the following about MATLAB:
1. How to create a two-dimensional matrix in MATLAB.
2. How to extract a row vector from a two-dimensional matrix in MATLAB.
3. How to generate random variables from a discrete PMF defined in a vector.
4. How to define and use a simple cell array.
5. How to access the fields of a struct.
1.3
Files
To complete this assignment, you will need the following files, which are posted on Piazza:
1. AddNote.m: A function that adds the signal of a note to a song. Type help AddNote to get
help information for this function.
2. CreateScale.m: A function that converts a cell array of note strings into note indices. Type
help CreateScale to get help information for this function.
3. PlayTune.m: A function that plays a song. Type help PlayTune to get help information for
this function.
1
4. SaveTune.m: A function that saves a song to a .wav file. Type help SaveTune to get help
information for this function.
5. parameters.m: This file contains parameters and constants that are used in the files described
above.
6. rando.m: A function that draws a random variable according to a given PMF.
7. mydatasample.m: A function that draws one sample randomly and uniformly from a data
vector.
2
2.1
Preliminaries
Notes on an 88-key Piano
In practice, when a piano string is excited (or any oscillator, from a guitar to a flute), it will
naturally vibrate at a series of distinct frequencies known as normal modes. The lowest normal
mode is known as the fundamental frequency, while the higher frequencies are called overtones.
Harmonics are overtones whose frequencies are integer multiples of the fundamental frequency
(including the fundamental frequency which is 1 times itself).
The fundamental frequency of each successive key on a standard modern 88-key piano is derived
by multiplying the previous key’s frequency by the twelfth root of two. The following equation gives
the frequency f of the nth key:
n−49
f (n) = 2 12 × 440 Hz,
where 440 Hz is the note A4, which is the 49th key on the piano.
2.2
Note Value and Tempo
A whole note has a length equal to four beats in 4/4 time, which is the most popular time signature
in American pop music. Half, quarter, eighth, and sixteenth notes have durations that are 1/2,
1/4, 1/8, and 1/16 the length of a whole note, respectively. The relative duration of a note with
respect to a whole note is called the note value.
The tempo of a piece of music is typically specified in beats per minute (BPM). Assuming 4
beats for a whole note, a note’s duration measured in seconds can be determined as:
4 × 60
× v seconds
BPM
where v is the note value.
2.3
Generating a Note Signal
The function AddNote, which is provided to you on Piazza, automatically generates the audio signal
of a given note as described in this subsection.
A note with fundamental frequency f0 (n) is generated as a weighted sum of the M overtones
(including the fundamental frequency):
M
X
2πfm (n)t
−λt
A
wm e
sin
, for t = tstart , . . . , tend .
Fs
m=1
2
where
ˆ n is the index of the key.
ˆ A is the intensity of the note, which can be thought of as the volume with which it is played
or how hard the key is struck.
ˆ wm is the weight of the mth overtone, with m = 0 corresponding to the fundamental frequency.
It is assumed that w0 = 1.
ˆ λ is the attenuation parameter, which causes the note’s signal amplitude to decay in time.
ˆ fm (n) is the frequency of the mth overtone/harmonic of key n, where fm (n) = mf0 (n).
ˆ Fs is the sampling frequency, i.e., the number of sound samples per second.
ˆ tstart is the time at which the note’s signal begins.
ˆ tend is the time at which the note’s signal ends.
2.4
Useful Resources
Some useful resources can be found at the following links:
1. Piano key frequencies: http://en.wikipedia.org/wiki/Piano_key_frequencies
2. Piano scales: http://www.pianoscales.org/
3. MATLAB cell array: http://www.mathworks.com/help/matlab/cell-arrays.html
4. MATLAB structures: http://www.mathworks.com/help/matlab/structures.html
3
New MATLAB Commands
You will now use the MATLAB Command Window to perform several operations to get more familiar with basic MATLAB and the functions that have been provided to you. To enter information
into the Command Window, simply put your cursor where you see the >> symbol. You can then
type a command and hit the ENTER key to execute it. Type in the following commands:
1. >> DMajorStr = {‘D3’,‘E3’,‘F#3’,‘G3’,‘A3’,‘B3’,‘C#4’,‘D4’}
This command creates a MATLAB cell array containing strings of the notes that are in the
D Major scale. A cell array is a complex and flexible data type. Cell arrays are similar to
vectors, but instead of each index pointing to a single number or character, as is the case
with vectors, each index of a cell array can point to a number, string of characters, or even
a vector. You will not need to know much about cell arrays to complete this project other
than the two commands that we show you in this document; however, if you are interested
in learning more about cell arrays, please see the online documentation that is linked to in
Section 2.4.
Let us look closer at the strings that define a note. The string ‘D3’ indicates the 3rd octave of
the note D. You can get different notes by changing the character, e.g., replacing ‘D’ with ‘E’.
3
You can change the octave by using a different number, e.g., replacing ‘3’ with ‘4’. Finally,
you can make the note sharp or flat by writing ‘D#3’ or ‘Db3’, respectively.
2. >> DMajorStr{3}
This returns the third string in the cell array DMajorStr, i.e., ‘F#3’. Note that you use the
notation {i} to return the ith entry of a cell array. This is in contrast to arrays, for which
you use the notation (i).
3. >> DMajor = CreateScale(DMajorStr)
The function CreateScale converts the cell array of note strings into a vector of note indices.
Each of these indices corresponds to one of the 88 keys on the piano.
4. Input the following code into a new MATLAB script file and then run it. In this code, random
notes are played with random durations, intensities, and attenuations. Note that the first line
of this script actually executes the script parameters.m, which creates the param structure. A
structure is a complex data type that groups multiple fields of related data into one variable.
For example, to access a field in the param structure you simply write param.varName, where
varName is the name of the field that you want. For more information about MATLAB
structures, see the link in Section 2.4. For more information about the custom MATLAB
function mydatasample, use the MATLAB help command.
Important: In the below code, some lines wrap-around to the next line. You must make
sure to keep these on a single line in your code; otherwise, MATLAB will throw an error. In
particular, if you copy-and-paste the below code, it will not work until you correct it.
% Demo 1: Independent and Identically Distributed Music Test
parameters % Load parameters from parameters . m
song = zeros (1 ,240* param . Fs ) ; % Initialize 240 seconds of song
samples
start = 1; % Index of first audio sample
for i = 1:30 % Generate 30 random notes
% Select random note , note duration , note intensity , and
note attenuation
note = mydatasample ( param . DMajor ) ;
duration = mydatasample ( param . durationSet ) ;
intensity = mydatasample ( param . intensitySet ) ;
attenuation = mydatasample ( param . attenuationSet ) ;
[ song , next ] = AddNote ( song , start , note , duration , intensity ,
attenuation , param ) ;
start = next ; % Index of next audio sample
end
mySong = song (1: next ) ; % Remove empty samples from song
PlayTune ( mySong , param ) ; % Play your tune !
4
We now introduce how to simulate a discrete-time Markov chain in MATLAB. Before you
input these commands, it is recommended that you conduct the discrete-time Markov chain
self-study as described in Section 4.1.
5. >> stateSet = [10 12 13 16];
This is a vector defining the set of states (right now, the states are arbitrary, but in the final
example they will represent notes from a scale). We refer to the values 10, 12, 13, and 16 as
states. When we write stateSet(i) we refer to i as the ith state index and stateSet(i) as
the ith state.
6. >> stateTPF = [0.75 0.25 0 0; 0 0.5 0.5 0; 0 0 0.5 0.5; 0 0 0.25 0.75]
This defines a 4x4 matrix. The first four numbers occupy the first row of the matrix. The
numbers after the first semicolon occupy the second row of the matrix. The numbers after the
second semicolon occupy the third row of the matrix, and so on. In other words, a semicolon
is used to separate rows of the matrix. Note that each row of a matrix must have the same
number of elements (in this case 4); otherwise, MATLAB will give you an error.
The 4x4 matrix in stateTPF actually represents a Markovian state-transition probability
matrix over the four states in stateSet. You can see that it is a state-transition probability
matrix because each of its rows contain positive elements that sum to 1.
7. >> stateTPF(2,3)
This gives us the probability of transitioning to the 3rd state (i.e., state 13) from the 2nd
state (i.e., state 12). In general, stateTPF(i,j) gives the probability of transitioning from
the ith state to the jth state.
8. >> stateTPF(2,:)
This gives us the conditional PMF of the next state, given that we are currently in the 2nd
state.
9. sum(stateTPF(2,:))
The built-in MATLAB function sum takes the sum of the values in an array (in this case, the
array represents the conditional PMF). If stateTPF(i,:) does not sum to 1, for all i, then
it is not a valid state transition probability matrix.
10. rando(stateTPF(2,:))
This returns a random next state index according to the conditional PMF. Given our definition
of stateTPF, if we start in the 2nd state, then we either remain in the 2nd state with
probability 0.5 or transition to the 3rd state with probability 0.5.
11. Input the following code into a new MATLAB script file and then run it. In this code, the
sequence of notes played follows a discrete-time Markov chain.
Important: In the below code, some lines wrap-around to the next line. You must make
sure to keep these on a single line in your code; otherwise, MATLAB will throw an error. In
particular, if you copy-and-paste the below code, it will not work until you correct it.
5
% Demo 2: Markov Chain Music Test
parameters % Load parameters from parameters . m
% Initialize 240 seconds of song samples
song = zeros (1 ,240* param . Fs ) ;
% Set the state set to the notes of the Phrygian dominant scale
stateSet = param . PhrygianDom ;
% Initialize the transition probability matrix
% (8 x8 matrix since there are 8 notes in the Phrygian dominant
scale )
% NOTE : The ellipsis (...) allow you to continue your code on
the next line .
stateTPF = [0.25 0.5 0 0 0 0 0 0.25;...
0.25 0.5 0.25 0 0 0 0 0;...
0 0.25 0.5 0.25 0 0 0 0;...
0 0 0.25 0.5 0.25 0 0 0;...
0 0 0 0.25 0.5 0.25 0 0;...
0 0 0 0 0.25 0.5 0.25 0;...
0 0 0 0 0 0.25 0.5 0.25;...
0.25 0 0 0 0 0 0.5 0.25];
stateIdx = 1; % Start in 1 st state
start = 1; % Index of first audio sample
for i = 1:30 % Generate 30 notes
note = stateSet ( stateIdx ) ; % Get note corresponding to
current state index
duration = param . durationSet (3) ; % All 1/4 notes
intensity = param . intensitySet ( end ) ; % All maximum intensity
attenuation = param . attenuationSet (45) ; % All high
attenuation
[ song , next ] = AddNote ( song , start , note , duration , intensity ,
attenuation , param ) ;
start = next ; % Index of next audio sample
% Markov state transition
stateIdx = rando ( stateTPF ( stateIdx ,:) ) ; % Get random next
state
end
mySong = song (1: next ) ; % Remove empty samples from song
PlayTune ( mySong , param ) ; % Play your tune !
% Save your tune to my Fi rs tM ar ko vM us ic . wav
6
SaveTune ( mySong , param , ' my Fi rs tM ar ko vM us ic ' ) ;
4
Assignment
4.1
What You Need to Do
1. Discrete-time Markov chain self-study: For this part of the project, you will teach
yourself about discrete-time Markov chains. I recommend that you start by reading Sections
7.1 and 7.2 in the textbook. You may also search Wikipedia and any other resources available.
Make sure to cite your sources. As part of your self-study, you must type up brief answers to
the following questions.
(a) What does the key word discrete-time refer to in discrete-time Markov chain?
(b) What is a state?
(c) What is a transition probability?
(d) What is the Markov property?
(e) What is a transition probability matrix? How should one interpret the row and column
indices of a transition probability matrix? What does a row in the transition probability
matrix represent?
(f) What is a transient state?
(g) What is a recurrent state?
(h) What is an absorbing state?
(i) What does it mean for a Markov chain to be time-homogeneous.
2. Let’s make music! The Markov chain music that we created in the final example of Section
3 was fairly boring: all notes had the same duration, intensity, and attenuation, and there
was very little structure or variation to the song. For this part of the project, I want you to
get creative and figure out how to make more interesting music using Markov chains.
The following is a list of suggestions ranging from easy to hard. You must implement
at least two (2) easy modifications and one (1) medium difficulty modification
to receive full credit on the assignment. You may implement a hard modification instead of a medium difficulty modification for extra credit. All of your
modifications must be integrated into a single song.
(a) [Easy] Add and use a new scale. You can find scales on one of the websites listed in
Section 2.4. You can add more scales to the param structure in parameters.m.
(b) [Easy] Insert rest (silence) into your song by using note index 89.
(c) [Easy] Change the sound of the instrument by modifying param.overtoneWeights in
parameters.m.
(d) [Easy] Change the sound of the instrument by assigning different decay rates to each
overtone. (Note: This is harder than the other easy modifications.)
(e) [Easy] Create longer sequences of music (more than 30 notes).
7
(f) [Easy] Come up with your own idea, but please check with the instructor to ensure that
it has the appropriate difficulty.
(g) [Medium] Generate separate Markov chains to not only randomly adapt the notes
played, but also randomly adapt their durations, intensities, and/or attenuations.
(h) [Medium] Use a Bernoulli process to randomly switch between two different transition
probability matrices or two different octaves of the same scale.
(i) [Medium] Have two instruments play at the same time. For example, they may use
different octaves, durations, intensities, attenuations, overtone weights, and/or transition
probability matrices.
(j) [Medium] Create a more structured song by looping your generated notes. For example,
you may generate one bar of music and repeat it several times. Variations on this
may have three repeated bars followed by a fourth unique bar, or the addition of new
instruments or note patterns for every set of four bars.
(k) [Medium] Come up with your own idea, but please check with the instructor to ensure
that it has the appropriate difficulty.
(l) [Hard] Define a second-order Markov chain, where the state is based on the last two
notes played, instead of only the previous note played.
(m) [Hard] Use MATLAB to create a graphical user interface (GUI) that is simple enough for
a grade school student to use to generate Markov music. For example, you may include
a drop down menu or other mechanism for selecting among several available scales. You
may include some user interface to allow people to change the transition probabilities
without them needing to understand the underlying details. You may include some
mechanism to overlay multiple instruments or create repeated loops.
(n) [Hard] Generate a Markov chain to jump around the Circle of Fifths (https://www.
youtube.com/watch?v=62tIvfP9A2w) while using another Markov chain to play notes
in each of the 12 scales.
(o) [Hard] Use the concepts of Prime, Inversion, Retrograde, and Retrograde Inversion
(https://www.youtube.com/watch?v=Dfr7GE28Qp8). For example, randomly generate
a bar of music using a Markov chain and then algorithmically generate its Inversion,
Retrograde, or Retrograde Inversion. You could also have multiple instruments playing
these different musical voices on top of each other.
(p) [Hard] Come up with your own idea, but please check with the instructor to ensure
that it has the appropriate difficulty.
4.2
What You Need to Turn In
You will submit the Markov music project through UBlearns. You will receive an announcement
when the submission system is open (it is not set up yet). Please carefully follow the instructions
below on how to package your submission.
Your entire submission must be packaged in a folder named <lastname> <firstname>, where
you will replace <lastname> with your last name and <firstname> with your first name. Compress
the entire folder containing the items below into a zip file named <lastname> <firstname>.zip.
You will upload this zip file to UBlearns. Your zip file must include the following items.
8
1. A typed document containing answers to the self-study questions that are given in Section
4.1. You must save this to a file with the name <lastname> <firstname>.pdf, where you
replace <lastname> with your last name and <firstname> with your first name.
2. In the same typed document, you must provide a brief description of the easy, medium, and
hard modifications that you made to generate your Markov chain music. That is, you should
describe in words the specific modifications that you made to the baseline Markov Chain
Music Test in order to create your song.
3. A saved copy of your song in .wav format. You must save the song to a file with the
name <lastname> <firstname>.wav, where you replace <lastname> with your last name
and <firstname> with your first name. This single WAV file must contain ALL of your
modifications.
4. Within your .zip file, include a folder with the name “code” that includes all of the MATLAB files that are needed to generate your song in MATLAB. This means that you need
to include every .m file provided to you in the assignment with whatever modifications that
you have made. I recommend that, before submission, you test all of the necessary code by
running your script from the “code” directory. If it executes properly for you, then it should
execute properly for us. The script that can be run to generate your song must be named
<lastname> <firstname>.m.
An example of a correctly formatted submission package is provided with the project.
The assignment is due at 11:59:59 PM on the due date.
4.3
What is this Project Worth?
The MATLAB assignments are worth 20% of your total grade. Each of the first three MATLAB
assignments are worth 100 points. This project is worth 200 points. You can receive an extra 50
points for completing a hard modification instead of a medium difficulty modification.
9
Download