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@20
|
6 from basic_functions 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@20
|
15 #def get_syncopation(seq, subdivision_seq, strong_beat_level, postbar_seq):
|
csong@20
|
16 def get_syncopation(bar, parameters = None):
|
csong@1
|
17 syncopation = None
|
csong@1
|
18
|
csong@20
|
19 binarySequence = bar.get_binary_sequence()
|
csong@20
|
20 sequenceLength = len(binarySequence)
|
csong@20
|
21 subdivisionSequence = bar.get_subdivision_sequence()
|
csong@20
|
22 strongBeatLevel = bar.get_beat_level()
|
csong@20
|
23 nextbarBinarySequence = None
|
csong@20
|
24
|
csong@20
|
25 if bar.get_next_bar() != None:
|
csong@20
|
26 nextbarBinarySequence = bar.get_next_bar().get_binary_sequence()
|
csong@20
|
27
|
csong@20
|
28 numberOfBeats = cumu_multiply(subdivisionSequence[0:strongBeatLevel+1]) # numberOfBeats is the number of strong beats
|
csong@2
|
29
|
csong@20
|
30 if sequenceLength % numberOfBeats != 0:
|
csong@20
|
31 print 'Error: the length of sequence is not subdivable by the subdivision factor in subdivision sequence.'
|
csong@1
|
32 else:
|
csong@1
|
33 # Find the indices of all the strong-beats
|
csong@20
|
34 beatIndices = []
|
csong@20
|
35 beatInterval = sequenceLength / numberOfBeats
|
csong@20
|
36 for i in range(numberOfBeats+1):
|
csong@20
|
37 beatIndices.append(i*beatInterval)
|
csong@20
|
38 if nextbarBinarySequence != None: # if there is a postbar_seq, add another two beats index for later calculation
|
csong@20
|
39 beatIndices += [sequenceLength+beatInterval, sequenceLength+ 2* beatInterval]
|
csong@0
|
40
|
csong@20
|
41 noteIndices = get_note_indices(binarySequence) # all the notes
|
csong@0
|
42
|
csong@1
|
43 # Calculate the WNBD measure for each note
|
csong@20
|
44 def measure_pernote(noteIndices, nextNoteIndex):
|
csong@1
|
45 # Find the nearest beats where this note locates - in [beat_indices[j], beat_indices[j+1])
|
csong@1
|
46 j = 0
|
csong@20
|
47 while noteIndices < beatIndices[j] or noteIndices >= beatIndices[j+1]:
|
csong@1
|
48 j = j + 1
|
csong@1
|
49
|
csong@1
|
50 # The distance of note to nearest beat normalised by the beat interval
|
csong@20
|
51 distanceToNearestBeat = min(abs(noteIndices - beatIndices[j]), abs(noteIndices - beatIndices[j+1]))/float(beatInterval)
|
csong@0
|
52
|
csong@1
|
53 # if this note is on-beat
|
csong@20
|
54 if distanceToNearestBeat == 0:
|
csong@1
|
55 measure = 0
|
csong@1
|
56 # or if this note is held on past the following beat, but ends on or before the later beat
|
csong@20
|
57 elif beatIndices[j+1] < nextNoteIndex <= beatIndices[j+2]:
|
csong@20
|
58 measure = float(2)/distanceToNearestBeat
|
csong@1
|
59 else:
|
csong@20
|
60 measure = float(1)/distanceToNearestBeat
|
csong@1
|
61 return measure
|
csong@0
|
62
|
csong@1
|
63 total = 0
|
csong@20
|
64 for i in range(len(noteIndices)):
|
csong@20
|
65 # if this is the last note, end_time is the index of the following note in the next bar
|
csong@20
|
66 if i == len(noteIndices)-1:
|
csong@20
|
67 # if the next bar is not none or a bar of full rest,
|
csong@20
|
68 # the nextNoteIndex is the sum of sequence length in the current bar and the noteIndex in the next bar
|
csong@20
|
69 if nextbarBinarySequence != None and nextbarBinarySequence != repeat([0],len(nextbarBinarySequence)):
|
csong@20
|
70 nextNoteIndex = get_note_indices(nextbarBinarySequence)[0]+sequenceLength
|
csong@20
|
71 # else when the next bar is none or full rest, end_time is the end of this sequence.
|
csong@20
|
72 else:
|
csong@20
|
73 nextNoteIndex = sequenceLength
|
csong@20
|
74 # else this is not the last note, the nextNoteIndex is the following element in the noteIndices list
|
csong@0
|
75 else:
|
csong@20
|
76 nextNoteIndex = noteIndices[i+1]
|
csong@20
|
77 # sum up the syncopation value for individual note at noteIndices[i]
|
csong@20
|
78 total += measure_pernote(noteIndices[i],nextNoteIndex)
|
csong@0
|
79
|
csong@2
|
80 #syncopation = float(total) / len(note_indices)
|
csong@0
|
81
|
csong@20
|
82 # return the total value, leave the normalisation done in the end
|
csong@2
|
83 return total
|