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@0
|
5 ** Sioros and Guedes's Model **
|
csong@0
|
6
|
csong@0
|
7 Algorithm:
|
csong@0
|
8
|
csong@0
|
9 Only applicable to monorhythms.
|
csong@0
|
10
|
csong@0
|
11 This version of implementation follows the description in authors' 2011 ISMIR paper and assumes each bar of rhythm is looped.
|
csong@0
|
12 Therefore each bar is calculated seperatedly in a loop-mode and summed up in the end as the total syncopation.
|
csong@0
|
13
|
csong@0
|
14 '''
|
csong@0
|
15
|
csong@0
|
16 from MeterStructure import MeterStructure
|
csong@0
|
17 from math import pow
|
csong@0
|
18
|
csong@0
|
19 def subdivide(sequence, segments_num):
|
csong@0
|
20 subSeq = []
|
csong@0
|
21 if len(sequence) % segments_num != 0:
|
csong@0
|
22 print 'Error: rhythm segment cannot be equally subdivided '
|
csong@0
|
23 else:
|
csong@0
|
24 n = len(sequence) / segments_num
|
csong@0
|
25 start , end = 0, n
|
csong@0
|
26 for i in range(segments_num):
|
csong@0
|
27 subSeq.append(sequence[start : end])
|
csong@0
|
28 start = end
|
csong@0
|
29 end = end + n
|
csong@0
|
30
|
csong@0
|
31 return subSeq
|
csong@0
|
32
|
csong@0
|
33
|
csong@0
|
34 def sgModel(rhythm, time_sig, category, bar):
|
csong@0
|
35 ms = MeterStructure(time_sig)
|
csong@0
|
36 mWeights = ms.getLHLWeights(1)
|
csong@0
|
37 #print "hierarchy", mWeights
|
csong@0
|
38 num_onsets = 0
|
csong@0
|
39 h_min = min(mWeights)
|
csong@0
|
40
|
csong@0
|
41 syncAbsolute = 0
|
csong@0
|
42 syncNormM = 0
|
csong@0
|
43 syncNormE = 0
|
csong@0
|
44
|
csong@0
|
45 if 'poly' in category:
|
csong@0
|
46 syncAbsolute = -1
|
csong@0
|
47 else:
|
csong@0
|
48 # segment rhythm into bars
|
csong@0
|
49 rhythm_byBar = subdivide (rhythm, bar)
|
csong@0
|
50
|
csong@0
|
51 def measurePerBar(rhythm):
|
csong@0
|
52 syncopation = 0
|
csong@0
|
53
|
csong@0
|
54 def aveNeighbours(index, h):
|
csong@0
|
55 averages = []
|
csong@0
|
56 parameter_k = 0.8
|
csong@0
|
57
|
csong@0
|
58 def findPre(h_hat):
|
csong@0
|
59 pre_index = index - 1
|
csong@0
|
60 while(mWeights[pre_index] < h_hat):
|
csong@0
|
61 pre_index = (pre_index - 1)%len(mWeights)
|
csong@0
|
62 #print "h_hat and pre", h_hat, pre_index
|
csong@0
|
63 return pre_index
|
csong@0
|
64
|
csong@0
|
65 def findPost(h_hat):
|
csong@0
|
66 post_index = (index + 1)%len(mWeights)
|
csong@0
|
67 while(mWeights[post_index] < h_hat):
|
csong@0
|
68 post_index = (post_index + 1)%len(mWeights)
|
csong@0
|
69 #print "h_hat and post", h_hat, post_index
|
csong@0
|
70 return post_index
|
csong@0
|
71
|
csong@0
|
72 def dif(index1,index2):
|
csong@0
|
73 parameter_beta = 0.5
|
csong@0
|
74 pos1 = int(float(index1)/len(mWeights)*48)
|
csong@0
|
75 pos2 = int(float(index2)/len(mWeights)*48)
|
csong@0
|
76 dif_v = rhythm[pos1]-rhythm[pos2]
|
csong@0
|
77 dif_h = abs(mWeights[index1]-mWeights[index2])
|
csong@0
|
78 dif = dif_v*(parameter_beta*dif_h/4+1-parameter_beta)
|
csong@0
|
79 #print 'dif', dif
|
csong@0
|
80 return dif
|
csong@0
|
81
|
csong@0
|
82 for h_hat in range(h_min,h+1):
|
csong@0
|
83 ave = ( parameter_k*dif(index,findPre(h_hat))+dif(index,findPost(h_hat)) )/(1+parameter_k)
|
csong@0
|
84 #print 'ave', ave
|
csong@0
|
85 averages.append(ave)
|
csong@0
|
86
|
csong@0
|
87 return averages
|
csong@0
|
88
|
csong@0
|
89 for pos in range(len(rhythm)):
|
csong@0
|
90 if rhythm[pos] != 0: # Onset detected
|
csong@0
|
91 #num_onsets += 1
|
csong@0
|
92 i = int((pos/48.0*len(mWeights)))
|
csong@0
|
93 h = mWeights[i]
|
csong@0
|
94 potential = 1 - pow(0.5,(-h))
|
csong@0
|
95 #print "intermediate", min(aveNeighbours(i,h))
|
csong@0
|
96 syncopation += min(aveNeighbours(i, h))*potential
|
csong@0
|
97
|
csong@0
|
98 return syncopation
|
csong@0
|
99
|
csong@0
|
100 for r in rhythm_byBar:
|
csong@0
|
101 syncAbsolute = syncAbsolute + measurePerBar(r)
|
csong@0
|
102 #syncAbsolute /= 2.0
|
csong@0
|
103
|
csong@0
|
104 return syncAbsolute
|
csong@0
|
105
|
csong@0
|
106 # Retrieve the stimuli
|
csong@0
|
107 #f = file('stimuli.txt')
|
csong@0
|
108 #f = file('stimuli_34only.txt')
|
csong@0
|
109 f = file('clave.txt')
|
csong@0
|
110
|
csong@0
|
111
|
csong@0
|
112 #Calculate syncopation for each rhythm pattern
|
csong@0
|
113 #while True:
|
csong@0
|
114 for i in range(1):
|
csong@0
|
115 line = f.readline().split(';')
|
csong@0
|
116 if len(line) == 1:
|
csong@0
|
117 break
|
csong@0
|
118 else:
|
csong@0
|
119 sti_name = line[0]
|
csong@0
|
120 rhythmString = line[1].split()
|
csong@0
|
121 time_sig = line[2]
|
csong@0
|
122 category = line[3]
|
csong@0
|
123 bar = int(line[4])
|
csong@0
|
124
|
csong@0
|
125 rhythm = map(int,rhythmString[0].split(','))
|
csong@0
|
126 print sti_name, sgModel(rhythm, time_sig, category, bar) |