diff 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
line wrap: on
line diff
--- a/Syncopation models/synpy/LHL.py	Mon Apr 27 09:46:18 2015 +0100
+++ b/Syncopation models/synpy/LHL.py	Mon Apr 27 09:51:15 2015 +0100
@@ -6,37 +6,42 @@
 from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category
 from parameter_setter import are_parameters_valid
 
-terminalNodes = []		# Global variable, storing all the terminal nodes from recursive tree structure in time order
 
 
 
-# Each terminnal node contains two properties: its node type (note or rest) and its metrical weight.
+# Each terminal node contains two properties: its node type (note or rest) and its metrical weight.
 class Node:
 	def __init__(self,nodeType,metricalWeight):
 		self.nodeType = nodeType
 		self.metricalWeight = metricalWeight
 
 # This function will recurse the tree for a binary sequence and return a sequence containing the terminal nodes in time order.
-def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level):
+def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level, Lmax):
 	# If matching to a Note type, add to terminal nodes
+	output = list()
 	if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)):	
-		terminalNodes.append(Node('N',metricalWeight))
+		output.append(Node('N',metricalWeight))
 
 	# If matching to a Rest type, add to terminal nodes
 	elif binarySequence == repeat([0],len(binarySequence)):					
-		terminalNodes.append(Node('R',metricalWeight))
+		output.append(Node('R',metricalWeight))
+
+	elif level+1 == Lmax:
+		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."
+		output.append(Node('N',metricalWeight))
 
 	# Keep subdividing by the subdivisor of the next level
-	else:													
+	else:	
 		subBinarySequences = subdivide(binarySequence, subdivisionSequence[level+1])	
 		subWeightSequences = concatenate([metricalWeight],repeat([weightSequence[level+1]],subdivisionSequence[level+1]-1))
 		for a in range(len(subBinarySequences)):
-			recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1)
-
+			output = output + recursive_tree(subBinarySequences[a], subdivisionSequence, weightSequence, subWeightSequences[a], level+1, Lmax)
+	
+	return output
 
 def get_syncopation(bar, parameters = None):
-	del terminalNodes[:]
 	syncopation = None
+	naughtyglobal = 0
 
 	binarySequence = bar.get_binary_sequence()
 	subdivisionSequence = bar.get_subdivision_sequence()
@@ -44,9 +49,12 @@
 	# LHL can only measure monorhythms
 	if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
 		print 'Warning: LHL model detects polyrhythms so returning None.'
+	elif bar.is_empty():
+		print 'LHL model detects empty bar so returning -1.'
+		syncopation = -1
 	else:
 		# set defaults
-		Lmax = 5
+		Lmax = 10
 		weightSequence = range(0,-Lmax-1,-1)
 		# if parameters are specified by users, check their validities and update parameters if valid		
 		if parameters!= None:
@@ -58,25 +66,34 @@
 		if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence):
 			print 'Error: the given parameters are not valid.'
 		else:
-			# If there is rhythm in previous bar, process its tree structure
+			
+			# For the rhythm in the current bar, process its tree structure and store the terminal nodes 
+			terminalNodes = recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0, Lmax)
+			
+			# save the terminal nodes on the current bar so that 
+			# the next bar can access them...
+			bar.LHLterminalNodes = terminalNodes
+
+			# If there is rhythm in the previous bar and we've already processed it 
 			prevbar =  bar.get_previous_bar()
-			if prevbar != None and not prevbar.is_empty():
-				prebarBinarySequence = prevbar.get_binary_sequence()
-				recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
-				
-				if len(terminalNodes)>0:
+			if prevbar != None and prevbar.is_empty() != True:
+				# get its LHL tree if it has one
+				try:
+					prevbarNodes = prevbar.LHLterminalNodes
+				except AttributeError:
+					prevbarNodes = []
+
+				# find the final note node in the previous bar:
+				if len(prevbarNodes)>0:
+					i = len(prevbarNodes) - 1
 					# Only keep the last note-type node
-					while terminalNodes[-1].nodeType != 'N':
-						del terminalNodes[-1]
-					del terminalNodes[0:-1]
-
-			# For the rhythm in the current bar, process its tree structure and store the terminal nodes 
-			recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
+					while prevbarNodes[i].nodeType != 'N' and i>=0:
+						i = i-1
+					# prepend the note to the terminal node list for this bar
+					terminalNodes = [ prevbarNodes[i] ] + terminalNodes
+						
 			
-			# for t in terminalNodes:
-			# 	print '<', t.nodeType, t.metricalWeight, '>'
-
-			# Search for the NR pairs that contribute to syncopation,then add the weight-difference to the NRpairSyncopation list
+			# Search for the NR pairs that contribute to syncopation, then add the weight-difference to the NRpairSyncopation list
 			NRpairSyncopation = []
 			for i in range(len(terminalNodes)-1,0,-1):
 				if terminalNodes[i].nodeType == 'R':
@@ -84,7 +101,6 @@
 						if (terminalNodes[j].nodeType == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight):
 							NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight)
 							break
-			#print NRpairSyncopation
 
 			# If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list	
 			if len(NRpairSyncopation) != 0: