view Syncopation models/PRS.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 4acddc008048
line wrap: on
line source
'''
Author: Chunyang Song
Institution: Centre for Digital Music, Queen Mary University of London
'''

from BasicFuncs import repeat, subdivide, ceiling, get_min_timeSpan

def get_cost(seq,next_seq):
	seq = get_min_timeSpan(seq)					# converting to the minimum time-span format
	
	if seq[1:] == repeat([0],len(seq)-1):		# null prototype
		cost = 0
	elif seq == repeat([1],len(seq)):			# filled prototype
		cost = 1
	elif seq[0] == 1 and seq[-1] == 0:			# run1 prototype
		cost = 2
	elif seq[0] == 1 and (next_seq == None or next_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
		cost = 3
	elif seq[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):
	total = 0
	for l in range(num_subs):
		total = total + get_cost(sub_seqs[l], sub_seqs[l+1])
	normalised = float(total)/num_subs
	
	return normalised

# This function calculates the overall syncopation value for a bar of sequence..
def get_syncopation(seq,subdivision_seq, postbar_seq, rhythm_category):
	syncopation = None
	if rhythm_category == 'poly':
		print 'Error: PRS model cannot deal with polyrhythms.'
	else:
		syncopation = 0

		current_num_subs = 1	# the initial number of sub-sequences at a certain metrical level
		for subdivisor in subdivision_seq:
			# 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
			# recursion stops when the length of sub-sequence is less than 2
			if len(seq)/current_num_subs >= 2:		
				# generate sub-sequences and append the next bar sequence
				sub_seqs = subdivide(ceiling(seq), current_num_subs)	
				sub_seqs.append(postbar_seq)
				# adding syncopation at each metrical level to the total syncopation
				syncopation += syncopation_perlevel(sub_seqs, current_num_subs)	
			else:
				break

	return syncopation