view Syncopation models/WNBD.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 repeat, get_note_indices

# To find the product of multiple numbers
def cumu_multiply(numbers):
	product = 1
	for n in numbers:
		product = product*n
	return product

def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq):
	syncopation = None
	
	num_beats = cumu_multiply(subdivision_seq[0:strong_beat_level+1])	# num_beats is the number of strong beats
	
	if len(seq)%num_beats != 0:
		print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision_seq.'
	else:
		# Find the indices of all the strong-beats
		beat_indices = []
		beat_interval = len(seq)/num_beats
		for i in range(num_beats+1):
			beat_indices.append(i*beat_interval)
		if postbar_seq != None:		# if there is a postbar_seq, add another two beats index for later calculation
			beat_indices += [len(seq)+beat_interval, len(seq)+ 2* beat_interval]

		note_indices = get_note_indices(seq)	# all the notes

		# Calculate the WNBD measure for each note
		def measure_pernote(note_index, nextnote_index):
			# Find the nearest beats where this note locates - in [beat_indices[j], beat_indices[j+1]) 
			j = 0
			while note_index < beat_indices[j] or note_index >= beat_indices[j+1]:
				j = j + 1
			
			# The distance of note to nearest beat normalised by the beat interval
			distance_nearest_beat = min(abs(note_index - beat_indices[j]), abs(note_index - beat_indices[j+1]))/float(beat_interval)

			# if this note is on-beat
			if distance_nearest_beat == 0:	
				measure = 0
			# or if this note is held on past the following beat, but ends on or before the later beat  
			elif beat_indices[j+1] < nextnote_index <= beat_indices[j+2]:
				measure = float(2)/distance_nearest_beat
			else:
				measure = float(1)/distance_nearest_beat

			return measure

		total = 0
		for i in range(len(note_indices)):
			if i == len(note_indices)-1:# if this is the last note, end_time is the index of the following note in the next bar
				if postbar_seq != None and postbar_seq != repeat([0],len(postbar_seq)):
					nextnote_index = get_note_indices(postbar_seq)[0]+len(seq)
				else:	# or if the next bar is none or full rest, end_time is the end of this sequence.
					nextnote_index = len(seq)
			else:
				nextnote_index = note_indices[i+1]
			total += measure_pernote(note_indices[i],nextnote_index)

		#syncopation = float(total) / len(note_indices)

	return total