Mercurial > hg > syncopation-dataset
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/PRS.py Fri Mar 21 15:49:46 2014 +0000 @@ -0,0 +1,316 @@ +''' +Author: Chunyang Song +Institution: Centre for Digital Music, Queen Mary University of London + +** Pressing's model ** + +Algorithm: + +Only applicable to simple rhtyhms. + +Generate hierarchical metrical structure for rhythms, they way as same as LHL model; + + +''' + +def subdivide(sequence, segments_num): + subSeq = [] + if len(sequence) % segments_num != 0: + print 'Error: rhythm segment cannot be equally subdivided ' + else: + n = len(sequence) / segments_num + start , end = 0, n + for i in range(segments_num): + subSeq.append(sequence[start : end]) + start = end + end = end + n + + return subSeq + +# To check whether there is a need to continue subdividing and measuring +def checkContinue(sequence, division): + isContinue = False + if len(sequence) % division == 0: + subs = subdivide (sequence, division) + + for s in subs: + if 1 in s[1:]: # If there are still onsets in-between the divisions + isContinue = True + else: + print 'Error: the sequence cannot be equally subdivided!' + return isContinue + +def timeSpanTranscribe(sequence): + l = len(sequence) + transcribe = [] + + if not (1 in sequence): # Full rest + transcribe = [0] + else: + divisor = 1 + while True: + if l%divisor != 0: + divisor = divisor + 1 + else: + sampleStep = l/divisor # how many digits in each segment, divisor also represents the number of segments + template = (([1] + [0]*(sampleStep-1) ) * divisor ) + + sampled = [] + for i in range(l): + sampled.append(sequence[i] and template[i]) + + if sequence == sampled: + break + else: + divisor = divisor + 1 + + subs = subdivide(sequence, divisor) + for s in subs: + transcribe.append(s[0]) + + return transcribe + +# Identify the type of rhythm sequence : 0- null; 1-filled; 2-run; 3-upbeat; 5-syncopated +def syncType (sequence, followed_event): + + # Null is full rest or only one single on-beat note, therefore no 0 in sequence[1:] + if not(1 in sequence[1:]) : + syncType = 0 + + else: + ts = timeSpanTranscribe(sequence) + + # Filled is equally spaced onsets, therefore all 1s in the time span transcribe of the sequence + if not(0 in ts ): + syncType = 1 + # Run is either starting with 1 and end with 0 in time span, or starting with 1 if next bar starts with 0 + elif ts[0] == 1 and ts[-1] == 0: + syncType = 2 + elif followed_event ==0 and ts[0] == 1: + syncType = 2 + # Upbeat requires next bars starting with 1 and at least the last event in time span is 1 + elif followed_event == 1 and ts[-1] == 1: + syncType = 3 + # Syncopated start and end off-beat + elif sequence[0] == 0: + syncType = 5 + else: + print 'Error: un-recognizable syncopation type ', sequence + syncType = None + + return syncType + +def createHierarchy(rhythm, time_sig, bar): + h = [] # A list of lists to record syncopation type(s) in each hierarchy level across bars + s_bar = subdivide (rhythm, bar) + + if '4/4' in time_sig: + + for i in range(bar): + bar_level = s_bar[i] + + if i == bar -1: + followed_event = s_bar[0][0] + else: + followed_event = s_bar[i+1][0] + + h. append ( [syncType(bar_level, followed_event)] ) # Indentify syncopation type at bar level + + if checkContinue(rhythm, 2*bar): + + for i in range(bar): + s_halfBar = subdivide (s_bar[i], 2) + halfBar_h = [] + + for j in range(2): + halfBar_level = s_halfBar[j] + + if j == 1: + followed_event = s_halfBar[0][0] + else: + followed_event = s_halfBar[j+1][0] + + halfBar_h.append (syncType (halfBar_level , followed_event)) + + h.append(halfBar_h) + + if checkContinue(rhythm, 4*bar): + + for i in range(bar): + s_quarter = subdivide (s_bar[i], 4) + quarter_h = [] + + for j in range(4): + quarter_level = s_quarter [j] + + if j == 3: + followed_event = s_quarter[0][0] + else: + followed_event = s_quarter[j+1][0] + + quarter_h. append ( syncType (quarter_level , followed_event) ) # quarter note level + + h.append(quarter_h) + + if checkContinue( rhythm, 8*bar): + + for i in range(bar): + s_eighth = subdivide (s_bar[i], 8) + eighth_h = [] + + for j in range(8): + eighth_level = s_eighth [j] + + if j == 7: + followed_event = eighth_level[0][0] + else: + followed_event = eighth_level[j+1][0] + + eighth_h.append (syncType (eighth_level, followed_event) ) + + h.append(eighth_h) + + + elif '3/4' in time_sig: + size_bar = len(s_bar) + for i in range(size_bar): + bar_level = s_bar[i] + + quarter_h = [] + eighth_h = [] + + if i == size_bar -1: + followed_event = s_bar[0][0] + else: + followed_event = s_bar[i+1][0] + + h. append ( [syncType(bar_level, followed_event)] ) # Indentify syncopation type at bar level + + if checkContinue(bar_level, 3): + s_quarter = subdivide (bar_level, 3) + size_quarter = len(s_quarter) + + for j in range(size_quarter): + quarter_level = s_quarter [j] + + if j == size_quarter -1: + followed_event = s_quarter[0][0] + else: + followed_event = s_quarter[j+1][0] + + quarter_h. append ( syncType (quarter_level , followed_event) ) # quarter note level + + if checkContinue( quarter_level, 2): + s_eighth = subdivide (quarter_level, 2) # eighth note level + size_eighth = len(s_eighth) + + for k in range(size_eighth): + eighth_level = s_eighth [k] + + if k == size_eighth - 1: + followed_event = eighth_level[0][0] + else: + followed_event = eighth_level[k+1][0] + + eighth_h.append (syncType (eighth_level, followed_event) ) + h.append(eighth_h) + + h.append(quarter_h) + + + elif '6/8' in time_sig: + for i in range(bar): + bar_level = s_bar[i] + + if i == bar -1: + followed_event = s_bar[0][0] + else: + followed_event = s_bar[i+1][0] + + h. append ( [syncType(bar_level, followed_event)] ) # Indentify syncopation type at bar level + + if checkContinue(rhythm, 2*bar): + + for i in range(bar): + s_halfBar = subdivide (s_bar[i], 2) + halfBar_h = [] + + for j in range(2): + halfBar_level = s_halfBar [j] + + if j == 1: + followed_event = s_halfBar[0][0] + else: + followed_event = s_halfBar[j+1][0] + + halfBar_h. append ( syncType (halfBar_level , followed_event) ) + + h.append(halfBar_h) + + if checkContinue( rhythm, 6*bar): + + for i in range(bar): + s_eighth = subdivide (s_bar[i], 6) # eighth note level + eighth_h = [] + + for j in range(6): + eighth_level = s_eighth [j] + + if j == 5: + followed_event = eighth_level[0][0] + else: + followed_event = eighth_level[j+1][0] + + eighth_h.append (syncType (eighth_level, followed_event) ) + + h.append(eighth_h) + + else: + print 'This time signature is not defined. Choose between 4/4, 3/4 or 6/8' + + return h + + +def pressing(rhythm, time_sig, category, bar): + sync_oneLevel = [] + + if 'poly' in category: + return -1 + + else: + hierarchy = createHierarchy(rhythm, time_sig, bar) + # print 'h', hierarchy + + if len(hierarchy) != 0: + for h in hierarchy: + sync_oneLevel.append (sum(h) / float(len(h)) ) + + # Syncopation is the sum of averaged syncopation values of each level + syncopation = sum (sync_oneLevel) + + else: + syncopation = 0 + + return syncopation + + +# Retrieve the stimuli +# f = file('stimuli.txt') +f = file('stimuli_34only.txt') + +#Calculate syncopation for each rhythm pattern +while True: + line = f.readline().split(';') + if len(line) == 1: + break + else: + sti_name = line[0] + rhythmString = line[1].split() + time_sig = line[2] + category = line[3] + bar = int([4]) + + rhythm = map(int,rhythmString[0].split(',')) + + print sti_name, pressing(rhythm, time_sig, category, bar) +