diff Syncopation models/TMC.py @ 1:b2da092dc2e0

The consolidated syncopation software. Have finished individual model and basic functions. Need to revise the coding in main.py, and add rhythm-input interface.
author Chunyang Song <csong@eecs.qmul.ac.uk>
date Sun, 05 Oct 2014 21:52:41 +0100
parents 76ce27beba95
children 031e2ccb1fb6
line wrap: on
line diff
--- a/Syncopation models/TMC.py	Fri Mar 21 15:49:46 2014 +0000
+++ b/Syncopation models/TMC.py	Sun Oct 05 21:52:41 2014 +0100
@@ -2,71 +2,54 @@
 Author: Chunyang Song
 Institution: Centre for Digital Music, Queen Mary University of London
 
-** Toussaint's Metric Complexity Model **
-
-Algorithm:
-
-Only applicable to monorhythms.
-
-Define metrical hierarchy by given time signature;
-Calculate how many onsets and determine Maximum Metricality Max_Metric;
-Calculate the Metrical Simplicity - the weights of all onsets;
-Syncopation = Max_Metric - Metric_simplicity.
-Output the predicted syncopation score; -1 indicates non-applicable
-
 '''
 
-from MeterStructure import MeterStructure
+from basic_functions import get_H, ceiling, get_min_timeSpan
 
-def metricalModel(rhythm, time_sig, category, bar):
-	ms = MeterStructure(time_sig)
-	meter = ms.getLJWeights(bar)
-	if len(meter) !=0:
+# The get_metricity function calculates the metricity for a binary sequence with given sequence of metrical weights in a certain metrical level.
+def get_metricity(seq, H):
+	metricity = 0
+	for m in range(len(seq)):
+		metricity = metricity + seq[m]*H[m]
+	return metricity
+
+# The get_max_metricity function calculates the maximum metricity for the same number of notes in a binary sequence.
+def get_max_metricity(seq, H):
+	max_metricity = 0
+	H.sort(reverse=True) # Sort the metrical weight sequence from large to small
+	for i in range(sum(seq)):
+		max_metricity = max_metricity+H[i]
+	return max_metricity
+
+# The get_syncopation function calculates the syncopation value of the given sequence for TMC model. 
+def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category):
+	syncopation = None
+	if rhythm_category == 'poly':
+		print 'Error: TMC model cannot deal with polyrhythms.'
+	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
+			else:
+				matching_level = matching_level - 1
+
+		if new_L_max == True:
+			print 'Error: needs a bigger L_max (i.e. the lowest metrical level) to match the given rhythm sequence.'
 		
-		metricalSimplicity = 0  # sum of weights of onsets per bar
-		maxMetrical = 0 	 # maximum metricity per bar
-		onsetCount = 0		 # The number of onsets per bar
-	
-		if 'poly' in category:  # not applicable to polyrhythms
-			return -1
-	
-		# Calculate metricalSimplicity
 		else:
-			l = len(rhythm)
-			for i in range(l):
-				if rhythm[i] == 1: # onset detected
-					pos = int((float(i)/l) *len(meter)) # looking for the metrical position where this note locates
-					metricalSimplicity = metricalSimplicity+meter[pos]
-					onsetCount = onsetCount+1
-		
-			# Calculate max metricity
-			meter.sort(reverse=True)
-			for i in range(0,onsetCount):
-				maxMetrical = maxMetrical+meter[i]
+			# generate the metrical weights of the lowest level, 
+			# using the last matching_level number of elements in the weight_seq list, to make sure the last element is 1
+			H = get_H (weight_seq[-(matching_level+1):], subdivision_seq, matching_level)
 			
-			#print 'test', onsetCount, maxMetrical, metricalSimplicity
-			syncopation = (maxMetrical - metricalSimplicity)
-	
-			return syncopation	
-	else:
-		return -1
+			metricity = get_metricity(ceiling(seq), H)	# converting to binary sequence then calculate metricity
+			max_metricity = get_max_metricity(ceiling(seq), H)
 
-# Retrieve the stimuli
-f = file('stimuli.txt')
-#f = file('stimuli_34only.txt')
+			syncopation = max_metricity - metricity
+	return syncopation
 
-#Calculate syncopation for each rhythm pattern
-while True:
-	line = f.readline().split(';')
-	if len(line) == 1:
-		 break
-	else:
-		sti_name = line[0]
-		rhythmString = line[1].split()
-		time_sig = line[2]
-		category = line[3]
-		bar = int(line[4])
-		
-		rhythm = map(int,rhythmString[0].split(','))
-
-		print sti_name, metricalModel(rhythm, time_sig, category, bar)