Daniel@0: # Part of DML (Digital Music Laboratory) Daniel@0: # Copyright 2014-2015 Steven Hargreaves; Samer Abdallah, University of London Daniel@0: Daniel@0: # This program is free software; you can redistribute it and/or Daniel@0: # modify it under the terms of the GNU General Public License Daniel@0: # as published by the Free Software Foundation; either version 2 Daniel@0: # of the License, or (at your option) any later version. Daniel@0: # Daniel@0: # This program is distributed in the hope that it will be useful, Daniel@0: # but WITHOUT ANY WARRANTY; without even the implied warranty of Daniel@0: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Daniel@0: # GNU General Public License for more details. Daniel@0: # Daniel@0: # You should have received a copy of the GNU General Public Daniel@0: # License along with this library; if not, write to the Free Software Daniel@0: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Daniel@0: Daniel@0: # -*- coding: utf-8 -*- Daniel@0: __author__="hargreavess, abdallahs, wolffd" Daniel@0: Daniel@0: import sys Daniel@0: from csvutils import * Daniel@0: from pitchutils import * Daniel@0: from aggregate import * Daniel@0: from rdflib import RDF, RDFS Daniel@0: from rdfutils import parse_xsd_duration, event_ns, tl_ns, af_ns Daniel@0: from n3Parser import get_rdf_graph_from_n3 Daniel@0: from semitone_hist import notes_histogram, transcription_from_csv, transcription_from_n3 Daniel@0: from key_tonic_hist import tonic_from_n3, tonic_from_csv Daniel@0: Daniel@0: # Compute aggregate pitch histogram from a list of input transcriptions. Daniel@0: def aggregate(transcriptions_tonics,opts): Daniel@0: parser_table = { 'n3':transcription_from_n3, Daniel@0: 'csv':transcription_from_csv } Daniel@0: Daniel@0: hist = 12*[0] # will be aggragate histogram Daniel@0: def add_no_norm(h): Daniel@0: for x in range(0, 12): hist[x] += h[x] Daniel@0: Daniel@0: def add_norm(h): Daniel@0: total=sum(h) Daniel@0: for x in range(0, 12): hist[x] += h[x]/total Daniel@0: Daniel@0: if opts['normalisation']=='piece': add_to_hist=add_norm Daniel@0: else: add_to_hist=add_no_norm Daniel@0: Daniel@0: def accum(f): Daniel@0: # subtract 1 from tonic because tonic_from_csv uses range 1 to 12 whilst this script uses 0 to 11 Daniel@0: add_to_hist( rotate_left( notes_histogram(decode_tagged(parser_table,f['transcription'])), Daniel@0: argmax(find_tonic_histogram(f['tonic']['value'],f['duration'])))) Daniel@0: Daniel@0: # do_stuff Daniel@0: stats=for_each(transcriptions_tonics,accum) Daniel@0: return { 'result': discrete_hist([str(i) for i in range(1,13)],hist), 'stats':stats } Daniel@0: Daniel@0: def rotate_left(x,n): return x[n:]+x[:n] Daniel@0: Daniel@0: def argmax(x): return max(range(0,len(x)),key=x.__getitem__) Daniel@0: Daniel@0: # Parse the qm-keydetector_tonic csv file, and generate Daniel@0: # a tonic histogram Daniel@0: def find_tonic_histogram(input_f_file,duration): Daniel@0: tonic_hist = 12*[0] Daniel@0: # ['time','keynr','label'] -> [time:float, keynr:in(range(0,12))] Daniel@0: data = csv_map_columns(input_f_file,3,[lambda r:float(r[0]), lambda r:int(r[1])-1]) Daniel@0: Daniel@0: # build duration weighted histogram Daniel@0: for idx in range(1,len(data[0]) ): Daniel@0: tonic_hist[data[1][idx-1]] += data[0][idx] - data[0][idx-1] Daniel@0: Daniel@0: # add last tonic if duration is given Daniel@0: if duration>0: Daniel@0: tonic_hist[data[1][-1]] += duration - data[0][-1] Daniel@0: Daniel@0: return tonic_hist Daniel@0: