diff Syncopation models/SG.py @ 20:b959c2acb927

Refactored all models except for KTH, all past testing except for SG.
author csong <csong@eecs.qmul.ac.uk>
date Tue, 07 Apr 2015 19:05:07 +0100
parents 031e2ccb1fb6
children df1e7c378ee0
line wrap: on
line diff
--- a/Syncopation models/SG.py	Fri Apr 03 22:57:27 2015 +0100
+++ b/Syncopation models/SG.py	Tue Apr 07 19:05:07 2015 +0100
@@ -4,73 +4,85 @@
 
 '''
 
-from BasicFuncs import get_H, get_min_timeSpan
+from basic_functions import get_H, get_min_timeSpan, get_rhythm_category
+from TMC import find_L
 
-def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category):
+#def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category):
+def get_syncopation(bar, parameters = None):
 	syncopation = None
-	if rhythm_category == 'poly':
-		print 'Error: SG model cannot deal with polyrhythms.'
+	velocitySequence = bar.get_velocity_sequence()
+	subdivisionSequence = bar.get_subdivision_sequence()
+
+	if get_rhythm_category(velocitySequence, subdivisionSequence) == 'poly':
+		print 'Warning: SG model detects polyrhythms so returning None.'
 	else:
-		
-		seq = get_min_timeSpan(seq)	# converting to the minimum time-span format
-		
-		# checking whether the given L_max is enough to analyse the given sequence, if not, request a bigger L_max
-		new_L_max = True
-		matching_level = L_max
-		while matching_level >= 0:
-			if len(get_H(weight_seq,subdivision_seq, matching_level)) == len(seq):
-				new_L_max = False
-				break
+		velocitySequence = get_min_timeSpan(velocitySequence)	# converting to the minimum time-span format
+
+		# If the parameters are not given, use the default settings
+		if parameters == None:
+			Lmax  = 5
+			weightSequence = range(Lmax+1) # i.e. [0,1,2,3,4,5]
+		else:
+			if are_parameters_valid(parameters):
+				Lmax = parameters['Lmax']
+				weightSequence = parameters['W']
 			else:
-				matching_level = matching_level - 1
+				pass
+				#raise InvalidParameterError
 
-		if new_L_max == True:
-			print 'Error: needs a bigger L_max (i.e. the lowest metrical level) to match the given rhythm sequence.'
-
-		else:
+		L = find_L(velocitySequence, Lmax, weightSequence, subdivisionSequence) 
+		print 'L', L
+		if L != None:
 			syncopation = 0
 			# generate the metrical weights of the lowest level
-			H = get_H(weight_seq,subdivision_seq, matching_level)
+			H = get_H(weightSequence,subdivisionSequence, L)
+			print 'H', H
 
-			# The aveDif_neighbours function calculates the (weighted) average of the difference between the note at a certain index and its neighbours in a certain metrical level
-			def aveDif_neighbours(index, level):
+			# The ave_dif_neighbours function calculates the (weighted) average of the difference between the note at a certain index and its neighbours in a certain metrical level
+			def ave_dif_neighbours(index, level):
+
 				averages = []
-				parameter_garma = 0.8
+				parameterGarma = 0.8
 				
 				# The findPre function is to calculate the index of the previous neighbour at a certain metrical level.
-				def findPre(index, level):
-					pre_index = (index - 1)%len(H)
-					while(H[pre_index] > level):
-						pre_index = (pre_index - 1)%len(H)
-					return pre_index
+				def find_pre(index, level):
+					preIndex = (index - 1)%len(H)	# using % is to restrict the index varies within range(0, len(H))
+					while(H[preIndex] > level):
+						preIndex = (preIndex - 1)%len(H)
+					print 'preIndex', preIndex
+					return preIndex
 
 				# The findPost function is to calculate the index of the next neighbour at a certain metrical level.
-				def findPost(index, level):
-					post_index = (index + 1)%len(H)
-					while(H[post_index] > level):
-						post_index = (post_index + 1)%len(H)
-					return post_index
+				def find_post(index, level):
+					postIndex = (index + 1)%len(H)
+					while(H[postIndex] > level):
+						postIndex = (postIndex + 1)%len(H)
+					print 'postIndex', postIndex
+					return postIndex
 				
 				# The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence
 				def dif(index1,index2):
-					parameter_beta = 0.5
-					dif_v = seq[index1]-seq[index2]
+					parameterBeta = 0.5
+					dif_v = velocitySequence[index1]-velocitySequence[index2]
 					dif_h = abs(H[index1]-H[index2])
-					dif = dif_v*(parameter_beta*dif_h/4+1-parameter_beta)
+					dif = dif_v*(parameterBeta*dif_h/4+1-parameterBeta)
+					print 'dif', dif
 					return dif
 
 				# From the highest to the lowest metrical levels where the current note resides, calculate the difference between the note and its neighbours at that level
 				for l in range(level, max(H)+1):
-					ave = ( parameter_garma*dif(index,findPre(index,l))+dif(index,findPost(index,l)) )/(1+parameter_garma)
+					ave = (parameterGarma*dif(index,find_pre(index,l))+dif(index,find_post(index,l)) )/(1+parameterGarma)
 					averages.append(ave)
+				print 'averages', averages
 				return averages
 
 			# Calculate the syncopation value for each note
-			for index in range(len(seq)):
-				if seq[index] != 0: # Onset detected
-					h = H[index]
-					potential = 1 - pow(0.5,h) # Syncopation potential according to its metrical level, which is equal to the metrical weight
-					level = h 		# Metrical weight happens to be equal to its metrical level
-					syncopation += min(aveDif_neighbours(index, h))*potential
+			for index in range(len(velocitySequence)):
+				if velocitySequence[index] != 0: # Onset detected
+					h = H[index] 
+					# Syncopation potential according to its metrical level, which is equal to the metrical weight
+					potential = 1 - pow(0.5,h)
+					level = h 		# Metrical weight is equal to its metrical level
+					syncopation += min(ave_dif_neighbours(index, level))*potential
 			
 	return syncopation