Mercurial > hg > syncopation-dataset
diff Syncopation models/synpy/SG.py @ 45:6e9154fc58df
moving the code files to the synpy package directory
author | christopherh <christopher.harte@eecs.qmul.ac.uk> |
---|---|
date | Thu, 23 Apr 2015 23:52:04 +0100 |
parents | |
children | 9a60ca4ae0fb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Syncopation models/synpy/SG.py Thu Apr 23 23:52:04 2015 +0100 @@ -0,0 +1,88 @@ +''' +Author: Chunyang Song +Institution: Centre for Digital Music, Queen Mary University of London + +''' + +from basic_functions import get_H, velocity_sequence_to_min_timespan, get_rhythm_category, upsample_velocity_sequence +from parameter_setter import are_parameters_valid + +def get_syncopation(bar, parameters = None): + syncopation = None + velocitySequence = bar.get_velocity_sequence() + subdivisionSequence = bar.get_subdivision_sequence() + + if get_rhythm_category(velocitySequence, subdivisionSequence) == 'poly': + print 'Warning: SG model detects polyrhythms so returning None.' + else: + #velocitySequence = velocity_sequence_to_min_timespan(velocitySequence) # converting to the minimum time-span format + + # set the defaults + Lmax = 5 + weightSequence = range(Lmax+1) # i.e. [0,1,2,3,4,5] + if parameters!= None: + if 'Lmax' in parameters: + Lmax = parameters['Lmax'] + if 'W' in parameters: + weightSequence = parameters['W'] + + if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence): + print 'Error: the given parameters are not valid.' + else: + # generate the metrical weights of level Lmax, and upsample(stretch) the velocity sequence to match the length of H + H = get_H(weightSequence,subdivisionSequence, Lmax) + + velocitySequence = upsample_velocity_sequence(velocitySequence, len(H)) + + # The ave_dif_neighbours function calculates the (weighted) average of the difference between the note at a certain index and its neighbours in a certain metrical level + def ave_dif_neighbours(index, level): + + averages = [] + parameterGarma = 0.8 + + # The findPre function is to calculate the index of the previous neighbour at a certain metrical level. + def find_pre(index, level): + preIndex = (index - 1)%len(H) # using % is to restrict the index varies within range(0, len(H)) + while(H[preIndex] > level): + preIndex = (preIndex - 1)%len(H) + #print 'preIndex', preIndex + return preIndex + + # The findPost function is to calculate the index of the next neighbour at a certain metrical level. + def find_post(index, level): + postIndex = (index + 1)%len(H) + while(H[postIndex] > level): + postIndex = (postIndex + 1)%len(H) + #print 'postIndex', postIndex + return postIndex + + # The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence + def dif(index1,index2): + parameterBeta = 0.5 + dif_v = velocitySequence[index1]-velocitySequence[index2] + dif_h = abs(H[index1]-H[index2]) + dif = dif_v*(parameterBeta*dif_h/4+1-parameterBeta) + #print 'dif', dif + return dif + + # From the highest to the lowest metrical levels where the current note resides, calculate the difference between the note and its neighbours at that level + for l in range(level, max(H)+1): + ave = (parameterGarma*dif(index,find_pre(index,l))+dif(index,find_post(index,l)) )/(1+parameterGarma) + averages.append(ave) + #print 'averages', averages + return averages + + # if the upsampling was successfully done + if velocitySequence != None: + syncopation = 0 + # Calculate the syncopation value for each note + for index in range(len(velocitySequence)): + if velocitySequence[index] != 0: # Onset detected + h = H[index] + # Syncopation potential according to its metrical level, which is equal to the metrical weight + potential = 1 - pow(0.5,h) + level = h # Metrical weight is equal to its metrical level + syncopation += min(ave_dif_neighbours(index, level))*potential + else: + print 'Try giving a bigger Lmax so that the rhythm sequence can be measured by the matching metrical weights sequence (H).' + return syncopation