Mercurial > hg > syncopation-dataset
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; |