csong@0: ''' csong@0: Author: Chunyang Song csong@0: Institution: Centre for Digital Music, Queen Mary University of London csong@0: csong@1: ''' csong@2: from BasicFuncs import repeat, get_note_indices csong@0: csong@2: # To find the product of multiple numbers csong@1: def cumu_multiply(numbers): csong@1: product = 1 csong@1: for n in numbers: csong@1: product = product*n csong@1: return product csong@0: csong@1: def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq): csong@1: syncopation = None csong@1: csong@1: num_beats = cumu_multiply(subdivision_seq[0:strong_beat_level+1]) # num_beats is the number of strong beats csong@2: csong@1: if len(seq)%num_beats != 0: csong@1: print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision_seq.' csong@1: else: csong@1: # Find the indices of all the strong-beats csong@1: beat_indices = [] csong@1: beat_interval = len(seq)/num_beats csong@1: for i in range(num_beats+1): csong@1: beat_indices.append(i*beat_interval) csong@1: if postbar_seq != None: # if there is a postbar_seq, add another two beats index for later calculation csong@1: beat_indices += [len(seq)+beat_interval, len(seq)+ 2* beat_interval] csong@0: csong@1: note_indices = get_note_indices(seq) # all the notes csong@0: csong@1: # Calculate the WNBD measure for each note csong@1: def measure_pernote(note_index, nextnote_index): csong@1: # Find the nearest beats where this note locates - in [beat_indices[j], beat_indices[j+1]) csong@1: j = 0 csong@1: while note_index < beat_indices[j] or note_index >= beat_indices[j+1]: csong@1: j = j + 1 csong@1: csong@1: # The distance of note to nearest beat normalised by the beat interval csong@1: distance_nearest_beat = min(abs(note_index - beat_indices[j]), abs(note_index - beat_indices[j+1]))/float(beat_interval) csong@0: csong@1: # if this note is on-beat csong@1: if distance_nearest_beat == 0: csong@1: measure = 0 csong@1: # or if this note is held on past the following beat, but ends on or before the later beat csong@1: elif beat_indices[j+1] < nextnote_index <= beat_indices[j+2]: csong@1: measure = float(2)/distance_nearest_beat csong@1: else: csong@1: measure = float(1)/distance_nearest_beat csong@0: csong@1: return measure csong@0: csong@1: total = 0 csong@1: for i in range(len(note_indices)): csong@1: 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: if postbar_seq != None and postbar_seq != repeat([0],len(postbar_seq)): csong@1: nextnote_index = get_note_indices(postbar_seq)[0]+len(seq) csong@1: else: # or if the next bar is none or full rest, end_time is the end of this sequence. csong@1: nextnote_index = len(seq) csong@0: else: csong@1: nextnote_index = note_indices[i+1] csong@1: total += measure_pernote(note_indices[i],nextnote_index) csong@0: csong@2: #syncopation = float(total) / len(note_indices) csong@0: csong@2: return total