Mercurial > hg > syncopation-dataset
comparison Syncopation models/synpy/LHL.py @ 45:6e9154fc58df
moving the code files to the synpy package directory
author | christopherh <christopher.harte@eecs.qmul.ac.uk> |
---|---|
date | Thu, 23 Apr 2015 23:52:04 +0100 |
parents | |
children | e71028851131 |
comparison
equal
deleted
inserted
replaced
44:144460f34b5e | 45:6e9154fc58df |
---|---|
1 ''' | |
2 Author: Chunyang Song | |
3 Institution: Centre for Digital Music, Queen Mary University of London | |
4 ''' | |
5 | |
6 from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category | |
7 from parameter_setter import are_parameters_valid | |
8 | |
9 terminalNodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order | |
10 | |
11 | |
12 | |
13 # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight. | |
14 class Node: | |
15 def __init__(self,nodeType,metricalWeight): | |
16 self.nodeType = nodeType | |
17 self.metricalWeight = metricalWeight | |
18 | |
19 # 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): | |
21 # If matching to a Note type, add to terminal nodes | |
22 if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)): | |
23 terminalNodes.append(Node('N',metricalWeight)) | |
24 | |
25 # If matching to a Rest type, add to terminal nodes | |
26 elif binarySequence == repeat([0],len(binarySequence)): | |
27 terminalNodes.append(Node('R',metricalWeight)) | |
28 | |
29 # Keep subdividing by the subdivisor of the next level | |
30 else: | |
31 subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1]) | |
32 subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1)) | |
33 for a in range(len(subBinarySequences)): | |
34 recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1) | |
35 | |
36 | |
37 def get_syncopation(bar, parameters = None): | |
38 del terminalNodes[:] | |
39 syncopation = None | |
40 | |
41 binarySequence = bar.get_binary_sequence() | |
42 subdivisionSequence = bar.get_subdivision_sequence() | |
43 | |
44 # LHL can only measure monorhythms | |
45 if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': | |
46 print 'Warning: LHL model detects polyrhythms so returning None.' | |
47 else: | |
48 # set defaults | |
49 Lmax = 5 | |
50 weightSequence = range(0,-Lmax-1,-1) | |
51 # if parameters are specified by users, check their validities and update parameters if valid | |
52 if parameters!= None: | |
53 if 'Lmax' in parameters: | |
54 Lmax = parameters['Lmax'] | |
55 if 'W' in parameters: | |
56 weightSequence = parameters['W'] | |
57 | |
58 if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence): | |
59 print 'Error: the given parameters are not valid.' | |
60 else: | |
61 # If there is rhythm in previous bar, process its tree structure | |
62 prevbar = bar.get_previous_bar() | |
63 if prevbar != None and not prevbar.is_empty(): | |
64 prebarBinarySequence = prevbar.get_binary_sequence() | |
65 recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) | |
66 | |
67 if len(terminalNodes)>0: | |
68 # Only keep the last note-type node | |
69 while terminalNodes[-1].nodeType != 'N': | |
70 del terminalNodes[-1] | |
71 del terminalNodes[0:-1] | |
72 | |
73 # For the rhythm in the current bar, process its tree structure and store the terminal nodes | |
74 recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) | |
75 | |
76 # for t in terminalNodes: | |
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 = [] | |
81 for i in range(len(terminalNodes)-1,0,-1): | |
82 if terminalNodes[i].nodeType == 'R': | |
83 for j in range(i-1, -1, -1): | |
84 if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight): | |
85 NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight) | |
86 break | |
87 #print NRpairSyncopation | |
88 | |
89 # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list | |
90 if len(NRpairSyncopation) != 0: | |
91 syncopation = sum(NRpairSyncopation) | |
92 # If no syncopation, the value is -1; | |
93 elif len(terminalNodes) != 0: | |
94 syncopation = -1 | |
95 | |
96 return syncopation | |
97 | |
98 |