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 ** Pressing's model **
|
csong@0
|
6
|
csong@0
|
7 Algorithm:
|
csong@0
|
8
|
csong@0
|
9 Only applicable to simple rhtyhms.
|
csong@0
|
10
|
csong@0
|
11 Generate hierarchical metrical structure for rhythms, they way as same as LHL model;
|
csong@0
|
12
|
csong@0
|
13
|
csong@0
|
14 '''
|
csong@0
|
15
|
csong@0
|
16 def subdivide(sequence, segments_num):
|
csong@0
|
17 subSeq = []
|
csong@0
|
18 if len(sequence) % segments_num != 0:
|
csong@0
|
19 print 'Error: rhythm segment cannot be equally subdivided '
|
csong@0
|
20 else:
|
csong@0
|
21 n = len(sequence) / segments_num
|
csong@0
|
22 start , end = 0, n
|
csong@0
|
23 for i in range(segments_num):
|
csong@0
|
24 subSeq.append(sequence[start : end])
|
csong@0
|
25 start = end
|
csong@0
|
26 end = end + n
|
csong@0
|
27
|
csong@0
|
28 return subSeq
|
csong@0
|
29
|
csong@0
|
30 # To check whether there is a need to continue subdividing and measuring
|
csong@0
|
31 def checkContinue(sequence, division):
|
csong@0
|
32 isContinue = False
|
csong@0
|
33 if len(sequence) % division == 0:
|
csong@0
|
34 subs = subdivide (sequence, division)
|
csong@0
|
35
|
csong@0
|
36 for s in subs:
|
csong@0
|
37 if 1 in s[1:]: # If there are still onsets in-between the divisions
|
csong@0
|
38 isContinue = True
|
csong@0
|
39 else:
|
csong@0
|
40 print 'Error: the sequence cannot be equally subdivided!'
|
csong@0
|
41 return isContinue
|
csong@0
|
42
|
csong@0
|
43 def timeSpanTranscribe(sequence):
|
csong@0
|
44 l = len(sequence)
|
csong@0
|
45 transcribe = []
|
csong@0
|
46
|
csong@0
|
47 if not (1 in sequence): # Full rest
|
csong@0
|
48 transcribe = [0]
|
csong@0
|
49 else:
|
csong@0
|
50 divisor = 1
|
csong@0
|
51 while True:
|
csong@0
|
52 if l%divisor != 0:
|
csong@0
|
53 divisor = divisor + 1
|
csong@0
|
54 else:
|
csong@0
|
55 sampleStep = l/divisor # how many digits in each segment, divisor also represents the number of segments
|
csong@0
|
56 template = (([1] + [0]*(sampleStep-1) ) * divisor )
|
csong@0
|
57
|
csong@0
|
58 sampled = []
|
csong@0
|
59 for i in range(l):
|
csong@0
|
60 sampled.append(sequence[i] and template[i])
|
csong@0
|
61
|
csong@0
|
62 if sequence == sampled:
|
csong@0
|
63 break
|
csong@0
|
64 else:
|
csong@0
|
65 divisor = divisor + 1
|
csong@0
|
66
|
csong@0
|
67 subs = subdivide(sequence, divisor)
|
csong@0
|
68 for s in subs:
|
csong@0
|
69 transcribe.append(s[0])
|
csong@0
|
70
|
csong@0
|
71 return transcribe
|
csong@0
|
72
|
csong@0
|
73 # Identify the type of rhythm sequence : 0- null; 1-filled; 2-run; 3-upbeat; 5-syncopated
|
csong@0
|
74 def syncType (sequence, followed_event):
|
csong@0
|
75
|
csong@0
|
76 # Null is full rest or only one single on-beat note, therefore no 0 in sequence[1:]
|
csong@0
|
77 if not(1 in sequence[1:]) :
|
csong@0
|
78 syncType = 0
|
csong@0
|
79
|
csong@0
|
80 else:
|
csong@0
|
81 ts = timeSpanTranscribe(sequence)
|
csong@0
|
82
|
csong@0
|
83 # Filled is equally spaced onsets, therefore all 1s in the time span transcribe of the sequence
|
csong@0
|
84 if not(0 in ts ):
|
csong@0
|
85 syncType = 1
|
csong@0
|
86 # Run is either starting with 1 and end with 0 in time span, or starting with 1 if next bar starts with 0
|
csong@0
|
87 elif ts[0] == 1 and ts[-1] == 0:
|
csong@0
|
88 syncType = 2
|
csong@0
|
89 elif followed_event ==0 and ts[0] == 1:
|
csong@0
|
90 syncType = 2
|
csong@0
|
91 # Upbeat requires next bars starting with 1 and at least the last event in time span is 1
|
csong@0
|
92 elif followed_event == 1 and ts[-1] == 1:
|
csong@0
|
93 syncType = 3
|
csong@0
|
94 # Syncopated start and end off-beat
|
csong@0
|
95 elif sequence[0] == 0:
|
csong@0
|
96 syncType = 5
|
csong@0
|
97 else:
|
csong@0
|
98 print 'Error: un-recognizable syncopation type ', sequence
|
csong@0
|
99 syncType = None
|
csong@0
|
100
|
csong@0
|
101 return syncType
|
csong@0
|
102
|
csong@0
|
103 def createHierarchy(rhythm, time_sig, bar):
|
csong@0
|
104 h = [] # A list of lists to record syncopation type(s) in each hierarchy level across bars
|
csong@0
|
105 s_bar = subdivide (rhythm, bar)
|
csong@0
|
106
|
csong@0
|
107 if '4/4' in time_sig:
|
csong@0
|
108
|
csong@0
|
109 for i in range(bar):
|
csong@0
|
110 bar_level = s_bar[i]
|
csong@0
|
111
|
csong@0
|
112 if i == bar -1:
|
csong@0
|
113 followed_event = s_bar[0][0]
|
csong@0
|
114 else:
|
csong@0
|
115 followed_event = s_bar[i+1][0]
|
csong@0
|
116
|
csong@0
|
117 h. append ( [syncType(bar_level, followed_event)] ) # Indentify syncopation type at bar level
|
csong@0
|
118
|
csong@0
|
119 if checkContinue(rhythm, 2*bar):
|
csong@0
|
120
|
csong@0
|
121 for i in range(bar):
|
csong@0
|
122 s_halfBar = subdivide (s_bar[i], 2)
|
csong@0
|
123 halfBar_h = []
|
csong@0
|
124
|
csong@0
|
125 for j in range(2):
|
csong@0
|
126 halfBar_level = s_halfBar[j]
|
csong@0
|
127
|
csong@0
|
128 if j == 1:
|
csong@0
|
129 followed_event = s_halfBar[0][0]
|
csong@0
|
130 else:
|
csong@0
|
131 followed_event = s_halfBar[j+1][0]
|
csong@0
|
132
|
csong@0
|
133 halfBar_h.append (syncType (halfBar_level , followed_event))
|
csong@0
|
134
|
csong@0
|
135 h.append(halfBar_h)
|
csong@0
|
136
|
csong@0
|
137 if checkContinue(rhythm, 4*bar):
|
csong@0
|
138
|
csong@0
|
139 for i in range(bar):
|
csong@0
|
140 s_quarter = subdivide (s_bar[i], 4)
|
csong@0
|
141 quarter_h = []
|
csong@0
|
142
|
csong@0
|
143 for j in range(4):
|
csong@0
|
144 quarter_level = s_quarter [j]
|
csong@0
|
145
|
csong@0
|
146 if j == 3:
|
csong@0
|
147 followed_event = s_quarter[0][0]
|
csong@0
|
148 else:
|
csong@0
|
149 followed_event = s_quarter[j+1][0]
|
csong@0
|
150
|
csong@0
|
151 quarter_h. append ( syncType (quarter_level , followed_event) ) # quarter note level
|
csong@0
|
152
|
csong@0
|
153 h.append(quarter_h)
|
csong@0
|
154
|
csong@0
|
155 if checkContinue( rhythm, 8*bar):
|
csong@0
|
156
|
csong@0
|
157 for i in range(bar):
|
csong@0
|
158 s_eighth = subdivide (s_bar[i], 8)
|
csong@0
|
159 eighth_h = []
|
csong@0
|
160
|
csong@0
|
161 for j in range(8):
|
csong@0
|
162 eighth_level = s_eighth [j]
|
csong@0
|
163
|
csong@0
|
164 if j == 7:
|
csong@0
|
165 followed_event = eighth_level[0][0]
|
csong@0
|
166 else:
|
csong@0
|
167 followed_event = eighth_level[j+1][0]
|
csong@0
|
168
|
csong@0
|
169 eighth_h.append (syncType (eighth_level, followed_event) )
|
csong@0
|
170
|
csong@0
|
171 h.append(eighth_h)
|
csong@0
|
172
|
csong@0
|
173
|
csong@0
|
174 elif '3/4' in time_sig:
|
csong@0
|
175 size_bar = len(s_bar)
|
csong@0
|
176 for i in range(size_bar):
|
csong@0
|
177 bar_level = s_bar[i]
|
csong@0
|
178
|
csong@0
|
179 quarter_h = []
|
csong@0
|
180 eighth_h = []
|
csong@0
|
181
|
csong@0
|
182 if i == size_bar -1:
|
csong@0
|
183 followed_event = s_bar[0][0]
|
csong@0
|
184 else:
|
csong@0
|
185 followed_event = s_bar[i+1][0]
|
csong@0
|
186
|
csong@0
|
187 h. append ( [syncType(bar_level, followed_event)] ) # Indentify syncopation type at bar level
|
csong@0
|
188
|
csong@0
|
189 if checkContinue(bar_level, 3):
|
csong@0
|
190 s_quarter = subdivide (bar_level, 3)
|
csong@0
|
191 size_quarter = len(s_quarter)
|
csong@0
|
192
|
csong@0
|
193 for j in range(size_quarter):
|
csong@0
|
194 quarter_level = s_quarter [j]
|
csong@0
|
195
|
csong@0
|
196 if j == size_quarter -1:
|
csong@0
|
197 followed_event = s_quarter[0][0]
|
csong@0
|
198 else:
|
csong@0
|
199 followed_event = s_quarter[j+1][0]
|
csong@0
|
200
|
csong@0
|
201 quarter_h. append ( syncType (quarter_level , followed_event) ) # quarter note level
|
csong@0
|
202
|
csong@0
|
203 if checkContinue( quarter_level, 2):
|
csong@0
|
204 s_eighth = subdivide (quarter_level, 2) # eighth note level
|
csong@0
|
205 size_eighth = len(s_eighth)
|
csong@0
|
206
|
csong@0
|
207 for k in range(size_eighth):
|
csong@0
|
208 eighth_level = s_eighth [k]
|
csong@0
|
209
|
csong@0
|
210 if k == size_eighth - 1:
|
csong@0
|
211 followed_event = eighth_level[0][0]
|
csong@0
|
212 else:
|
csong@0
|
213 followed_event = eighth_level[k+1][0]
|
csong@0
|
214
|
csong@0
|
215 eighth_h.append (syncType (eighth_level, followed_event) )
|
csong@0
|
216 h.append(eighth_h)
|
csong@0
|
217
|
csong@0
|
218 h.append(quarter_h)
|
csong@0
|
219
|
csong@0
|
220
|
csong@0
|
221 elif '6/8' in time_sig:
|
csong@0
|
222 for i in range(bar):
|
csong@0
|
223 bar_level = s_bar[i]
|
csong@0
|
224
|
csong@0
|
225 if i == bar -1:
|
csong@0
|
226 followed_event = s_bar[0][0]
|
csong@0
|
227 else:
|
csong@0
|
228 followed_event = s_bar[i+1][0]
|
csong@0
|
229
|
csong@0
|
230 h. append ( [syncType(bar_level, followed_event)] ) # Indentify syncopation type at bar level
|
csong@0
|
231
|
csong@0
|
232 if checkContinue(rhythm, 2*bar):
|
csong@0
|
233
|
csong@0
|
234 for i in range(bar):
|
csong@0
|
235 s_halfBar = subdivide (s_bar[i], 2)
|
csong@0
|
236 halfBar_h = []
|
csong@0
|
237
|
csong@0
|
238 for j in range(2):
|
csong@0
|
239 halfBar_level = s_halfBar [j]
|
csong@0
|
240
|
csong@0
|
241 if j == 1:
|
csong@0
|
242 followed_event = s_halfBar[0][0]
|
csong@0
|
243 else:
|
csong@0
|
244 followed_event = s_halfBar[j+1][0]
|
csong@0
|
245
|
csong@0
|
246 halfBar_h. append ( syncType (halfBar_level , followed_event) )
|
csong@0
|
247
|
csong@0
|
248 h.append(halfBar_h)
|
csong@0
|
249
|
csong@0
|
250 if checkContinue( rhythm, 6*bar):
|
csong@0
|
251
|
csong@0
|
252 for i in range(bar):
|
csong@0
|
253 s_eighth = subdivide (s_bar[i], 6) # eighth note level
|
csong@0
|
254 eighth_h = []
|
csong@0
|
255
|
csong@0
|
256 for j in range(6):
|
csong@0
|
257 eighth_level = s_eighth [j]
|
csong@0
|
258
|
csong@0
|
259 if j == 5:
|
csong@0
|
260 followed_event = eighth_level[0][0]
|
csong@0
|
261 else:
|
csong@0
|
262 followed_event = eighth_level[j+1][0]
|
csong@0
|
263
|
csong@0
|
264 eighth_h.append (syncType (eighth_level, followed_event) )
|
csong@0
|
265
|
csong@0
|
266 h.append(eighth_h)
|
csong@0
|
267
|
csong@0
|
268 else:
|
csong@0
|
269 print 'This time signature is not defined. Choose between 4/4, 3/4 or 6/8'
|
csong@0
|
270
|
csong@0
|
271 return h
|
csong@0
|
272
|
csong@0
|
273
|
csong@0
|
274 def pressing(rhythm, time_sig, category, bar):
|
csong@0
|
275 sync_oneLevel = []
|
csong@0
|
276
|
csong@0
|
277 if 'poly' in category:
|
csong@0
|
278 return -1
|
csong@0
|
279
|
csong@0
|
280 else:
|
csong@0
|
281 hierarchy = createHierarchy(rhythm, time_sig, bar)
|
csong@0
|
282 # print 'h', hierarchy
|
csong@0
|
283
|
csong@0
|
284 if len(hierarchy) != 0:
|
csong@0
|
285 for h in hierarchy:
|
csong@0
|
286 sync_oneLevel.append (sum(h) / float(len(h)) )
|
csong@0
|
287
|
csong@0
|
288 # Syncopation is the sum of averaged syncopation values of each level
|
csong@0
|
289 syncopation = sum (sync_oneLevel)
|
csong@0
|
290
|
csong@0
|
291 else:
|
csong@0
|
292 syncopation = 0
|
csong@0
|
293
|
csong@0
|
294 return syncopation
|
csong@0
|
295
|
csong@0
|
296
|
csong@0
|
297 # Retrieve the stimuli
|
csong@0
|
298 # f = file('stimuli.txt')
|
csong@0
|
299 f = file('stimuli_34only.txt')
|
csong@0
|
300
|
csong@0
|
301 #Calculate syncopation for each rhythm pattern
|
csong@0
|
302 while True:
|
csong@0
|
303 line = f.readline().split(';')
|
csong@0
|
304 if len(line) == 1:
|
csong@0
|
305 break
|
csong@0
|
306 else:
|
csong@0
|
307 sti_name = line[0]
|
csong@0
|
308 rhythmString = line[1].split()
|
csong@0
|
309 time_sig = line[2]
|
csong@0
|
310 category = line[3]
|
csong@0
|
311 bar = int([4])
|
csong@0
|
312
|
csong@0
|
313 rhythm = map(int,rhythmString[0].split(','))
|
csong@0
|
314
|
csong@0
|
315 print sti_name, pressing(rhythm, time_sig, category, bar)
|
csong@0
|
316
|