annotate 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
rev   line source
csong@0 1 '''
csong@0 2 Author: Chunyang Song
csong@0 3 Institution: Centre for Digital Music, Queen Mary University of London
csong@0 4
csong@1 5 '''
csong@2 6 from BasicFuncs import repeat, get_note_indices
csong@0 7
csong@2 8 # To find the product of multiple numbers
csong@1 9 def cumu_multiply(numbers):
csong@1 10 product = 1
csong@1 11 for n in numbers:
csong@1 12 product = product*n
csong@1 13 return product
csong@0 14
csong@1 15 def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq):
csong@1 16 syncopation = None
csong@1 17
csong@1 18 num_beats = cumu_multiply(subdivision_seq[0:strong_beat_level+1]) # num_beats is the number of strong beats
csong@2 19
csong@1 20 if len(seq)%num_beats != 0:
csong@1 21 print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision_seq.'
csong@1 22 else:
csong@1 23 # Find the indices of all the strong-beats
csong@1 24 beat_indices = []
csong@1 25 beat_interval = len(seq)/num_beats
csong@1 26 for i in range(num_beats+1):
csong@1 27 beat_indices.append(i*beat_interval)
csong@1 28 if postbar_seq != None: # if there is a postbar_seq, add another two beats index for later calculation
csong@1 29 beat_indices += [len(seq)+beat_interval, len(seq)+ 2* beat_interval]
csong@0 30
csong@1 31 note_indices = get_note_indices(seq) # all the notes
csong@0 32
csong@1 33 # Calculate the WNBD measure for each note
csong@1 34 def measure_pernote(note_index, nextnote_index):
csong@1 35 # Find the nearest beats where this note locates - in [beat_indices[j], beat_indices[j+1])
csong@1 36 j = 0
csong@1 37 while note_index < beat_indices[j] or note_index >= beat_indices[j+1]:
csong@1 38 j = j + 1
csong@1 39
csong@1 40 # The distance of note to nearest beat normalised by the beat interval
csong@1 41 distance_nearest_beat = min(abs(note_index - beat_indices[j]), abs(note_index - beat_indices[j+1]))/float(beat_interval)
csong@0 42
csong@1 43 # if this note is on-beat
csong@1 44 if distance_nearest_beat == 0:
csong@1 45 measure = 0
csong@1 46 # or if this note is held on past the following beat, but ends on or before the later beat
csong@1 47 elif beat_indices[j+1] < nextnote_index <= beat_indices[j+2]:
csong@1 48 measure = float(2)/distance_nearest_beat
csong@1 49 else:
csong@1 50 measure = float(1)/distance_nearest_beat
csong@0 51
csong@1 52 return measure
csong@0 53
csong@1 54 total = 0
csong@1 55 for i in range(len(note_indices)):
csong@1 56 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
csong@1 57 if postbar_seq != None and postbar_seq != repeat([0],len(postbar_seq)):
csong@1 58 nextnote_index = get_note_indices(postbar_seq)[0]+len(seq)
csong@1 59 else: # or if the next bar is none or full rest, end_time is the end of this sequence.
csong@1 60 nextnote_index = len(seq)
csong@0 61 else:
csong@1 62 nextnote_index = note_indices[i+1]
csong@1 63 total += measure_pernote(note_indices[i],nextnote_index)
csong@0 64
csong@2 65 #syncopation = float(total) / len(note_indices)
csong@0 66
csong@2 67 return total