view Syncopation models/TMC.py @ 23:df1e7c378ee0

fixed KTH, and WNBD
author csong <csong@eecs.qmul.ac.uk>
date Sun, 12 Apr 2015 13:06:17 +0100
parents b959c2acb927
children 5de1cb45c145
line wrap: on
line source
'''
Author: Chunyang Song
Institution: Centre for Digital Music, Queen Mary University of London

'''

from basic_functions import get_H, ceiling, velocity_sequence_to_min_timespan, get_rhythm_category

# 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(binarySequence, H):
	metricity = 0
	for m in range(len(binarySequence)):
		metricity = metricity + binarySequence[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(binarySequence, H):
	maxMetricity = 0
	H.sort(reverse=True) # Sort the metrical weight sequence from large to small
	for i in range(sum(binarySequence)):
		maxMetricity = maxMetricity+H[i]
	return maxMetricity

# find the metrical level L that contains the same number of metrical positions as the length of the binary sequence
# if the given Lmax is not big enough to analyse the given sequence, request a bigger Lmax
def find_L(rhythmSequence, Lmax, weightSequence, subdivisionSequence):
	L = Lmax

	# initially assuming the Lmax is not big enough
	needBiggerLmax = True 
	
	# from the lowest metrical level (Lmax) to the highest, find the matching metrical level that 
	# has the same length as the length of binary sequence  
	while L >= 0:
		if len(get_H(weightSequence,subdivisionSequence, L)) == len(rhythmSequence):
			needBiggerLmax = False
			break
		else:
			L = L - 1

	# if need a bigger Lmax, print error message and return None; otherwise return the matching metrical level L
	if needBiggerLmax:
		print 'Error: needs a bigger L_max (i.e. the lowest metrical level) to match the given rhythm sequence.'
		L = None
	
	return L

# 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):
def get_syncopation(bar, parameters = None):
	syncopation = None
	binarySequence = bar.get_binary_sequence()
	subdivisionSequence = bar.get_subdivision_sequence()

	if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
		print 'Warning: TMC model detects polyrhythms so returning None.'
	else:
		binarySequence = velocity_sequence_to_min_timespan(binarySequence)	# 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,0,-1) # i.e. [6,5,4,3,2,1]
		else:
			if are_parameters_valid(parameters):
				Lmax = parameters['Lmax']
				weightSequence = parameters['W']
			else:
				pass
				#raise InvalidParameterError

		L = find_L(binarySequence, Lmax, weightSequence, subdivisionSequence) 
		if L != None:
			#? generate the metrical weights of the lowest level, 
			#? using the last matching_level number of elements in the weightSequence, to make sure the last element is 1
			H = get_H (weightSequence[-(L+1):], subdivisionSequence, L)
			
			metricity = get_metricity(binarySequence, H)	# converting to binary sequence then calculate metricity
			maxMetricity = get_max_metricity(binarySequence, H)

			syncopation = maxMetricity - metricity

	return syncopation