Mercurial > hg > syncopation-dataset
changeset 38:cc38b3047ed9
updated syncopation.y to allow output of sync for a bar list
also fixed some problems in models and other modules
author | christopherh <christopher.harte@eecs.qmul.ac.uk> |
---|---|
date | Mon, 13 Apr 2015 23:06:49 +0100 |
parents | fefbe0d853c6 |
children | 02f69d16603d 6371e8f21f7d |
files | Syncopation models/LHL.py Syncopation models/PRS.py Syncopation models/TOB.py Syncopation models/music_objects.py Syncopation models/rhythm_parser.py Syncopation models/syncopation.py |
diffstat | 6 files changed, 89 insertions(+), 96 deletions(-) [+] |
line wrap: on
line diff
--- a/Syncopation models/LHL.py Mon Apr 13 22:36:51 2015 +0100 +++ b/Syncopation models/LHL.py Mon Apr 13 23:06:49 2015 +0100 @@ -8,6 +8,8 @@ terminalNodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order + + # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight. class Node: def __init__(self,nodeType,metricalWeight): @@ -57,14 +59,16 @@ print 'Error: the given parameters are not valid.' else: # If there is rhythm in previous bar, process its tree structure - if bar.get_previous_bar() != None: - prebarBinarySequence = bar.get_previous_bar().get_binary_sequence() + prevbar = bar.get_previous_bar() + if prevbar != None and not prevbar.is_empty(): + prebarBinarySequence = prevbar.get_binary_sequence() recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) - # Only keep the last note-type node - while terminalNodes[-1].nodeType != 'N': - del terminalNodes[-1] - del terminalNodes[0:-1] + if len(terminalNodes)>0: + # Only keep the last note-type node + while terminalNodes[-1].nodeType != 'N': + del terminalNodes[-1] + del terminalNodes[0:-1] # For the rhythm in the current bar, process its tree structure and store the terminal nodes recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
--- a/Syncopation models/PRS.py Mon Apr 13 22:36:51 2015 +0100 +++ b/Syncopation models/PRS.py Mon Apr 13 23:06:49 2015 +0100 @@ -25,12 +25,12 @@ # This function calculates the syncopation value (cost) for the sequence with the postbar_seq for a certain level. def syncopation_perlevel(subSequences): - print 'subSequences', subSequences + #print 'subSequences', subSequences total = 0 for l in range(len(subSequences)-1): - print 'cost', get_cost(subSequences[l], subSequences[l+1]) + #print 'cost', get_cost(subSequences[l], subSequences[l+1]) total = total + get_cost(subSequences[l], subSequences[l+1]) - print 'total this level', total + #print 'total this level', total normalised = float(total)/(len(subSequences)-1) return normalised
--- a/Syncopation models/TOB.py Mon Apr 13 22:36:51 2015 +0100 +++ b/Syncopation models/TOB.py Mon Apr 13 23:06:49 2015 +0100 @@ -4,10 +4,10 @@ ''' -from basic_functions import ceiling, find_divisor, is_prime +from basic_functions import ceiling, find_divisor, is_prime, velocity_sequence_to_min_timespan -def get_syncopation(bar, parameter = None): - binarySequence = bar.get_binary_sequence() +def get_syncopation(bar, parameters = None): + binarySequence = velocity_sequence_to_min_timespan(bar.get_binary_sequence()) sequenceLength = len(binarySequence) syncopation = 0
--- a/Syncopation models/music_objects.py Mon Apr 13 22:36:51 2015 +0100 +++ b/Syncopation models/music_objects.py Mon Apr 13 23:06:49 2015 +0100 @@ -115,7 +115,8 @@ velocitySequence += [0]*(noteSequence[-1].duration-1) # normalising velocity sequence between 0-1 - velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence]) + if max(velocitySequence)>0: + velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence]) return velocitySequence @@ -162,7 +163,7 @@ def get_velocity_sequence(self): if self.velocitySequence == None: - self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence) + self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence, self.get_bar_ticks()) return self.velocitySequence def get_binary_sequence(self): @@ -193,11 +194,23 @@ def get_bar_ticks(self): return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq) + def is_empty(self): + if max(self.get_velocity_sequence())>0: + return False + else: + return True + def to_string(self, sequenceType=None): + output = "t{"+self.timeSignature.to_string()+"}" + prev = self.get_previous_bar() + if prev!=None: + if prev.get_time_signature()==self.get_time_signature(): + output="" + if sequenceType==None or sequenceType=="v": - output = "v{"+self.get_velocity_sequence().to_string()+"}" + output += "v{"+self.get_velocity_sequence().to_string()+"}" else: - output = "y{"+self.get_note_sequence().to_string()+"}" + output += "y{"+self.get_note_sequence().to_string()+"}" return output
--- a/Syncopation models/rhythm_parser.py Mon Apr 13 22:36:51 2015 +0100 +++ b/Syncopation models/rhythm_parser.py Mon Apr 13 23:06:49 2015 +0100 @@ -10,6 +10,7 @@ from music_objects import * comment_sign = '#' + def discard_comments(line): if comment_sign in line: line = line[0:line.find(comment_sign)]
--- a/Syncopation models/syncopation.py Mon Apr 13 22:36:51 2015 +0100 +++ b/Syncopation models/syncopation.py Mon Apr 13 23:06:49 2015 +0100 @@ -3,102 +3,77 @@ Institution: Centre for Digital Music, Queen Mary University of London ''' +from rhythm_parser import * +from music_objects import * + def sync_perbar_permodel (model, bar, parameters=None): return model.get_syncopation(bar, parameters) - def syncopation_barlist_permodel(model, source, parameters=None): - total = 0 +def syncopation_barlist_permodel(model, source, parameters=None): + total = 0.0 + barResults = [] numberOfNotes = 0 + barlist = None + + if isinstance(source, BarList): + barlist = source + sourceType = "bar list" + elif isinstance(source, basestring): + #treat source as a filename + sourceType = source + if source[-4:]==".mid": + import readmidi + midiFile = readmidi.read_midi_file(source) + barlist = readmidi.get_bars_from_midi(midiFile) + + elif source[-4:]==".rhy": + #import rhythm_parser + barlist = read_rhythm(source) + else: + print "Error in syncopation_barlist_permodel(): Unrecognised file type." + else: + print "Error in syncopation_barlist_permodel(): unrecognised source type." + barsDiscarded=0 - for bar in barlist: - if sync_perbar_permodel(model, bar, parameters) != None: - total += sync_perbar_permodel(model, bar, parameters) - numberOfNotes += sum(bar.get_binary_sequence()) - else: - print 'Bar %d cannot be measured, returning None.' % barlist.index(bar) + if barlist!=None: + for bar in barlist: + if not bar.is_empty(): + barSyncopation = sync_perbar_permodel(model, bar, parameters) + else: + barSyncopation = None + print 'Bar %d cannot be measured because it is empty, returning None.' % barlist.index(bar) + + barResults.append(barSyncopation) + if barSyncopation != None: + total += barSyncopation + numberOfNotes += sum(bar.get_binary_sequence()) + else: + barsDiscarded += 1 + print 'Model could not measure bar %d, returning None.' % barlist.index(bar) - if model is WNBD: - total = (float) total/ numberOfNotes + import WNBD + if model is WNBD: + total = total / numberOfNotes -# def sync_perbar_permodel(seq, model, timesig = None, subdivision_seq = None, weight_seq = None, L_max = 5, prebar_seq = None, postbar_seq = None, strong_beat_level = None): -# syncopation = None + average = total / (len(barResults)-barsDiscarded) -# if seq == None or model == None: -# print 'Error: please indicate rhythm sequence and syncopation model.' + return {"summed_syncopation":total, "average_syncopation_per_bar":average, "source":sourceType, "number_of_bars":len(barResults), "number_of_bars_not_measured":barsDiscarded, "syncopation_by_bar":barResults} -# elif timesig == None and subdivision_seq == None: -# print 'Error: please indicate either time signature or subdivision sequence.' - -# else: -# while subdivision_seq == None: -# from basic_functions import get_subdivision_seq -# subdivision_seq = get_subdivision_seq(timesig, L_max) -# # The get_rhythm_category function is used to detect rhythm category: monorhythm or polyrhythm. -# # For monorhythms, all prime factors of the length of minimum time-span representation of this sequence are -# # elements of its subdivision_seq, otherwise it is polyrhythm; -# # e.g. prime_factors of polyrhythm 100100101010 in 4/4 is [2,3] but subdivision_seq = [1,2,2] for 4/4 -# def get_rhythm_category(): -# rhythm_category = 'mono' -# from basic_functions import get_min_timeSpan, find_prime_factors -# for f in find_prime_factors(len(get_min_timeSpan(seq))): -# if not (f in subdivision_seq): -# rhythm_category = 'poly' -# break -# return rhythm_category - -# rhythm_category = get_rhythm_category() -# if model == 'LHL': -# import LHL -# if weight_seq == None: -# weight_seq = range(0,-L_max,-1) -# syncopation = LHL.get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category) -# elif model == 'PRS': -# import PRS -# syncopation = PRS.get_syncopation(seq, subdivision_seq, postbar_seq, rhythm_category) -# elif model == 'TMC': -# import TMC -# if weight_seq == None: -# weight_seq = range(L_max+1,0,-1) -# syncopation = TMC.get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category) -# elif model == 'SG': -# import SG -# if weight_seq == None: -# weight_seq = range(L_max+1) -# syncopation = SG.get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category) -# elif model == 'KTH': -# import KTH -# syncopation = KTH.get_syncopation(seq, timesig, postbar_seq) -# elif model == 'TOB': -# import TOB -# syncopation = TOB.get_syncopation(seq) -# elif model == 'WNBD': -# import WNBD -# if strong_beat_level == None: -# if timesig == '4/4': -# strong_beat_level = 2 -# else: -# strong_beat_level = 1 -# syncopation = WNBD.get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq) +def results_to_xml(results, outputFilename): + from xml.etree.ElementTree import Element, ElementTree -# else: -# print 'Error: undefined syncopation model.' + elem = Element("syncopation_results") -# return syncopation + for key, val in results.items(): + child = Element(key) + child.text = str(val) + elem.append(child) -# def syncopation_all(rhythm, model, timesig, subdivision_seq = None, weight_seq = None, L_max = 5, strong_beat_level = None): -# syncopation = 0 -# # Chope rhythm into seq -# # ... + ElementTree(elem).write(outputFilename) -# for (seq_perbar in seq): -# sync_perbar = syncopation_perbar(seq_perbar,model, timesig, subdivision_seq, weight_seq, L_max, strong_beat_level) -# if sync_perbar != None: -# syncopation = syncopation + sync_perbar -# return syncopation -