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
|