view Syncopation models/SG.py @ 2:031e2ccb1fb6

Added rhythm parser and parameter setter
author Chunyang Song <csong@eecs.qmul.ac.uk>
date Fri, 20 Mar 2015 18:28:08 +0000
parents b2da092dc2e0
children b959c2acb927
line wrap: on
line source
'''
Author: Chunyang Song
Institution: Centre for Digital Music, Queen Mary University of London

'''

from BasicFuncs import get_H, get_min_timeSpan

def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category):
	syncopation = None
	if rhythm_category == 'poly':
		print 'Error: SG 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.'

		else:
			syncopation = 0
			# generate the metrical weights of the lowest level
			H = get_H(weight_seq,subdivision_seq, matching_level)

			# 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):
				averages = []
				parameter_garma = 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

				# 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
				
				# 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]
					dif_h = abs(H[index1]-H[index2])
					dif = dif_v*(parameter_beta*dif_h/4+1-parameter_beta)
					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)
					averages.append(ave)
				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
			
	return syncopation