Mercurial > hg > syncopation-dataset
changeset 26:d9d22e6f396d
fixed SG!
author | csong <csong@eecs.qmul.ac.uk> |
---|---|
date | Sun, 12 Apr 2015 15:53:58 +0100 |
parents | df1e7c378ee0 |
children | ed29ed80635c |
files | Syncopation models/SG.py Syncopation models/basic_functions.py |
diffstat | 2 files changed, 62 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/Syncopation models/SG.py Sun Apr 12 13:06:17 2015 +0100 +++ b/Syncopation models/SG.py Sun Apr 12 15:53:58 2015 +0100 @@ -4,7 +4,7 @@ ''' -from basic_functions import get_H, velocity_sequence_to_min_timespan, get_rhythm_category +from basic_functions import get_H, velocity_sequence_to_min_timespan, get_rhythm_category, upsample_velocity_sequence from TMC import find_L #def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category): @@ -16,7 +16,7 @@ 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 + #velocitySequence = velocity_sequence_to_min_timespan(velocitySequence) # converting to the minimum time-span format # If the parameters are not given, use the default settings if parameters == None: @@ -30,59 +30,56 @@ pass #raise InvalidParameterError - L = find_L(velocitySequence, Lmax, weightSequence, subdivisionSequence) - print 'L', L - if L != None: - syncopation = 0 - # generate the metrical weights of the lowest level - H = get_H(weightSequence,subdivisionSequence, L) - print 'H', H + syncopation = 0 + # 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): + # 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 + 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 + # 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 + # 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 - # 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 - + # 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 + return syncopation
--- a/Syncopation models/basic_functions.py Sun Apr 12 13:06:17 2015 +0100 +++ b/Syncopation models/basic_functions.py Sun Apr 12 15:53:58 2015 +0100 @@ -79,6 +79,18 @@ isPrime = False return isPrime +# upsample a velocity sequence to certain length, e.g. [1,1] to [1,0,0,0,1,0,0,0] +def upsample_velocity_sequence(velocitySequence, length): + upsampledVelocitySequence = [0]*length + if length%len(velocitySequence) != 0: + print 'Error: the velocity sequence can only be upsampled to the interger times of its length.' + else: + scalingFactor = length/len(velocitySequence) + for index in range(len(velocitySequence)): + upsampledVelocitySequence[index*scalingFactor] = velocitySequence[index] + return upsampledVelocitySequence + + # convert a velocity sequence to its minimum time-span representation def velocity_sequence_to_min_timespan(velocitySequence): minTimeSpanVelocitySeq = [1] @@ -118,7 +130,6 @@ return noteSequence - # get_note_indices returns all the indices of all the notes in this velocity_sequence def get_note_indices(velocitySequence): noteIndices = [] @@ -159,7 +170,7 @@ e.g. prime_factors of polyrhythm 100100101010 in 4/4 is [2,3] but subdivision_seq = [1,2,2] for 4/4 ''' rhythmCategory = 'mono' - for f in find_prime_factors(len(get_min_timeSpan(velocitySequence))): + for f in find_prime_factors(len(velocity_sequence_to_min_timespan(velocitySequence))): if not (f in subdivisionSequence): rhythmCategory = 'poly' break