annotate Syncopation models/LHL.py @ 19:9030967a05f8

Refactored parameter_setter, basic_functions. Halfway fixing parameter argument in LHL model.
author csong <csong@eecs.qmul.ac.uk>
date Fri, 03 Apr 2015 22:57:27 +0100
parents 4acddc008048
children b959c2acb927
rev   line source
csong@0 1 '''
csong@0 2 Author: Chunyang Song
csong@0 3 Institution: Centre for Digital Music, Queen Mary University of London
csong@1 4 '''
csong@0 5
csong@12 6 from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category
csong@0 7
csong@12 8 terminalNodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order
csong@0 9
csong@1 10 # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight.
csong@1 11 class Node:
csong@12 12 def __init__(self,nodeType,metricalWeight):
csong@12 13 self.nodeType = nodeType
csong@12 14 self.metricalWeight = metricalWeight
csong@0 15
csong@1 16 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order.
csong@12 17 def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level):
csong@12 18 # If matching to a Note type, add to terminal nodes
csong@12 19 if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)):
csong@12 20 terminalNodes.append(Node('N',metricalWeight))
csong@0 21
csong@12 22 # If matching to a Rest type, add to terminal nodes
csong@12 23 elif binarySequence == repeat([0],len(binarySequence)):
csong@12 24 terminalNodes.append(Node('R',metricalWeight))
csong@0 25
csong@12 26 # Keep subdividing by the subdivisor of the next level
csong@12 27 else:
csong@12 28 subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1])
csong@12 29 subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1))
csong@12 30 for a in range(len(subBinarySequences)):
csong@12 31 recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1)
csong@0 32
csong@19 33 def are_parameters_valid(parameters):
csong@19 34 areValid = False
csong@19 35 if 'Lmax' not in parameters :
csong@19 36
csong@19 37 def get_syncopation(bar, parameters = None):
csong@12 38 '''
csong@12 39 The get_syncopation function calculates syncopation value .
csong@12 40 '''
csong@12 41 #def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category):
csong@1 42 syncopation = None
csong@12 43
csong@12 44 binarySequence = bar.get_binary_sequence()
csong@12 45 subdivisionSequence = bar.get_subdivision_sequence()
csong@12 46
csong@12 47 if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
csong@12 48 print 'Warning: LHL model detects polyrhythms so returning None.'
csong@1 49 else:
csong@19 50 # If the parameters are not given, use the default settings
csong@19 51 if parameters == None:
csong@19 52 Lmax = 5
csong@19 53 weightSequence = range(0,-Lmax,-1)
csong@19 54 else:
csong@19 55 if are_parameters_valid(parameters):
csong@19 56 Lmax = parameters['Lmax']
csong@19 57 weightSequence = parameters['W']
csong@19 58 else:
csong@19 59 pass
csong@19 60 #raise InvalidParameterError
csong@12 61
csong@1 62 # If there is rhythm in previous bar, process its tree structure
csong@12 63 if bar.get_previous_bar() != None:
csong@12 64 prebarBinarySequence = bar.get_previous_bar().get_binary_sequence()
csong@12 65 recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
csong@1 66
csong@1 67 # Only keep the last note-type node
csong@12 68 while terminalNodes[-1].node_type != 'N':
csong@12 69 del terminalNodes[-1]
csong@12 70 del terminalNodes[0:-1]
csong@0 71
csong@1 72 # For the rhythm in the current bar, process its tree structure and store the terminal nodes
csong@12 73 recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
csong@1 74
csong@12 75 # for t in terminalNodes:
csong@1 76 # print '<', t.node_type, t.metrical_weight, '>'
csong@0 77
csong@12 78 # Search for the NR pairs that contribute to syncopation,
csong@12 79 # then add the weight-difference to the NRpairSyncopation list
csong@12 80 NRpairSyncopation = []
csong@12 81 for i in range(len(terminalNodes)-1,0,-1):
csong@12 82 if terminalNodes[i].node_type == 'R':
csong@1 83 for j in range(i-1, -1, -1):
csong@12 84 if (terminalNodes[j].node_type == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight):
csong@12 85 NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight)
csong@1 86 break
csong@12 87 #print NRpairSyncopation
csong@0 88
csong@12 89 # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list
csong@12 90 if len(NRpairSyncopation) != 0:
csong@12 91 syncopation = sum(NRpairSyncopation)
csong@12 92 # If no syncopation, the value is -1;
csong@12 93 elif len(terminalNodes) != 0:
csong@1 94 syncopation = -1
csong@0 95
csong@1 96 return syncopation
csong@12 97
csong@12 98