annotate Syncopation models/LHL.py @ 38:cc38b3047ed9

updated syncopation.y to allow output of sync for a bar list also fixed some problems in models and other modules
author christopherh <christopher.harte@eecs.qmul.ac.uk>
date Mon, 13 Apr 2015 23:06:49 +0100
parents f5abd2e8cafe
children
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@28 7 from parameter_setter import are_parameters_valid
csong@0 8
csong@12 9 terminalNodes = [] # Global variable, storing all the terminal nodes from recursive tree structure in time order
csong@0 10
christopher@38 11
christopher@38 12
csong@1 13 # Each terminnal node contains two properties: its node type (note or rest) and its metrical weight.
csong@1 14 class Node:
csong@12 15 def __init__(self,nodeType,metricalWeight):
csong@12 16 self.nodeType = nodeType
csong@12 17 self.metricalWeight = metricalWeight
csong@0 18
csong@1 19 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order.
csong@12 20 def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level):
csong@12 21 # If matching to a Note type, add to terminal nodes
csong@12 22 if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)):
csong@12 23 terminalNodes.append(Node('N',metricalWeight))
csong@0 24
csong@12 25 # If matching to a Rest type, add to terminal nodes
csong@12 26 elif binarySequence == repeat([0],len(binarySequence)):
csong@12 27 terminalNodes.append(Node('R',metricalWeight))
csong@0 28
csong@12 29 # Keep subdividing by the subdivisor of the next level
csong@12 30 else:
csong@12 31 subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1])
csong@12 32 subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1))
csong@12 33 for a in range(len(subBinarySequences)):
csong@12 34 recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1)
csong@0 35
csong@19 36
csong@19 37 def get_syncopation(bar, parameters = None):
csong@20 38 del terminalNodes[:]
csong@1 39 syncopation = None
csong@12 40
csong@12 41 binarySequence = bar.get_binary_sequence()
csong@12 42 subdivisionSequence = bar.get_subdivision_sequence()
csong@12 43
csong@28 44 # LHL can only measure monorhythms
csong@12 45 if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
csong@12 46 print 'Warning: LHL model detects polyrhythms so returning None.'
csong@1 47 else:
csong@28 48 # set defaults
csong@28 49 Lmax = 5
csong@33 50 weightSequence = range(0,-Lmax-1,-1)
csong@28 51 # if parameters are specified by users, check their validities and update parameters if valid
csong@28 52 if parameters!= None:
csong@28 53 if 'Lmax' in parameters:
csong@28 54 Lmax = parameters['Lmax']
csong@28 55 if 'W' in parameters:
csong@28 56 weightSequence = parameters['W']
csong@28 57
csong@28 58 if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence):
csong@28 59 print 'Error: the given parameters are not valid.'
csong@19 60 else:
csong@28 61 # If there is rhythm in previous bar, process its tree structure
christopher@38 62 prevbar = bar.get_previous_bar()
christopher@38 63 if prevbar != None and not prevbar.is_empty():
christopher@38 64 prebarBinarySequence = prevbar.get_binary_sequence()
csong@28 65 recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
csong@28 66
christopher@38 67 if len(terminalNodes)>0:
christopher@38 68 # Only keep the last note-type node
christopher@38 69 while terminalNodes[-1].nodeType != 'N':
christopher@38 70 del terminalNodes[-1]
christopher@38 71 del terminalNodes[0:-1]
csong@12 72
csong@28 73 # For the rhythm in the current bar, process its tree structure and store the terminal nodes
csong@28 74 recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
csong@1 75
csong@28 76 # for t in terminalNodes:
csong@28 77 # print '<', t.nodeType, t.metricalWeight, '>'
csong@0 78
csong@28 79 # Search for the NR pairs that contribute to syncopation,then add the weight-difference to the NRpairSyncopation list
csong@28 80 NRpairSyncopation = []
csong@28 81 for i in range(len(terminalNodes)-1,0,-1):
csong@28 82 if terminalNodes[i].nodeType == 'R':
csong@28 83 for j in range(i-1, -1, -1):
csong@28 84 if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight):
csong@28 85 NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight)
csong@28 86 break
csong@28 87 #print NRpairSyncopation
csong@0 88
csong@28 89 # If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list
csong@28 90 if len(NRpairSyncopation) != 0:
csong@28 91 syncopation = sum(NRpairSyncopation)
csong@28 92 # If no syncopation, the value is -1;
csong@28 93 elif len(terminalNodes) != 0:
csong@28 94 syncopation = -1
csong@0 95
csong@1 96 return syncopation
csong@12 97
csong@12 98