Mercurial > hg > syncopation-dataset
diff Syncopation models/synpy/LHL.py @ 50:e71028851131
updating latex and bug fixes to main py files
author | christopherh <christopher.harte@eecs.qmul.ac.uk> |
---|---|
date | Mon, 27 Apr 2015 09:51:15 +0100 |
parents | 6e9154fc58df |
children |
line wrap: on
line diff
--- a/Syncopation models/synpy/LHL.py Mon Apr 27 09:46:18 2015 +0100 +++ b/Syncopation models/synpy/LHL.py Mon Apr 27 09:51:15 2015 +0100 @@ -6,37 +6,42 @@ from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category from parameter_setter import are_parameters_valid -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. +# Each terminal node contains two properties: its node type (note or rest) and its metrical weight. class Node: def __init__(self,nodeType,metricalWeight): self.nodeType = nodeType self.metricalWeight = metricalWeight # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order. -def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level): +def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level, Lmax): # If matching to a Note type, add to terminal nodes + output = list() if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)): - terminalNodes.append(Node('N',metricalWeight)) + output.append(Node('N',metricalWeight)) # If matching to a Rest type, add to terminal nodes elif binarySequence == repeat([0],len(binarySequence)): - terminalNodes.append(Node('R',metricalWeight)) + output.append(Node('R',metricalWeight)) + + elif level+1 == Lmax: + print "WARNING: LHL tree recursion descended to Lmax, returning a note node but result will not be fully accurate. Check the rhythm pattern under test and/or specify larger Lmax to rectify the problem." + output.append(Node('N',metricalWeight)) # Keep subdividing by the subdivisor of the next level - else: + else: subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1]) subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1)) for a in range(len(subBinarySequences)): - recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1) - + output = output + recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1, Lmax) + + return output def get_syncopation(bar, parameters = None): - del terminalNodes[:] syncopation = None + naughtyglobal = 0 binarySequence = bar.get_binary_sequence() subdivisionSequence = bar.get_subdivision_sequence() @@ -44,9 +49,12 @@ # LHL can only measure monorhythms if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': print 'Warning: LHL model detects polyrhythms so returning None.' + elif bar.is_empty(): + print 'LHL model detects empty bar so returning -1.' + syncopation = -1 else: # set defaults - Lmax = 5 + Lmax = 10 weightSequence = range(0,-Lmax-1,-1) # if parameters are specified by users, check their validities and update parameters if valid if parameters!= None: @@ -58,25 +66,34 @@ if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence): print 'Error: the given parameters are not valid.' else: - # If there is rhythm in previous bar, process its tree structure + + # For the rhythm in the current bar, process its tree structure and store the terminal nodes + terminalNodes = recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0, Lmax) + + # save the terminal nodes on the current bar so that + # the next bar can access them... + bar.LHLterminalNodes = terminalNodes + + # If there is rhythm in the previous bar and we've already processed it 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) - - if len(terminalNodes)>0: + if prevbar != None and prevbar.is_empty() != True: + # get its LHL tree if it has one + try: + prevbarNodes = prevbar.LHLterminalNodes + except AttributeError: + prevbarNodes = [] + + # find the final note node in the previous bar: + if len(prevbarNodes)>0: + i = len(prevbarNodes) - 1 # 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) + while prevbarNodes[i].nodeType != 'N' and i>=0: + i = i-1 + # prepend the note to the terminal node list for this bar + terminalNodes = [ prevbarNodes[i] ] + terminalNodes + - # for t in terminalNodes: - # print '<', t.nodeType, t.metricalWeight, '>' - - # Search for the NR pairs that contribute to syncopation,then add the weight-difference to the NRpairSyncopation list + # Search for the NR pairs that contribute to syncopation, then add the weight-difference to the NRpairSyncopation list NRpairSyncopation = [] for i in range(len(terminalNodes)-1,0,-1): if terminalNodes[i].nodeType == 'R': @@ -84,7 +101,6 @@ if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight): NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight) break - #print NRpairSyncopation # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list if len(NRpairSyncopation) != 0: