-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchordEstimate.m
125 lines (108 loc) · 4.19 KB
/
chordEstimate.m
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
% Chord Recognition Project @ CCRMA 2014
% Sub module 5: Chord Estimation
% desc: A basic chord estimation based on the fitness matrix
function [myChord Fitness_Matrix] = chordEstimate(myChroma,class,fmin,numchords,Template,doPlot,doPause)
% function: chordEstimate(Template,doPlot,doPause)
% input: myChroma - the chromagram
% class - chromagram classification versus time: '1=chord','2=silence','3=noise'
% Template - binary chord template
% doPlot - boolean, plot or not
% doPause - boolean, pause after each plot or not
% output: myChord - my estimated chords
% FitnessMatrix - The fitness matrix
% Note from Kitty: I've implemented two ways, one is by using the dot product,
% Another way is to use the Euclidean distance. I think they're pretty
% much the same thing. But maybe we can test if we have time?
%% Create Fitness Matrix
% Calculating dot product of numChords Template * Chromagram
% Templates: numchords * bpo
% Chromagram: bpo * frames = 12 * 1889
if 0
upperChroma = ones(size(myChroma))*mean(mean(myChroma));
nKeep = 12;
[nC,nF] = size(myChroma);
for f=1:nF
[sc,k] = sort(myChroma(:,f));
sk = k(end-nKeep+1:end);
upperChroma(sk,f) = myChroma(sk,f);
end
else
upperChroma = myChroma;
end
Fitness_Matrix = Template * upperChroma;
% Class =
% 1 for chord
% 2 for silence
% 3 for noise
nClass = length(class);
fmMin = min(min(Fitness_Matrix));
for m=1:nClass
if class(m) ~= 1
Fitness_Matrix(:,m) = fmMin; % make silence/noise 0
end
end
if doPlot
screensize = get(0,'screensize');
figPos = screensize([3,4,3,4]).*[0.6 0 0.4 0.4]; % upper right corner
figurepos(figPos);
% Plot the fitness matrix for interactive perusal:
if size(Fitness_Matrix,2)>2
mesh(Fitness_Matrix);
else
plot(Fitness_Matrix);
end
title('Fitness Matrix = TemplateMatrix * Chromagram = Chord Scores vs Time');
xlabel('Time (frames)');
ylabel('Major-Minor Chord Index');
zlabel('Magnitude (Measure of Fit)');
if doPause, disp('PAUSING'); pause; end
end
% Option 1: Pick up the template that maximize dot product
[~, myChord] = max(Fitness_Matrix);
%% Option 2: Calculating Euclidean Distance: See below
% Create Distance Matrix, find my chord sequence: mypath
% Calculate Euclidean Distance
% Creating a Distance Matrix of size 24 * num_of_frames
% such that D(x,y) represents the Euclidean Distance
% between Template(x,:) and Chroma_Matrix(:,y)
% Need to flip Chroma_Matrix (from 36*frame to frame*36)
% (between each frame of chroma matrix and each column in Template Matrix)
% code reference: "Matlab array manipulation tips and tricks" 10.4 (Acklam)
% X = Template; % Size: numchords * 36;
% Y = chroma_smooth'; % Size: frame * 36;
% m = 24; n = frameM; % define m,n
% Distance_Matrix = sqrt(sum(abs( repmat(permute(X, [1 3 2]), [1 n 1]) ...
% - repmat(permute(Y, [3 1 2]), [m 1 1]) ).^2, 3));
%
% Calculate the template that has the minimum distance for each frame
% [~, myChord] = min(Distance_Matrix);
% size(Fitness_Matrix)
%% Plot
if doPlot
screensize = get(0,'screensize');
figPos = screensize([3,4,3,4]).*[0.6 0 0.4 0.4]; % upper right corner
figurepos(figPos);
[pitches_M, pitches_m, pitches_M7, pitches_m7] = getPitches(fmin);
if numchords == 24,
chordn = [pitches_M;pitches_m; 'N '];
elseif numchords == 48,
chordn = [pitches_M; pitches_m; pitches_M7; pitches_m7; 'N '];
end;
M = size(Fitness_Matrix,2); %M: number of frames
% Plot the Fitness Matrix
imagesc(Fitness_Matrix); grid('on');
hold on;
plot(myChord,'-*k','linewidth',3); % Overlay estimated chord
title('Fitness Matrix = TemplateMatrix * Chromagram = Chord Scores vs Time');
set(gca,'YDir','normal');
set(gca,'YTick',1:numchords+1);
%set(gca,'YTick',1:numchords);
set(gca,'YTickLabel',chordn);
% set(gca,'XTick',1:100:M-1);
% secs = ((1:100:M)-1) * R/fs;
% set(gca,'XTickLabel',num2str(round(secs'))); %Round to seconds
% xlabel('Time (s)');
xlabel('Time (frames)');
if doPause, disp('PAUSING'); pause; end
hold off
end