annotate Syncopation models/WNBD.py @ 1:b2da092dc2e0

The consolidated syncopation software. Have finished individual model and basic functions. Need to revise the coding in main.py, and add rhythm-input interface.
author Chunyang Song <csong@eecs.qmul.ac.uk>
date Sun, 05 Oct 2014 21:52:41 +0100
parents 76ce27beba95
children 031e2ccb1fb6
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@1 6 from basic_functions import repeat, get_note_indices
csong@0 7
csong@1 8 def cumu_multiply(numbers):
csong@1 9 product = 1
csong@1 10 for n in numbers:
csong@1 11 product = product*n
csong@1 12 return product
csong@0 13
csong@1 14 def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq):
csong@1 15 syncopation = None
csong@1 16
csong@1 17 num_beats = cumu_multiply(subdivision_seq[0:strong_beat_level+1]) # num_beats is the number of strong beats
csong@1 18 if len(seq)%num_beats != 0:
csong@1 19 print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision_seq.'
csong@1 20 else:
csong@1 21 # Find the indices of all the strong-beats
csong@1 22 beat_indices = []
csong@1 23 beat_interval = len(seq)/num_beats
csong@1 24 for i in range(num_beats+1):
csong@1 25 beat_indices.append(i*beat_interval)
csong@1 26 if postbar_seq != None: # if there is a postbar_seq, add another two beats index for later calculation
csong@1 27 beat_indices += [len(seq)+beat_interval, len(seq)+ 2* beat_interval]
csong@0 28
csong@1 29 note_indices = get_note_indices(seq) # all the notes
csong@0 30
csong@1 31 # Calculate the WNBD measure for each note
csong@1 32 def measure_pernote(note_index, nextnote_index):
csong@1 33 # Find the nearest beats where this note locates - in [beat_indices[j], beat_indices[j+1])
csong@1 34 j = 0
csong@1 35 while note_index < beat_indices[j] or note_index >= beat_indices[j+1]:
csong@1 36 j = j + 1
csong@1 37
csong@1 38 # The distance of note to nearest beat normalised by the beat interval
csong@1 39 distance_nearest_beat = min(abs(note_index - beat_indices[j]), abs(note_index - beat_indices[j+1]))/float(beat_interval)
csong@0 40
csong@1 41 # if this note is on-beat
csong@1 42 if distance_nearest_beat == 0:
csong@1 43 measure = 0
csong@1 44 # or if this note is held on past the following beat, but ends on or before the later beat
csong@1 45 elif beat_indices[j+1] < nextnote_index <= beat_indices[j+2]:
csong@1 46 measure = float(2)/distance_nearest_beat
csong@1 47 else:
csong@1 48 measure = float(1)/distance_nearest_beat
csong@0 49
csong@1 50 return measure
csong@0 51
csong@1 52 total = 0
csong@1 53 for i in range(len(note_indices)):
csong@1 54 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 55 if postbar_seq != None and postbar_seq != repeat([0],len(postbar_seq)):
csong@1 56 nextnote_index = get_note_indices(postbar_seq)[0]+len(seq)
csong@1 57 else: # or if the next bar is none or full rest, end_time is the end of this sequence.
csong@1 58 nextnote_index = len(seq)
csong@0 59 else:
csong@1 60 nextnote_index = note_indices[i+1]
csong@1 61 total += measure_pernote(note_indices[i],nextnote_index)
csong@0 62
csong@1 63 syncopation = float(total) / len(note_indices)
csong@0 64
csong@1 65 return syncopation