Mercurial > hg > syncopation-dataset
comparison Syncopation models/LHL.py @ 14:6b6f8e3d7262
updating lhl and prs
| author | csong <csong@eecs.qmul.ac.uk> |
|---|---|
| date | Fri, 03 Apr 2015 17:10:57 +0100 |
| parents | 031e2ccb1fb6 |
| children | 9030967a05f8 |
comparison
equal
deleted
inserted
replaced
| 11:7d94ba423c04 | 14:6b6f8e3d7262 |
|---|---|
| 1 ''' | 1 ''' |
| 2 Author: Chunyang Song | 2 Author: Chunyang Song |
| 3 Institution: Centre for Digital Music, Queen Mary University of London | 3 Institution: Centre for Digital Music, Queen Mary University of London |
| 4 ''' | 4 ''' |
| 5 | 5 |
| 6 from BasicFuncs import concatenate, repeat, subdivide, ceiling | 6 from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category |
| 7 | 7 |
| 8 terminal_nodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order | 8 terminalNodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order |
| 9 | 9 |
| 10 # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight. | 10 # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight. |
| 11 class Node: | 11 class Node: |
| 12 def __init__(self,node_type,metrical_weight): | 12 def __init__(self,nodeType,metricalWeight): |
| 13 self.node_type = node_type | 13 self.nodeType = nodeType |
| 14 self.metrical_weight = metrical_weight | 14 self.metricalWeight = metricalWeight |
| 15 | 15 |
| 16 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order. | 16 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order. |
| 17 def recursive_tree(seq, subdivision_seq, weight_seq, metrical_weight, level): | 17 def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level): |
| 18 if seq == concatenate([1],repeat([0],len(seq)-1)): # If matching to a Note type, add to terminal nodes | 18 # If matching to a Note type, add to terminal nodes |
| 19 terminal_nodes.append(Node('N',metrical_weight)) | 19 if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)): |
| 20 terminalNodes.append(Node('N',metricalWeight)) | |
| 20 | 21 |
| 21 elif seq == repeat([0],len(seq)): # If matching to a Rest type, add to terminal nodes | 22 # If matching to a Rest type, add to terminal nodes |
| 22 terminal_nodes.append(Node('R',metrical_weight)) | 23 elif binarySequence == repeat([0],len(binarySequence)): |
| 24 terminalNodes.append(Node('R',metricalWeight)) | |
| 23 | 25 |
| 24 else: # Keep subdividing by the subdivisor of the next level | 26 # Keep subdividing by the subdivisor of the next level |
| 25 sub_seq = subdivide(seq, subdivision_seq[level+1]) | 27 else: |
| 26 sub_weight_seq = concatenate([metrical_weight],repeat([weight_seq[level+1]],subdivision_seq[level+1]-1)) | 28 subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1]) |
| 27 for a in range(len(sub_seq)): | 29 subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1)) |
| 28 recursive_tree(sub_seq[a], subdivision_seq, weight_seq, sub_weight_seq[a], level+1) | 30 for a in range(len(subBinarySequences)): |
| 31 recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1) | |
| 29 | 32 |
| 30 # This function calculate syncoaption score for LHL model. | 33 def get_syncopation(bar, weightSequence = None, LMax = None): |
| 31 def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category): | 34 ''' |
| 35 The get_syncopation function calculates syncopation value . | |
| 36 ''' | |
| 37 #def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category): | |
| 32 syncopation = None | 38 syncopation = None |
| 33 if rhythm_category == 'poly': | 39 |
| 34 print 'Error: LHL model cannot deal with polyrhythms.' | 40 binarySequence = bar.get_binary_sequence() |
| 41 subdivisionSequence = bar.get_subdivision_sequence() | |
| 42 | |
| 43 if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly': | |
| 44 print 'Warning: LHL model detects polyrhythms so returning None.' | |
| 35 else: | 45 else: |
| 46 if weightSequence == None: | |
| 47 if LMax == None: | |
| 48 LMax = 5 | |
| 49 weightSequence = range(0,-LMax,-1) | |
| 50 | |
| 36 # If there is rhythm in previous bar, process its tree structure | 51 # If there is rhythm in previous bar, process its tree structure |
| 37 if prebar_seq != None: | 52 if bar.get_previous_bar() != None: |
| 38 recursive_tree(ceiling(prebar_seq), subdivision_seq, weight_seq, weight_seq[0],0) | 53 prebarBinarySequence = bar.get_previous_bar().get_binary_sequence() |
| 54 recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) | |
| 39 | 55 |
| 40 # Only keep the last note-type node | 56 # Only keep the last note-type node |
| 41 while terminal_nodes[-1].node_type != 'N': | 57 while terminalNodes[-1].node_type != 'N': |
| 42 del terminal_nodes[-1] | 58 del terminalNodes[-1] |
| 43 del terminal_nodes[0:-1] | 59 del terminalNodes[0:-1] |
| 44 | 60 |
| 45 # For the rhythm in the current bar, process its tree structure and store the terminal nodes | 61 # For the rhythm in the current bar, process its tree structure and store the terminal nodes |
| 46 recursive_tree(ceiling(seq), subdivision_seq, weight_seq, weight_seq[0],0) | 62 recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0) |
| 47 | 63 |
| 48 # for t in terminal_nodes: | 64 # for t in terminalNodes: |
| 49 # print '<', t.node_type, t.metrical_weight, '>' | 65 # print '<', t.node_type, t.metrical_weight, '>' |
| 50 | 66 |
| 51 # Search for the NR pairs that contribute to syncopation, add the weight-difference to the NR_pair_syncopation list | 67 # Search for the NR pairs that contribute to syncopation, |
| 52 NR_pair_syncopation = [] | 68 # then add the weight-difference to the NRpairSyncopation list |
| 53 for i in range(len(terminal_nodes)-1,0,-1): | 69 NRpairSyncopation = [] |
| 54 if terminal_nodes[i].node_type == 'R': | 70 for i in range(len(terminalNodes)-1,0,-1): |
| 71 if terminalNodes[i].node_type == 'R': | |
| 55 for j in range(i-1, -1, -1): | 72 for j in range(i-1, -1, -1): |
| 56 if (terminal_nodes[j].node_type == 'N') & (terminal_nodes[i].metrical_weight >= terminal_nodes[j].metrical_weight): | 73 if (terminalNodes[j].node_type == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight): |
| 57 NR_pair_syncopation.append(terminal_nodes[i].metrical_weight - terminal_nodes[j].metrical_weight) | 74 NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight) |
| 58 break | 75 break |
| 59 #print NR_pair_syncopation | 76 #print NRpairSyncopation |
| 60 | 77 |
| 61 # If no syncopation, the value is -1; otherwise, sum all the local syncopation values stored in NR_pair_syncopation list | 78 # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list |
| 62 if len(NR_pair_syncopation) != 0: | 79 if len(NRpairSyncopation) != 0: |
| 63 syncopation = sum(NR_pair_syncopation) | 80 syncopation = sum(NRpairSyncopation) |
| 64 elif len(terminal_nodes) != 0: | 81 # If no syncopation, the value is -1; |
| 82 elif len(terminalNodes) != 0: | |
| 65 syncopation = -1 | 83 syncopation = -1 |
| 66 | 84 |
| 67 return syncopation | 85 return syncopation |
| 86 | |
| 87 |
