comparison 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
comparison
equal deleted inserted replaced
49:af3f32cebf8c 50:e71028851131
4 ''' 4 '''
5 5
6 from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category 6 from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category
7 from parameter_setter import are_parameters_valid 7 from parameter_setter import are_parameters_valid
8 8
9 terminalNodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order
10 9
11 10
12 11
13 # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight. 12 # Each terminal node contains two properties: its node type (note or rest) and its metrical weight.
14 class Node: 13 class Node:
15 def __init__(self,nodeType,metricalWeight): 14 def __init__(self,nodeType,metricalWeight):
16 self.nodeType = nodeType 15 self.nodeType = nodeType
17 self.metricalWeight = metricalWeight 16 self.metricalWeight = metricalWeight
18 17
19 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order. 18 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order.
20 def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level): 19 def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level, Lmax):
21 # If matching to a Note type, add to terminal nodes 20 # If matching to a Note type, add to terminal nodes
21 output = list()
22 if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)): 22 if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)):
23 terminalNodes.append(Node('N',metricalWeight)) 23 output.append(Node('N',metricalWeight))
24 24
25 # If matching to a Rest type, add to terminal nodes 25 # If matching to a Rest type, add to terminal nodes
26 elif binarySequence == repeat([0],len(binarySequence)): 26 elif binarySequence == repeat([0],len(binarySequence)):
27 terminalNodes.append(Node('R',metricalWeight)) 27 output.append(Node('R',metricalWeight))
28
29 elif level+1 == Lmax:
30 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."
31 output.append(Node('N',metricalWeight))
28 32
29 # Keep subdividing by the subdivisor of the next level 33 # Keep subdividing by the subdivisor of the next level
30 else: 34 else:
31 subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1]) 35 subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1])
32 subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1)) 36 subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1))
33 for a in range(len(subBinarySequences)): 37 for a in range(len(subBinarySequences)):
34 recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1) 38 output = output + recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1, Lmax)
35 39
40 return output
36 41
37 def get_syncopation(bar, parameters = None): 42 def get_syncopation(bar, parameters = None):
38 del terminalNodes[:]
39 syncopation = None 43 syncopation = None
44 naughtyglobal = 0
40 45
41 binarySequence = bar.get_binary_sequence() 46 binarySequence = bar.get_binary_sequence()
42 subdivisionSequence = bar.get_subdivision_sequence() 47 subdivisionSequence = bar.get_subdivision_sequence()
43 48
44 # LHL can only measure monorhythms 49 # LHL can only measure monorhythms
45 if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': 50 if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
46 print 'Warning: LHL model detects polyrhythms so returning None.' 51 print 'Warning: LHL model detects polyrhythms so returning None.'
52 elif bar.is_empty():
53 print 'LHL model detects empty bar so returning -1.'
54 syncopation = -1
47 else: 55 else:
48 # set defaults 56 # set defaults
49 Lmax = 5 57 Lmax = 10
50 weightSequence = range(0,-Lmax-1,-1) 58 weightSequence = range(0,-Lmax-1,-1)
51 # if parameters are specified by users, check their validities and update parameters if valid 59 # if parameters are specified by users, check their validities and update parameters if valid
52 if parameters!= None: 60 if parameters!= None:
53 if 'Lmax' in parameters: 61 if 'Lmax' in parameters:
54 Lmax = parameters['Lmax'] 62 Lmax = parameters['Lmax']
56 weightSequence = parameters['W'] 64 weightSequence = parameters['W']
57 65
58 if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence): 66 if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence):
59 print 'Error: the given parameters are not valid.' 67 print 'Error: the given parameters are not valid.'
60 else: 68 else:
61 # If there is rhythm in previous bar, process its tree structure 69
70 # For the rhythm in the current bar, process its tree structure and store the terminal nodes
71 terminalNodes = recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0, Lmax)
72
73 # save the terminal nodes on the current bar so that
74 # the next bar can access them...
75 bar.LHLterminalNodes = terminalNodes
76
77 # If there is rhythm in the previous bar and we've already processed it
62 prevbar = bar.get_previous_bar() 78 prevbar = bar.get_previous_bar()
63 if prevbar != None and not prevbar.is_empty(): 79 if prevbar != None and prevbar.is_empty() != True:
64 prebarBinarySequence = prevbar.get_binary_sequence() 80 # get its LHL tree if it has one
65 recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) 81 try:
66 82 prevbarNodes = prevbar.LHLterminalNodes
67 if len(terminalNodes)>0: 83 except AttributeError:
84 prevbarNodes = []
85
86 # find the final note node in the previous bar:
87 if len(prevbarNodes)>0:
88 i = len(prevbarNodes) - 1
68 # Only keep the last note-type node 89 # Only keep the last note-type node
69 while terminalNodes[-1].nodeType != 'N': 90 while prevbarNodes[i].nodeType != 'N' and i>=0:
70 del terminalNodes[-1] 91 i = i-1
71 del terminalNodes[0:-1] 92 # prepend the note to the terminal node list for this bar
72 93 terminalNodes = [ prevbarNodes[i] ] + terminalNodes
73 # For the rhythm in the current bar, process its tree structure and store the terminal nodes 94
74 recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
75 95
76 # for t in terminalNodes: 96 # Search for the NR pairs that contribute to syncopation, then add the weight-difference to the NRpairSyncopation list
77 # print '<', t.nodeType, t.metricalWeight, '>'
78
79 # Search for the NR pairs that contribute to syncopation,then add the weight-difference to the NRpairSyncopation list
80 NRpairSyncopation = [] 97 NRpairSyncopation = []
81 for i in range(len(terminalNodes)-1,0,-1): 98 for i in range(len(terminalNodes)-1,0,-1):
82 if terminalNodes[i].nodeType == 'R': 99 if terminalNodes[i].nodeType == 'R':
83 for j in range(i-1, -1, -1): 100 for j in range(i-1, -1, -1):
84 if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight): 101 if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight):
85 NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight) 102 NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight)
86 break 103 break
87 #print NRpairSyncopation
88 104
89 # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list 105 # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list
90 if len(NRpairSyncopation) != 0: 106 if len(NRpairSyncopation) != 0:
91 syncopation = sum(NRpairSyncopation) 107 syncopation = sum(NRpairSyncopation)
92 # If no syncopation, the value is -1; 108 # If no syncopation, the value is -1;