Skip to content

Instantly share code, notes, and snippets.

@justinsalamon
Created February 15, 2016 17:42
Show Gist options
  • Save justinsalamon/a46923f9c6ab58237585 to your computer and use it in GitHub Desktop.
Save justinsalamon/a46923f9c6ab58237585 to your computer and use it in GitHub Desktop.
Evaluation code used for MIREX multi-f0 Note Tracking subtask. This is the "new" code by Zhiyao Duan that has been used on the "Su" dataset for this task (I think...?) Raw
function Results = ErrorRate_MF0_NoteLevel(EstNote, GTNote, bUseOffset, FreqDevTh, OnsetDiff, OffsetDiff)
%function Results = ErrorRate_MF0_NoteLevel(EstNote, GTNote, bUseOffset, FreqDevTh, OnsetDiff, OffsetDiff)
% Note-level multi-F0 estimation error rate calculation. Compare a list of estimated notes with
% a list of ground-truth notes.
%
% Input
% - EstNote : estimated notes, each cell corresponds to a note: first line is frame number,
% second line is frequency in MIDI number
% - GTNote : ground-truth notes, the same format as EstNote
% - bUseOffset : (optional, default 0) the flag that if using offset criterion or not
% - FreqDevTh : (optional, default 0.5) frequency deviation threshold for considering pitch estimation error
% - OnsetDiff : (optional, default 0.05) the onset time difference criterion (in second)
% - OffsetDiff : (optional, default 0.2) the offset time difference criterion (in ratio of the length of reference length)
% Output
% - Results : Results
% - MulPre : Precision
% - MulRec : Recall
% - MulFme : F-measure
% - MulAcc : Accuracy
% - MulAOR : Average overlap ratio
% - OctPre : Precision without considering octave errors
% - OctRec : Recall without considering octave errors
% - OctFme : F-measure without considering octave errors
% - OctAcc : Accuracy without considering octave errors
% - OctAOR : Average overlap ratio without considering octave errors
%
% Author: Zhiyao Duan
% Created: 5/5/2009
% Last modified: 8/4/2014
if nargin<6 OffsetDiff=0.2; end
if nargin<5 OnsetDiff=0.05; end
if nargin<4 FreqDevTh=0.5; end
if nargin<3 bUseOffset=0; end
EstNoteNum = length(EstNote); % number of estimated notes
GTNoteNum = length(GTNote); % number of ground-truth notes
nCorrect = 0; % number of correctly estimated notes
AOR = 0; % average overlap ratio between estimated and ground-truth notes
nChromaCorrect = 0; % number of correctly estimated notes, without counting octave errors
ChromaAOR = 0; % average overlap ratio between estimated and ground-truth notes, without counting octave errors
% normal case
IsUsedEst = zeros(EstNoteNum, 1); % flag indicating if an estimated note has been matched
for gt_note = 1:GTNoteNum
gt_onset = GTNote{gt_note}(1,1); % ground-truth note onset time
gt_offset = GTNote{gt_note}(1,end); % ground-truth note offset time
gt_freq = mean(GTNote{gt_note}(2,:)); % ground-truth note average frequency (in MIDI number)
for est_note = 1:EstNoteNum
if IsUsedEst(est_note) == 0
est_onset = EstNote{est_note}(1,1); % estimated note onset time
est_offset = EstNote{est_note}(1,end); % estimated note offset time
est_freq = mean(EstNote{est_note}(2,:));% estimated note average frequency
if bUseOffset == 0 % offset difference is not involved in the criterion
if abs(est_freq - gt_freq) <= FreqDevTh ...
&& abs(est_onset - gt_onset) <= OnsetDiff
nCorrect = nCorrect + 1; % match
AOR = AOR ...
+ (min(est_offset, gt_offset) - max(est_onset, gt_onset)) ...
/ (max(est_offset, gt_offset) - min(est_onset, gt_onset));
IsUsedEst(est_note) = 1;
break;
end
else % offset difference is involved in the criterion
if abs(est_freq - gt_freq) <= FreqDevTh ...
&& abs(est_onset - gt_onset) <= OnsetDiff ...
&& abs(est_offset - gt_offset) <= OffsetDiff * (gt_offset-gt_onset)
nCorrect = nCorrect + 1; % match
AOR = AOR ...
+ (min(est_offset, gt_offset) - max(est_onset, gt_onset)) ...
/ (max(est_offset, gt_offset) - min(est_onset, gt_onset));
IsUsedEst(est_note) = 1;
break;
end
end
end
end
end
% chroma case
IsUsedEst = zeros(EstNoteNum, 1);
for gt_note = 1:GTNoteNum
gt_onset = GTNote{gt_note}(1,1); % ground-truth note onset time
gt_offset = GTNote{gt_note}(1,end); % ground-truth note offset time
gt_freq = mod(mean(GTNote{gt_note}(2,:)), 12); % ground-truth note average frequency (in MIDI number)
for est_note = 1:EstNoteNum
if IsUsedEst(est_note) == 0
est_onset = EstNote{est_note}(1,1); % estimated note onset time
est_offset = EstNote{est_note}(1,end); % estimated note offset time
est_freq = mod(mean(EstNote{est_note}(2,:)), 12); % estimated note average frequency
if bUseOffset == 0 % offset difference is not involved in the criterion
if (mod(est_freq - gt_freq, 12) <= FreqDevTh || mod(gt_freq - est_freq, 12) <= FreqDevTh) ...
&& abs(est_onset - gt_onset) <= OnsetDiff
nChromaCorrect = nChromaCorrect + 1; % match
ChromaAOR = ChromaAOR ...
+ (min(est_offset, gt_offset) - max(est_onset, gt_onset)) ...
/ (max(est_offset, gt_offset) - min(est_onset, gt_onset));
IsUsedEst(est_note) = 1;
break;
end
else % offset difference is involved in the criterion
if (mod(est_freq - gt_freq, 12) <= FreqDevTh || mod(gt_freq - est_freq, 12) <= FreqDevTh) ...
&& abs(est_onset - gt_onset) <= OnsetDiff ...
&& abs(est_offset - gt_offset) <= OffsetDiff * (gt_offset-gt_onset)
nChromaCorrect = nChromaCorrect + 1; % match
ChromaAOR = ChromaAOR ...
+ (min(est_offset, gt_offset) - max(est_onset, gt_onset)) ...
/ (max(est_offset, gt_offset) - min(est_onset, gt_onset));
IsUsedEst(est_note) = 1;
break;
end
end
end
end
end
% calculate statistics
Results.MulPre = nCorrect/nEstNote;
Results.MulRec = nCorrect/nGtNote;
Results.MulFme = 2*Results.MulPre*Results.MulRec ...
/ (Results.MulPre + Results.MulRec);
Results.MulAcc = nCorrect / (nEstNote + nGtNote - nCorrect);
Results.MulAOR = AOR/nCorrect;
if nCorrect==0
Results.MulFme = 0;
Results.MulAOR = 0;
end
Results.OctPre = nChromaCorrect/nEstNote;
Results.OctRec = nChromaCorrect/nGtNote;
Results.OctFme = 2*Results.OctPre*Results.OctRec ...
/ (Results.OctPre + Results.OctRec);
Results.OctAcc = nChromaCorrect / (nEstNote + nGtNote - nCorrect);
Results.OctAOR = ChromaAOR/nChromaCorrect;
if nChromaCorrect==0
Results.OctFme = 0;
Results.OctAOR = 0;
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment