annotate Syncopation models/PRS.py @ 0:76ce27beba95

Have uploaded the syncopation dataset and audio wavefies.
author Chunyang Song <csong@eecs.qmul.ac.uk>
date Fri, 21 Mar 2014 15:49:46 +0000
parents
children b2da092dc2e0
rev   line source
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