Daniel@0
|
1 # Part of DML (Digital Music Laboratory)
|
Daniel@0
|
2 # Copyright 2014-2015 Steven Hargreaves; Samer Abdallah, University of London
|
Daniel@0
|
3
|
Daniel@0
|
4 # This program is free software; you can redistribute it and/or
|
Daniel@0
|
5 # modify it under the terms of the GNU General Public License
|
Daniel@0
|
6 # as published by the Free Software Foundation; either version 2
|
Daniel@0
|
7 # of the License, or (at your option) any later version.
|
Daniel@0
|
8 #
|
Daniel@0
|
9 # This program is distributed in the hope that it will be useful,
|
Daniel@0
|
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Daniel@0
|
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Daniel@0
|
12 # GNU General Public License for more details.
|
Daniel@0
|
13 #
|
Daniel@0
|
14 # You should have received a copy of the GNU General Public
|
Daniel@0
|
15 # License along with this library; if not, write to the Free Software
|
Daniel@0
|
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Daniel@0
|
17
|
Daniel@0
|
18 # -*- coding: utf-8 -*-
|
Daniel@0
|
19 __author__="hargreavess, abdallahs, wolffd"
|
Daniel@0
|
20
|
Daniel@0
|
21 import sys
|
Daniel@0
|
22 from csvutils import *
|
Daniel@0
|
23 from pitchutils import *
|
Daniel@0
|
24 from aggregate import *
|
Daniel@0
|
25 from rdflib import RDF, RDFS
|
Daniel@0
|
26 from rdfutils import parse_xsd_duration, event_ns, tl_ns, af_ns
|
Daniel@0
|
27 from n3Parser import get_rdf_graph_from_n3
|
Daniel@0
|
28 from semitone_hist import notes_histogram, transcription_from_csv, transcription_from_n3
|
Daniel@0
|
29 from key_tonic_hist import tonic_from_n3, tonic_from_csv
|
Daniel@0
|
30
|
Daniel@0
|
31 # Compute aggregate pitch histogram from a list of input transcriptions.
|
Daniel@0
|
32 def aggregate(transcriptions_tonics,opts):
|
Daniel@0
|
33 parser_table = { 'n3':transcription_from_n3,
|
Daniel@0
|
34 'csv':transcription_from_csv }
|
Daniel@0
|
35
|
Daniel@0
|
36 hist = 12*[0] # will be aggragate histogram
|
Daniel@0
|
37 def add_no_norm(h):
|
Daniel@0
|
38 for x in range(0, 12): hist[x] += h[x]
|
Daniel@0
|
39
|
Daniel@0
|
40 def add_norm(h):
|
Daniel@0
|
41 total=sum(h)
|
Daniel@0
|
42 for x in range(0, 12): hist[x] += h[x]/total
|
Daniel@0
|
43
|
Daniel@0
|
44 if opts['normalisation']=='piece': add_to_hist=add_norm
|
Daniel@0
|
45 else: add_to_hist=add_no_norm
|
Daniel@0
|
46
|
Daniel@0
|
47 def accum(f):
|
Daniel@0
|
48 # subtract 1 from tonic because tonic_from_csv uses range 1 to 12 whilst this script uses 0 to 11
|
Daniel@0
|
49 add_to_hist( rotate_left( notes_histogram(decode_tagged(parser_table,f['transcription'])),
|
Daniel@0
|
50 argmax(find_tonic_histogram(f['tonic']['value'],f['duration']))))
|
Daniel@0
|
51
|
Daniel@0
|
52 # do_stuff
|
Daniel@0
|
53 stats=for_each(transcriptions_tonics,accum)
|
Daniel@0
|
54 return { 'result': discrete_hist([str(i) for i in range(1,13)],hist), 'stats':stats }
|
Daniel@0
|
55
|
Daniel@0
|
56 def rotate_left(x,n): return x[n:]+x[:n]
|
Daniel@0
|
57
|
Daniel@0
|
58 def argmax(x): return max(range(0,len(x)),key=x.__getitem__)
|
Daniel@0
|
59
|
Daniel@0
|
60 # Parse the qm-keydetector_tonic csv file, and generate
|
Daniel@0
|
61 # a tonic histogram
|
Daniel@0
|
62 def find_tonic_histogram(input_f_file,duration):
|
Daniel@0
|
63 tonic_hist = 12*[0]
|
Daniel@0
|
64 # ['time','keynr','label'] -> [time:float, keynr:in(range(0,12))]
|
Daniel@0
|
65 data = csv_map_columns(input_f_file,3,[lambda r:float(r[0]), lambda r:int(r[1])-1])
|
Daniel@0
|
66
|
Daniel@0
|
67 # build duration weighted histogram
|
Daniel@0
|
68 for idx in range(1,len(data[0]) ):
|
Daniel@0
|
69 tonic_hist[data[1][idx-1]] += data[0][idx] - data[0][idx-1]
|
Daniel@0
|
70
|
Daniel@0
|
71 # add last tonic if duration is given
|
Daniel@0
|
72 if duration>0:
|
Daniel@0
|
73 tonic_hist[data[1][-1]] += duration - data[0][-1]
|
Daniel@0
|
74
|
Daniel@0
|
75 return tonic_hist
|
Daniel@0
|
76
|