changeset 14:6b6f8e3d7262

updating lhl and prs
author csong <csong@eecs.qmul.ac.uk>
date Fri, 03 Apr 2015 17:10:57 +0100
parents 7d94ba423c04
children 4fb9c00e4ef0
files Syncopation models/LHL.py Syncopation models/PRS.py
diffstat 2 files changed, 94 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/Syncopation models/LHL.py	Fri Apr 03 16:18:00 2015 +0100
+++ b/Syncopation models/LHL.py	Fri Apr 03 17:10:57 2015 +0100
@@ -3,65 +3,85 @@
 Institution: Centre for Digital Music, Queen Mary University of London
 '''
 
-from BasicFuncs import concatenate, repeat, subdivide, ceiling
+from basic_functions import concatenate, repeat, subdivide, ceiling, get_rhythm_category
 
-terminal_nodes = []		# Global variable, storing all the terminal nodes from recursive tree structure in time order
+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.
 class Node:
-	def __init__(self,node_type,metrical_weight):
-		self.node_type = node_type
-		self.metrical_weight = metrical_weight
+	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(seq, subdivision_seq, weight_seq, metrical_weight, level):
-	if seq == concatenate([1],repeat([0],len(seq)-1)):	# If matching to a Note type, add to terminal nodes
-		terminal_nodes.append(Node('N',metrical_weight))
+def recursive_tree(binarySequence, subdivisionSequence, weightSequence, metricalWeight, level):
+	# If matching to a Note type, add to terminal nodes
+	if binarySequence == concatenate([1],repeat([0],len(binarySequence)-1)):	
+		terminalNodes.append(Node('N',metricalWeight))
 
-	elif seq == repeat([0],len(seq)):					# If matching to a Rest type, add to terminal nodes
-		terminal_nodes.append(Node('R',metrical_weight))
+	# If matching to a Rest type, add to terminal nodes
+	elif binarySequence == repeat([0],len(binarySequence)):					
+		terminalNodes.append(Node('R',metricalWeight))
 
-	else:													# Keep subdividing by the subdivisor of the next level
-		sub_seq = subdivide(seq, subdivision_seq[level+1])	
-		sub_weight_seq = concatenate([metrical_weight],repeat([weight_seq[level+1]],subdivision_seq[level+1]-1))
-		for a in range(len(sub_seq)):
-			recursive_tree(sub_seq[a], subdivision_seq, weight_seq, sub_weight_seq[a], level+1)
+	# Keep subdividing by the subdivisor of the next level
+	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)
 
-# This function calculate syncoaption score for LHL model. 
-def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category):
+def get_syncopation(bar, weightSequence = None, LMax = None):
+	'''
+	The get_syncopation function calculates syncopation value . 
+	'''
+#def get_syncopation(seq, subdivision_seq, weight_seq, prebar_seq, rhythm_category):
 	syncopation = None
-	if rhythm_category == 'poly':
-		print 'Error: LHL model cannot deal with polyrhythms.'
+
+	binarySequence = bar.get_binary_sequence()
+	subdivisionSequence = bar.get_subdivision_sequence()
+
+	if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
+		print 'Warning: LHL model detects polyrhythms so returning None.'
 	else:
+		if weightSequence == None:
+			if LMax == None:
+				LMax  = 5
+				weightSequence = range(0,-LMax,-1)
+
 		# If there is rhythm in previous bar, process its tree structure
-		if prebar_seq != None:		
-			recursive_tree(ceiling(prebar_seq), subdivision_seq, weight_seq, weight_seq[0],0)
+		if bar.get_previous_bar() != None:
+			prebarBinarySequence = bar.get_previous_bar().get_binary_sequence()
+			recursive_tree(ceiling(prebarBinarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
 			
 			# Only keep the last note-type node
-			while terminal_nodes[-1].node_type != 'N':
-				del terminal_nodes[-1]
-			del terminal_nodes[0:-1]
+			while terminalNodes[-1].node_type != '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(seq), subdivision_seq, weight_seq, weight_seq[0],0)
+		recursive_tree(ceiling(binarySequence), subdivisionSequence, weightSequence, weightSequence[0],0)
 		
-		# for t in terminal_nodes:
+		# for t in terminalNodes:
 		# 	print '<', t.node_type, t.metrical_weight, '>'
 
-		# Search for the NR pairs that contribute to syncopation, add the weight-difference to the NR_pair_syncopation list
-		NR_pair_syncopation = []
-		for i in range(len(terminal_nodes)-1,0,-1):
-			if terminal_nodes[i].node_type == 'R':
+		# 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].node_type == 'R':
 				for j in range(i-1, -1, -1):
-					if (terminal_nodes[j].node_type == 'N') & (terminal_nodes[i].metrical_weight >= terminal_nodes[j].metrical_weight):
-						NR_pair_syncopation.append(terminal_nodes[i].metrical_weight - terminal_nodes[j].metrical_weight)
+					if (terminalNodes[j].node_type == 'N') & (terminalNodes[i].metricalWeight >= terminalNodes[j].metricalWeight):
+						NRpairSyncopation.append(terminalNodes[i].metricalWeight - terminalNodes[j].metricalWeight)
 						break
-		#print NR_pair_syncopation
+		#print NRpairSyncopation
 
-		# If no syncopation, the value is -1; otherwise, sum all the local syncopation values stored in NR_pair_syncopation list	
-		if len(NR_pair_syncopation) != 0:
-			syncopation = sum(NR_pair_syncopation)	
-		elif len(terminal_nodes) != 0:
+		# If there are syncopation, sum all the local syncopation values stored in NRpairSyncopation list	
+		if len(NRpairSyncopation) != 0:
+			syncopation = sum(NRpairSyncopation)
+		# If no syncopation, the value is -1; 	
+		elif len(terminalNodes) != 0:
 			syncopation = -1
 
 	return syncopation
+
+
--- a/Syncopation models/PRS.py	Fri Apr 03 16:18:00 2015 +0100
+++ b/Syncopation models/PRS.py	Fri Apr 03 17:10:57 2015 +0100
@@ -3,54 +3,67 @@
 Institution: Centre for Digital Music, Queen Mary University of London
 '''
 
-from BasicFuncs import repeat, subdivide, ceiling, get_min_timeSpan
+from basic_functions import repeat, subdivide, ceiling, get_min_timeSpan, get_rhythm_category
 
-def get_cost(seq,next_seq):
-	seq = get_min_timeSpan(seq)					# converting to the minimum time-span format
+def get_cost(sequence,nextSequence):
+	sequence = get_min_timeSpan(sequence)					# converting to the minimum time-span format
 	
-	if seq[1:] == repeat([0],len(seq)-1):		# null prototype
+	if sequence[1:] == repeat([0],len(sequence)-1):		# null prototype
 		cost = 0
-	elif seq == repeat([1],len(seq)):			# filled prototype
+	elif sequence == repeat([1],len(sequence)):			# filled prototype
 		cost = 1
-	elif seq[0] == 1 and seq[-1] == 0:			# run1 prototype
+	elif sequence[0] == 1 and sequence[-1] == 0:			# run1 prototype
 		cost = 2
-	elif seq[0] == 1 and (next_seq == None or next_seq[0] == 0):	# run2 prototype
+	elif sequence[0] == 1 and (nextSequence == None or nenextSequencext_seq[0] == 0):	# run2 prototype
 		cost = 2
-	elif seq[0] == 1 and seq[-1] == 1 and next_seq != None and next_seq[0] == 1:		# upbeat prototype
+	elif sequence[0] == 1 and sequence[-1] == 1 and nextSequence != None and nextSequence[0] == 1:		# upbeat prototype
 		cost = 3
-	elif seq[0] == 0:							# syncopated prototype
+	elif sequence[0] == 0:							# syncopated prototype
 		cost = 5
 
 	return cost
 
 # This function calculates the syncopation value (cost) for the sequence with the postbar_seq for a certain level. 
-def syncopation_perlevel(sub_seqs, num_subs):
+def syncopation_perlevel(subSequences):
 	total = 0
-	for l in range(num_subs):
-		total = total + get_cost(sub_seqs[l], sub_seqs[l+1])
-	normalised = float(total)/num_subs
+	for l in range(len(subSequences)-1):
+		total = total + get_cost(subSequences[l], subSequences[l+1])
+	normalised = float(total)/(len(subSequences)-1)
 	
 	return normalised
 
-# This function calculates the overall syncopation value for a bar of sequence..
-def get_syncopation(seq,subdivision_seq, postbar_seq, rhythm_category):
+#def get_syncopation(seq,subdivision_seq, postbar_seq, rhythm_category):
+def get_syncopation(bar, weightSequence = None, LMax = None):
+	'''
+	The get_syncopation function calculates the overall syncopation value for a bar of sequence.
+	'''
 	syncopation = None
-	if rhythm_category == 'poly':
-		print 'Error: PRS model cannot deal with polyrhythms.'
+
+	binarySequence = bar.get_binary_sequence()
+	subdivisionSequence = bar.get_subdivision_sequence()
+
+	if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
+		print 'Warning: PRS model detects polyrhythms so returning None.'
 	else:
 		syncopation = 0
 
-		current_num_subs = 1	# the initial number of sub-sequences at a certain metrical level
-		for subdivisor in subdivision_seq:
+		if bar.get_next_bar() != None:
+			nextbarBinarySequence = bar.get_next_bar().get_binary_sequence()
+		else:
+			nextbarBinarySequence = None
+
+		# the initial number of sub-sequences at a certain metrical level
+		numberOfSubSeqs = 1	
+		for subdivisor in subdivisionSequence:
 			# the number of sub-sequence at the current level is product of all the subdivisors up to the current level
-			current_num_subs = current_num_subs * subdivisor
+			numberOfSubSeqs = numberOfSubSeqs * subdivisor
 			# recursion stops when the length of sub-sequence is less than 2
-			if len(seq)/current_num_subs >= 2:		
+			if len(binarySequence)/numberOfSubSeqs >= 2:		
 				# generate sub-sequences and append the next bar sequence
-				sub_seqs = subdivide(ceiling(seq), current_num_subs)	
-				sub_seqs.append(postbar_seq)
+				subSequences = subdivide(ceiling(binarySequence), numberOfSubSeqs)	
+				subSequences.append(nextbarBinarySequence)
 				# adding syncopation at each metrical level to the total syncopation
-				syncopation += syncopation_perlevel(sub_seqs, current_num_subs)	
+				syncopation += syncopation_perlevel(subSequences)	
 			else:
 				break