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
|