Mercurial > hg > silvet
changeset 223:51c18a17404a
Move some scripts about, make piano test script produce norm'd ref output as well as non-norm'd test output
author | Chris Cannam |
---|---|
date | Wed, 16 Jul 2014 13:29:38 +0100 |
parents | 69ac2d0770b8 |
children | 63bc32d6873b |
files | testdata/TRIOS-groundtruth/convert_midifileout.yeti testdata/TRIOS-groundtruth/convert_svout.yeti testdata/evaluation/batchProcessingEvaluate.m testdata/evaluation/computeNoteLevelAccuracy.m testdata/evaluation/convertMIDIToPianoRoll.m testdata/evaluation/run-piano.sh testdata/scripts/convert_midifileout.yeti testdata/scripts/convert_svout.yeti testdata/scripts/matlab/batchProcessingEvaluate.m testdata/scripts/matlab/computeNoteLevelAccuracy.m testdata/scripts/matlab/convertMIDIToPianoRoll.m |
diffstat | 11 files changed, 263 insertions(+), 256 deletions(-) [+] |
line wrap: on
line diff
--- a/testdata/TRIOS-groundtruth/convert_midifileout.yeti Wed Jul 16 12:46:18 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ - -// Convert the output of the midifile program -// (https://code.soundsoftware.ac.uk/projects/midifile) -// into lab file like those output from the test scripts. -// -// The midifile format contains lines looking like: -// -// <t>: Note: channel <c> duration <d> pitch <p> velocity <v> -// -// where t and d are defined in terms of the timebase and -// tempo, which are (usually) given in earlier lines: -// -// Timing division: <n> ppq -// <t>: Tempo: <n> -// -// Note that we assume 4 quarter-notes per bar, we don't parse time -// signatures, and we only handle the first tempo event. -// -// The output file format looks like: -// -// onset offset frequency -// -// with times in seconds. - -program convert_midifileout; - -usage () = - eprintln "\nUsage: convert_midifileout file.txt\n"; - -toFrequency m = - 440 * Math#pow(2.0, (m - 69) / 12.0); - -toTime timebase tempo t = - (t / timebase) * (60 / tempo); - -convert f = - (str = openInFile f "UTF-8"; - var timebase = 480; - var tempo = 120; - var tempoNowFixed = false; - for (str.lines ()) do line: - bits = strSplit ": " line; - if length bits > 1 then - if bits[0] == "Timing division" then - timebase := number (strReplace " ppq" "" bits[1]); - eprintln "Set timing division to \(timebase)"; - elif bits[1] == "Tempo" then - if tempoNowFixed then - failWith "Can't handle variable-tempo file"; - fi; - if length bits < 3 then - failWith "Too few bits in tempo line: \(line)"; - fi; - tempo := number (bits[2]); - tempoNowFixed := true; - eprintln "Set tempo to \(tempo)"; - elif bits[1] == "Note" then - tempoNowFixed := true; - if length bits < 3 then - failWith "Too few bits in note line: \(line)"; - fi; - noteparts = strSplit " " bits[2]; - if length noteparts < 8 then - failWith "Too few note parameters in line: \(line)"; - fi; - onset = toTime timebase tempo (number bits[0]); - duration = toTime timebase tempo (number noteparts[3]); - frequency = toFrequency (number noteparts[5]); - println "\(onset)\t\(onset + duration)\t\(frequency)"; - fi; - fi; - done; - str.close ()); - -case (list _argv) of -file::[]: convert file; -_: usage (); -esac; -
--- a/testdata/TRIOS-groundtruth/convert_svout.yeti Wed Jul 16 12:46:18 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ - -// Convert CSV file exported by Sonic Visualiser: -// -// onset,midinote,duration,level,label -// -// into lab file like those output from the test scripts: -// -// onset offset frequency - -program convert_svout; - -usage () = - eprintln "\nUsage: convert_svout file.csv\n"; - -toFrequency m = - 440 * Math#pow(2.0, (m - 69) / 12.0); - -convert f = - (str = openInFile f "UTF-8"; - for (str.lines ()) do line: - case list (strSplit "," line) of - onset::midinote::duration::_: - println "\(onset)\t\((number onset) + (number duration))\t\(toFrequency (number midinote))"; - _: - failWith "badly formed line: \(line)"; - esac; - done; - str.close ()); - -case (list _argv) of -file::[]: convert file; -_: usage (); -esac; -
--- a/testdata/evaluation/batchProcessingEvaluate.m Wed Jul 16 12:46:18 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -function [Pre,Rec,F] = batchProcessingEvaluate(folder) - -% Evaluate transcription output, using onset-only note-based metrics -% e.g. [Pre,Rec,F] = batchProcessingEvaluate('TRIOS-mirex2012-matlab'); - - -fileList = dir(folder); -fileCount = 0; - -for i=3:length(fileList) - - if(isdir([folder '/' fileList(i).name])) - - fileCount = fileCount + 1; - - - % Load ground truth - [pianoRollGT,nmatGT] = convertMIDIToPianoRoll([fileList(i).name '.mid'],10,1.0); - - - % Load transcripton nmat - nmat = load([folder '/' fileList(i).name '/' 'mix.lab']); - - - % Convert 3rd nmat column to MIDI scale - nmat(:,3) = round(12.*log2(nmat(:,3)./27.5) + 1); - - - % Compute onset-based note-level accuracy - [Pre(fileCount),Rec(fileCount),F(fileCount)] = computeNoteLevelAccuracy(nmat,nmatGT); - - end; -end; \ No newline at end of file
--- a/testdata/evaluation/computeNoteLevelAccuracy.m Wed Jul 16 12:46:18 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -function [Pre,Rec,F,Acc,PreOff,RecOff,FOff,AccOff] = computeNoteLevelAccuracy(nmat1,nmat2) - -% Compute note-level onset-only and onset-offset accuracy (Bay09) - - -% Initialize -if (isempty(nmat1)) Pre=0; Rec=0; F=0; Acc=0; return; end; - -% Total number of transcribed notes -Ntot = size(nmat1,1); - -% Number of reference notes -Nref = size(nmat2,1); - -% Number of correctly transcribed notes, onset within a +/-50 ms range -Ncorr = 0; -NcorrOff = 0; -for j=1:size(nmat2,1) - for i=1:size(nmat1,1) - if( (nmat1(i,3) == nmat2(j,3)) && (abs(nmat2(j,1)-nmat1(i,1))<=0.05) ) - Ncorr = Ncorr+1; - - % If offset within a +/-50 ms range or within 20% of ground-truth note's duration - if abs(nmat2(j,2) - nmat1(i,2)) <= max(0.05, 0.2 * (nmat2(j,2) - nmat2(j,1))) - NcorrOff = NcorrOff +1; - end; - - break; % In order to consider duplicates as false alarms - - end; - end; -end; - -% Number of onset-only P-R-F-Acc -Nfp = Ntot-Ncorr; -Nfn = Nref-Ncorr; -Rec = Ncorr/Nref; -Pre = Ncorr/Ntot; -F = 2*((Pre*Rec)/(Pre+Rec)); -Acc= Ncorr/(Ncorr+Nfp+Nfn); - -% Number of onset-offset P-R-F-Acc -NfpOff = Ntot-NcorrOff; -NfnOff = Nref-NcorrOff; -RecOff = NcorrOff/Nref; -PreOff = NcorrOff/Ntot; -FOff = 2*((PreOff*RecOff)/(PreOff+RecOff)); -AccOff= NcorrOff/(NcorrOff+NfpOff+NfnOff); \ No newline at end of file
--- a/testdata/evaluation/convertMIDIToPianoRoll.m Wed Jul 16 12:46:18 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -function [pianoRoll,newnmat] = convertMIDIToPianoRoll(filename,timeResolution,dur) - -% Time resolution is in msec -% eg. pianoRoll = convertMIDIToPianoRoll('bach_847MINp_align.mid',10); - -% Read MIDI file -nmat = readmidi(filename); - - -% Gather MIDI information -[n1 n2] = size(nmat); -lenthInSec = nmat(n1,6) + nmat(n1,7); -pianoRoll = zeros(88,round(lenthInSec*(1000/timeResolution))); - - -% Fill piano roll -for i=1:n1 - pianoRoll(round(nmat(i,4)-20),round(nmat(i,6)*(1000/timeResolution))+1:round(nmat(i,6)*(1000/timeResolution)+dur*nmat(i,7)*(1000/timeResolution))+1) = 1; -end; - -pianoRoll = pianoRoll'; - -% Plot piano roll -%figure; imagesc(imrotate(pianoRoll,0)); axis xy -%colormap('gray'); xlabel('time frame'); ylabel('Pitch'); - - -% Convert to non-MIDI nmat -newnmat(:,1) = nmat(:,6); -newnmat(:,2) = nmat(:,6)+nmat(:,7); -newnmat(:,3) = nmat(:,4)-20; \ No newline at end of file
--- a/testdata/evaluation/run-piano.sh Wed Jul 16 12:46:18 2014 +0100 +++ b/testdata/evaluation/run-piano.sh Wed Jul 16 13:29:38 2014 +0100 @@ -64,42 +64,49 @@ for instrument in $intended_instrument 0; do - echo - echo "For file $filename, instrument $instrument..." + for norm in no yes; do - # Don't normalise -- part of the point here is to make it work - # for various different levels - cp "$infile" "$tmpwav" + echo + echo "For file $filename, instrument $instrument, norm $norm..." - # generate the transform by interpolating the instrument parameter - cat transform.ttl | sed "s/INSTRUMENT_PARAMETER/$instrument/" > "$transfile" + if [ "$norm" = "no" ]; then + # Don't normalise -- part of the point here is to make + # it work for various different levels + cp "$infile" "$tmpwav" + else + # Normalise as reference + sox "$infile" "$tmpwav" gain -n -6.020599913279624 + fi - sonic-annotator \ - --writer csv \ - --csv-one-file "$outfile" \ - --csv-force \ - --transform "$transfile" \ - "$tmpwav" + # generate the transform by interpolating the instrument parameter + cat transform.ttl | sed "s/INSTRUMENT_PARAMETER/$instrument/" > "$transfile" - cat "$outfile" | \ - sed 's/^[^,]*,//' | \ - while IFS=, read start duration frequency level label; do - end=`echo "$start $duration + p" | dc` - echo -e "$start\t$end\t$frequency" - done > "$outfile.lab" + sonic-annotator \ + --writer csv \ + --csv-one-file "$outfile" \ + --csv-force \ + --transform "$transfile" \ + "$tmpwav" - for ms in 50; do - mark="" - if [ "$instrument" = "0" ]; then - mark=" <-- generic for $filename"; - else - mark=" <-- piano preset for $filename"; - fi; + cat "$outfile" | \ + sed 's/^[^,]*,//' | \ + while IFS=, read start duration frequency level label; do + end=`echo "$start $duration + p" | dc` + echo -e "$start\t$end\t$frequency" + done > "$outfile.lab" + + for ms in 50; do + mark="" + if [ "$instrument" = "0" ]; then + mark=" <-- generic for $filename (norm = $norm)"; + else + mark=" <-- piano preset for $filename (norm = $norm)"; + fi; + echo + echo "Validating against ground truth at $ms ms:" + "$yc" ./evaluate_lab.yeti "$ms" "../piano-groundtruth/$filename.lab" "$outfile.lab" | sed 's,$,'"$mark"',' + done; echo - echo "Validating against ground truth at $ms ms:" - "$yc" ./evaluate_lab.yeti "$ms" "../piano-groundtruth/$filename.lab" "$outfile.lab" | sed 's,$,'"$mark"',' - done; - - echo + done done done
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testdata/scripts/convert_midifileout.yeti Wed Jul 16 13:29:38 2014 +0100 @@ -0,0 +1,79 @@ + +// Convert the output of the midifile program +// (https://code.soundsoftware.ac.uk/projects/midifile) +// into lab file like those output from the test scripts. +// +// The midifile format contains lines looking like: +// +// <t>: Note: channel <c> duration <d> pitch <p> velocity <v> +// +// where t and d are defined in terms of the timebase and +// tempo, which are (usually) given in earlier lines: +// +// Timing division: <n> ppq +// <t>: Tempo: <n> +// +// Note that we assume 4 quarter-notes per bar, we don't parse time +// signatures, and we only handle the first tempo event. +// +// The output file format looks like: +// +// onset offset frequency +// +// with times in seconds. + +program convert_midifileout; + +usage () = + eprintln "\nUsage: convert_midifileout file.txt\n"; + +toFrequency m = + 440 * Math#pow(2.0, (m - 69) / 12.0); + +toTime timebase tempo t = + (t / timebase) * (60 / tempo); + +convert f = + (str = openInFile f "UTF-8"; + var timebase = 480; + var tempo = 120; + var tempoNowFixed = false; + for (str.lines ()) do line: + bits = strSplit ": " line; + if length bits > 1 then + if bits[0] == "Timing division" then + timebase := number (strReplace " ppq" "" bits[1]); + eprintln "Set timing division to \(timebase)"; + elif bits[1] == "Tempo" then + if tempoNowFixed then + failWith "Can't handle variable-tempo file"; + fi; + if length bits < 3 then + failWith "Too few bits in tempo line: \(line)"; + fi; + tempo := number (bits[2]); + tempoNowFixed := true; + eprintln "Set tempo to \(tempo)"; + elif bits[1] == "Note" then + tempoNowFixed := true; + if length bits < 3 then + failWith "Too few bits in note line: \(line)"; + fi; + noteparts = strSplit " " bits[2]; + if length noteparts < 8 then + failWith "Too few note parameters in line: \(line)"; + fi; + onset = toTime timebase tempo (number bits[0]); + duration = toTime timebase tempo (number noteparts[3]); + frequency = toFrequency (number noteparts[5]); + println "\(onset)\t\(onset + duration)\t\(frequency)"; + fi; + fi; + done; + str.close ()); + +case (list _argv) of +file::[]: convert file; +_: usage (); +esac; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testdata/scripts/convert_svout.yeti Wed Jul 16 13:29:38 2014 +0100 @@ -0,0 +1,34 @@ + +// Convert CSV file exported by Sonic Visualiser: +// +// onset,midinote,duration,level,label +// +// into lab file like those output from the test scripts: +// +// onset offset frequency + +program convert_svout; + +usage () = + eprintln "\nUsage: convert_svout file.csv\n"; + +toFrequency m = + 440 * Math#pow(2.0, (m - 69) / 12.0); + +convert f = + (str = openInFile f "UTF-8"; + for (str.lines ()) do line: + case list (strSplit "," line) of + onset::midinote::duration::_: + println "\(onset)\t\((number onset) + (number duration))\t\(toFrequency (number midinote))"; + _: + failWith "badly formed line: \(line)"; + esac; + done; + str.close ()); + +case (list _argv) of +file::[]: convert file; +_: usage (); +esac; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testdata/scripts/matlab/batchProcessingEvaluate.m Wed Jul 16 13:29:38 2014 +0100 @@ -0,0 +1,33 @@ +function [Pre,Rec,F] = batchProcessingEvaluate(folder) + +% Evaluate transcription output, using onset-only note-based metrics +% e.g. [Pre,Rec,F] = batchProcessingEvaluate('TRIOS-mirex2012-matlab'); + + +fileList = dir(folder); +fileCount = 0; + +for i=3:length(fileList) + + if(isdir([folder '/' fileList(i).name])) + + fileCount = fileCount + 1; + + + % Load ground truth + [pianoRollGT,nmatGT] = convertMIDIToPianoRoll([fileList(i).name '.mid'],10,1.0); + + + % Load transcripton nmat + nmat = load([folder '/' fileList(i).name '/' 'mix.lab']); + + + % Convert 3rd nmat column to MIDI scale + nmat(:,3) = round(12.*log2(nmat(:,3)./27.5) + 1); + + + % Compute onset-based note-level accuracy + [Pre(fileCount),Rec(fileCount),F(fileCount)] = computeNoteLevelAccuracy(nmat,nmatGT); + + end; +end; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testdata/scripts/matlab/computeNoteLevelAccuracy.m Wed Jul 16 13:29:38 2014 +0100 @@ -0,0 +1,48 @@ +function [Pre,Rec,F,Acc,PreOff,RecOff,FOff,AccOff] = computeNoteLevelAccuracy(nmat1,nmat2) + +% Compute note-level onset-only and onset-offset accuracy (Bay09) + + +% Initialize +if (isempty(nmat1)) Pre=0; Rec=0; F=0; Acc=0; return; end; + +% Total number of transcribed notes +Ntot = size(nmat1,1); + +% Number of reference notes +Nref = size(nmat2,1); + +% Number of correctly transcribed notes, onset within a +/-50 ms range +Ncorr = 0; +NcorrOff = 0; +for j=1:size(nmat2,1) + for i=1:size(nmat1,1) + if( (nmat1(i,3) == nmat2(j,3)) && (abs(nmat2(j,1)-nmat1(i,1))<=0.05) ) + Ncorr = Ncorr+1; + + % If offset within a +/-50 ms range or within 20% of ground-truth note's duration + if abs(nmat2(j,2) - nmat1(i,2)) <= max(0.05, 0.2 * (nmat2(j,2) - nmat2(j,1))) + NcorrOff = NcorrOff +1; + end; + + break; % In order to consider duplicates as false alarms + + end; + end; +end; + +% Number of onset-only P-R-F-Acc +Nfp = Ntot-Ncorr; +Nfn = Nref-Ncorr; +Rec = Ncorr/Nref; +Pre = Ncorr/Ntot; +F = 2*((Pre*Rec)/(Pre+Rec)); +Acc= Ncorr/(Ncorr+Nfp+Nfn); + +% Number of onset-offset P-R-F-Acc +NfpOff = Ntot-NcorrOff; +NfnOff = Nref-NcorrOff; +RecOff = NcorrOff/Nref; +PreOff = NcorrOff/Ntot; +FOff = 2*((PreOff*RecOff)/(PreOff+RecOff)); +AccOff= NcorrOff/(NcorrOff+NfpOff+NfnOff); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testdata/scripts/matlab/convertMIDIToPianoRoll.m Wed Jul 16 13:29:38 2014 +0100 @@ -0,0 +1,31 @@ +function [pianoRoll,newnmat] = convertMIDIToPianoRoll(filename,timeResolution,dur) + +% Time resolution is in msec +% eg. pianoRoll = convertMIDIToPianoRoll('bach_847MINp_align.mid',10); + +% Read MIDI file +nmat = readmidi(filename); + + +% Gather MIDI information +[n1 n2] = size(nmat); +lenthInSec = nmat(n1,6) + nmat(n1,7); +pianoRoll = zeros(88,round(lenthInSec*(1000/timeResolution))); + + +% Fill piano roll +for i=1:n1 + pianoRoll(round(nmat(i,4)-20),round(nmat(i,6)*(1000/timeResolution))+1:round(nmat(i,6)*(1000/timeResolution)+dur*nmat(i,7)*(1000/timeResolution))+1) = 1; +end; + +pianoRoll = pianoRoll'; + +% Plot piano roll +%figure; imagesc(imrotate(pianoRoll,0)); axis xy +%colormap('gray'); xlabel('time frame'); ylabel('Pitch'); + + +% Convert to non-MIDI nmat +newnmat(:,1) = nmat(:,6); +newnmat(:,2) = nmat(:,6)+nmat(:,7); +newnmat(:,3) = nmat(:,4)-20; \ No newline at end of file