Mercurial > hg > syncopation-dataset
view Syncopation models/Keith.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 |
line wrap: on
line source
''' Author: Chunyang Song Institution: Centre for Digital Music, Queen Mary University of London ** Keith Model ** Algorithm: Only applicable to binary meter (the number of beats is a power of 2). Calculate the duration (IOI) of each note, d; Round the d down to the nearest power of 2, D; Check if the start and the end of note are on-beat (whether divisible by D); If both on-beat, measure = 0; If start on-beat but end off-beat, measure = 1; If start off-beat but end on-beat, measure = 2; If start and end off-beat, measure = 3; Syncopation is the sum of measures of all notes. ''' from MeterStructure import MeterStructure def roundDownPower2(input): lower = 0 if input >=0: i = 0 lower = pow(2,i) while True: upper = pow(2,i+1) if lower <= input < upper: break else: lower = upper i = i+1 else: print 'Invalid input: input is negative' return lower def keith(rhythm, time_sig, category, bar): ms = MeterStructure(time_sig) circle = ms.getCircle(bar) l = len(circle) # mTemplate represents all the metrical positions for bar number of bars and the downbeat position of the following bar. #For example, the mTemplate for one bar in 4/4 rhythm with lowest level 16th note, mTemplate = [0:16] mTemplate = range(l+1) if len(mTemplate)!=0: onsetPos = [] measures = [] ''' Note that mTemplate is encoded by 8*bar+1- or 16*bar+1-long digits, rhythm is encoded by 48*bar-long digits, therefore we need to normalize the IOI of onsets to the mTemplate scale, by (pos/len(rhythm))*len(mTemplate) ''' # Locate all the onset, store the position of each note into onsetPos l = len(rhythm) for i in range(l): if rhythm[i] == 1: # onset detected onsetPos.append(i) #Calculate the duration of each onset and round it down to nearest power of 2, store into D # Then check if the start and end of each onset is on-beat, calculate measures n = len(onsetPos) for i in range(n): start = (onsetPos[i]/ float(l) )* (len(mTemplate)-1) if i == n-1: end = mTemplate[-1] # The duration of the last note is the its distance to the first beat in next bar else: end = (onsetPos[i+1]/ float (l) ) * (len(mTemplate)-1) # the duration of note is its distance to the next note d = end - start D = roundDownPower2(d) if start % D ==0 and end % D ==0: measures.append(0) elif start % D ==0 and end % D != 0: measures.append(1) elif start % D != 0 and end % D == 0: measures.append(2) else: measures.append(3) syncopation = sum(measures) return syncopation else: return -1 # Retrieve the stimuli f = file('stimuli.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(line[4]) rhythm = map(int,rhythmString[0].split(',')) print sti_name, keith(rhythm, time_sig, category, bar)