Chris@138
|
1
|
Chris@138
|
2 // Take two lab files of the form
|
Chris@138
|
3 //
|
Chris@138
|
4 // onset offset frequency
|
Chris@138
|
5 //
|
Chris@138
|
6 // and report their onset-only note-level accuracy F-measure.
|
Chris@138
|
7
|
Chris@138
|
8 program evaluate_lab;
|
Chris@138
|
9
|
Chris@138
|
10 usage () =
|
Chris@138
|
11 (eprintln "\nUsage: evaluate_lab reqd reference.lab transcribed.lab\n";
|
Chris@138
|
12 eprintln "where reqd is the number of milliseconds allowed for timing error (+/-)\n");
|
Chris@138
|
13
|
Chris@138
|
14 toMIDIPitch f =
|
Chris@138
|
15 round (12 * (Math#log(f / 220) / Math#log(2)) + 57);
|
Chris@138
|
16
|
Chris@138
|
17 suck f =
|
Chris@138
|
18 (str = openInFile f "UTF-8"; // better to use readFile here, oh well
|
Chris@138
|
19 d = map do line:
|
Chris@138
|
20 case list (strSplit "\t" line) of
|
Chris@138
|
21 onset::offset::frequency::_:
|
Chris@138
|
22 { onset = number onset, midi = toMIDIPitch (number frequency) };
|
Chris@138
|
23 _:
|
Chris@138
|
24 failWith "badly formed line: \(line)";
|
Chris@138
|
25 esac;
|
Chris@138
|
26 done (str.lines ());
|
Chris@138
|
27 str.close ();
|
Chris@138
|
28 d);
|
Chris@138
|
29
|
Chris@138
|
30 select f = fold do r x: if f x then x::r else r fi done [];
|
Chris@138
|
31
|
Chris@138
|
32 evaluate permitted ref trans =
|
Chris@138
|
33 (reference = suck ref;
|
Chris@138
|
34 transcribed = suck trans;
|
Chris@138
|
35 accurate =
|
Chris@138
|
36 select do here :
|
Chris@138
|
37 any do other:
|
Chris@138
|
38 here.midi == other.midi and
|
Chris@138
|
39 abs (here.onset - other.onset) < permitted
|
Chris@138
|
40 done reference
|
Chris@138
|
41 done transcribed;
|
Chris@138
|
42 {
|
Chris@138
|
43 ntot = length transcribed,
|
Chris@138
|
44 nref = length reference,
|
Chris@138
|
45 ncorr = length accurate,
|
Chris@138
|
46 });
|
Chris@138
|
47
|
Chris@138
|
48 pc n =
|
Chris@138
|
49 int (n * 1000) / 10;
|
Chris@138
|
50
|
Chris@138
|
51 report { ntot, nref, ncorr } =
|
Chris@138
|
52 (nfp = ntot - ncorr;
|
Chris@138
|
53 nfn = nref - ncorr;
|
Chris@222
|
54 if nref == 0 then
|
Chris@222
|
55 println "ERROR: no events in reference!"
|
Chris@222
|
56 elif ntot == 0 then
|
Chris@222
|
57 println "WARNING: no events transcribed!"
|
Chris@222
|
58 else
|
Chris@222
|
59 rec = ncorr / nref;
|
Chris@222
|
60 pre = ncorr / ntot;
|
Chris@222
|
61 f = if pre + rec == 0 then 0 else 2 * ((pre * rec) / (pre + rec)) fi;
|
Chris@222
|
62 acc = ncorr / (ncorr + nfp + nfn);
|
Chris@222
|
63 println "precision \(pc pre), recall \(pc rec), accuracy \(pc acc), F \(pc f)";
|
Chris@222
|
64 fi);
|
Chris@138
|
65
|
Chris@138
|
66 case (list _argv) of
|
Chris@138
|
67 reqd::ref::trans::[]: report (evaluate (number reqd / 1000) ref trans);
|
Chris@138
|
68 _: usage ();
|
Chris@138
|
69 esac;
|
Chris@138
|
70
|