christopher@45
|
1 '''
|
christopher@45
|
2 Author: Chunyang Song
|
christopher@45
|
3 Institution: Centre for Digital Music, Queen Mary University of London
|
christopher@45
|
4 '''
|
christopher@45
|
5
|
christopher@45
|
6 from basic_functions import repeat, subdivide, ceiling, velocity_sequence_to_min_timespan, get_rhythm_category
|
christopher@45
|
7
|
christopher@45
|
8 def get_cost(sequence,nextSequence):
|
christopher@45
|
9 sequence = velocity_sequence_to_min_timespan(sequence) # converting to the minimum time-span format
|
christopher@45
|
10
|
christopher@45
|
11 if sequence[1:] == repeat([0],len(sequence)-1): # null prototype
|
christopher@45
|
12 cost = 0
|
christopher@45
|
13 elif sequence == repeat([1],len(sequence)): # filled prototype
|
christopher@45
|
14 cost = 1
|
christopher@45
|
15 elif sequence[0] == 1 and sequence[-1] == 0: # run1 prototype
|
christopher@45
|
16 cost = 2
|
christopher@45
|
17 elif sequence[0] == 1 and (nextSequence == None or nextSequence[0] == 0): # run2 prototype
|
christopher@45
|
18 cost = 2
|
christopher@45
|
19 elif sequence[-1] == 1 and nextSequence != None and nextSequence[0] == 1: # upbeat prototype
|
christopher@45
|
20 cost = 3
|
christopher@45
|
21 elif sequence[0] == 0: # syncopated prototype
|
christopher@45
|
22 cost = 5
|
christopher@45
|
23
|
christopher@45
|
24 return cost
|
christopher@45
|
25
|
christopher@45
|
26 # This function calculates the syncopation value (cost) for the sequence with the postbar_seq for a certain level.
|
christopher@45
|
27 def syncopation_perlevel(subSequences):
|
christopher@45
|
28 #print 'subSequences', subSequences
|
christopher@45
|
29 total = 0
|
christopher@45
|
30 for l in range(len(subSequences)-1):
|
christopher@45
|
31 #print 'cost', get_cost(subSequences[l], subSequences[l+1])
|
christopher@45
|
32 total = total + get_cost(subSequences[l], subSequences[l+1])
|
christopher@45
|
33 #print 'total this level', total
|
christopher@45
|
34 normalised = float(total)/(len(subSequences)-1)
|
christopher@45
|
35
|
christopher@45
|
36 return normalised
|
christopher@45
|
37
|
christopher@45
|
38 def get_syncopation(bar, parameters = None):
|
christopher@45
|
39 syncopation = None
|
christopher@45
|
40
|
christopher@50
|
41 binarySequence = velocity_sequence_to_min_timespan(bar.get_binary_sequence())
|
christopher@45
|
42 subdivisionSequence = bar.get_subdivision_sequence()
|
christopher@45
|
43
|
christopher@45
|
44 # PRS does not handle polyrhythms
|
christopher@45
|
45 if get_rhythm_category(binarySequence, subdivisionSequence) == 'poly':
|
christopher@45
|
46 print 'Warning: PRS model detects polyrhythms so returning None.'
|
christopher@50
|
47 elif bar.is_empty():
|
christopher@50
|
48 print 'Warning: PRS model detects empty bar so returning None.'
|
christopher@45
|
49 else:
|
christopher@45
|
50 syncopation = 0
|
christopher@45
|
51
|
christopher@45
|
52 # retrieve the binary sequence in the next bar
|
christopher@45
|
53 if bar.get_next_bar() != None:
|
christopher@45
|
54 nextbarBinarySequence = bar.get_next_bar().get_binary_sequence()
|
christopher@45
|
55 else:
|
christopher@45
|
56 nextbarBinarySequence = None
|
christopher@45
|
57
|
christopher@45
|
58 # numberOfSubSeqs is the number of sub-sequences at a certain metrical level, initialised to be 1 (at the bar level)
|
christopher@45
|
59 numberOfSubSeqs = 1
|
christopher@45
|
60 for subdivisor in subdivisionSequence:
|
christopher@45
|
61 # numberOfSubSeqs is product of all the subdivisors up to the current level
|
christopher@45
|
62 numberOfSubSeqs = numberOfSubSeqs * subdivisor
|
christopher@45
|
63
|
christopher@45
|
64 # recursion stops when the length of sub-sequence is less than 2
|
christopher@45
|
65 if len(binarySequence)/numberOfSubSeqs >= 2:
|
christopher@45
|
66 # generate sub-sequences and append the next bar sequence
|
christopher@45
|
67 subSequences = subdivide(ceiling(binarySequence), numberOfSubSeqs)
|
christopher@45
|
68 subSequences.append(nextbarBinarySequence)
|
christopher@45
|
69 # adding syncopation at each metrical level to the total syncopation
|
christopher@45
|
70 #print 'per level', syncopation_perlevel(subSequences)
|
christopher@45
|
71 syncopation += syncopation_perlevel(subSequences)
|
christopher@45
|
72 else:
|
christopher@45
|
73 break
|
christopher@45
|
74
|
christopher@45
|
75 return syncopation
|