annotate synpy/SG.py @ 76:90b68f259541 tip

updated parameter_setter to be able to find the TimeSignature.pkl file without putting it in the pwd
author christopherh <christopher.harte@eecs.qmul.ac.uk>
date Wed, 13 May 2015 09:27:36 +0100
parents ef891481231e
children
rev   line source
christopher@45 1 '''
christopher@45 2 Author: Chunyang Song
christopher@45 3 Institution: Centre for Digital Music, Queen Mary University of London
christopher@45 4
christopher@45 5 '''
christopher@45 6
christopher@71 7 from basic_functions import get_H, velocity_sequence_to_min_timespan, get_rhythm_category, upsample_velocity_sequence, find_rhythm_Lmax
christopher@45 8 from parameter_setter import are_parameters_valid
christopher@45 9
christopher@45 10 def get_syncopation(bar, parameters = None):
christopher@45 11 syncopation = None
christopher@45 12 velocitySequence = bar.get_velocity_sequence()
christopher@45 13 subdivisionSequence = bar.get_subdivision_sequence()
christopher@45 14
christopher@45 15 if get_rhythm_category(velocitySequence, subdivisionSequence) == 'poly':
christopher@45 16 print 'Warning: SG model detects polyrhythms so returning None.'
christopher@71 17 elif bar.is_empty():
christopher@71 18 print 'Warning: SG model detects empty bar so returning None.'
christopher@45 19 else:
christopher@71 20 velocitySequence = velocity_sequence_to_min_timespan(velocitySequence) # converting to the minimum time-span format
christopher@45 21
christopher@45 22 # set the defaults
christopher@71 23 Lmax = 10
christopher@45 24 weightSequence = range(Lmax+1) # i.e. [0,1,2,3,4,5]
christopher@45 25 if parameters!= None:
christopher@45 26 if 'Lmax' in parameters:
christopher@45 27 Lmax = parameters['Lmax']
christopher@45 28 if 'W' in parameters:
christopher@45 29 weightSequence = parameters['W']
christopher@45 30
christopher@45 31 if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence):
christopher@45 32 print 'Error: the given parameters are not valid.'
christopher@45 33 else:
christopher@71 34 Lmax = find_rhythm_Lmax(velocitySequence, Lmax, weightSequence, subdivisionSequence)
christopher@71 35 if Lmax != None:
christopher@71 36 # generate the metrical weights of level Lmax, and upsample(stretch) the velocity sequence to match the length of H
christopher@71 37 H = get_H(weightSequence,subdivisionSequence, Lmax)
christopher@71 38 #print len(velocitySequence)
christopher@71 39 #velocitySequence = upsample_velocity_sequence(velocitySequence, len(H))
christopher@71 40 #print len(velocitySequence)
christopher@71 41
christopher@71 42 # 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
christopher@71 43 def ave_dif_neighbours(index, level):
christopher@45 44
christopher@71 45 averages = []
christopher@71 46 parameterGarma = 0.8
christopher@71 47
christopher@71 48 # The findPre function is to calculate the index of the previous neighbour at a certain metrical level.
christopher@71 49 def find_pre(index, level):
christopher@71 50 preIndex = (index - 1)%len(H) # using % is to restrict the index varies within range(0, len(H))
christopher@71 51 while(H[preIndex] > level):
christopher@71 52 preIndex = (preIndex - 1)%len(H)
christopher@71 53 #print 'preIndex', preIndex
christopher@71 54 return preIndex
christopher@45 55
christopher@71 56 # The findPost function is to calculate the index of the next neighbour at a certain metrical level.
christopher@71 57 def find_post(index, level):
christopher@71 58 postIndex = (index + 1)%len(H)
christopher@71 59 while(H[postIndex] > level):
christopher@71 60 postIndex = (postIndex + 1)%len(H)
christopher@71 61 #print 'postIndex', postIndex
christopher@71 62 return postIndex
christopher@71 63
christopher@71 64 # The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence
christopher@71 65 def dif(index1,index2):
christopher@71 66 parameterBeta = 0.5
christopher@71 67 dif_v = velocitySequence[index1]-velocitySequence[index2]
christopher@71 68 dif_h = abs(H[index1]-H[index2])
christopher@71 69 diffactor = (parameterBeta*dif_h/4+1-parameterBeta)
christopher@71 70 if diffactor>1:
christopher@71 71 return dif_v
christopher@71 72 else:
christopher@71 73 return dif_v*diffactor
christopher@45 74
christopher@45 75
christopher@71 76 # 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
christopher@71 77 for l in range(level, max(H)+1):
christopher@71 78 ave = (parameterGarma*dif(index,find_pre(index,l))+dif(index,find_post(index,l)) )/(1+parameterGarma)
christopher@71 79 averages.append(ave)
christopher@71 80 return averages
christopher@45 81
christopher@71 82 # if the upsampling was successfully done
christopher@71 83 if velocitySequence != None:
christopher@71 84 syncopation = 0
christopher@71 85 # Calculate the syncopation value for each note
christopher@71 86 for index in range(len(velocitySequence)):
christopher@71 87 if velocitySequence[index] != 0: # Onset detected
christopher@71 88 h = H[index]
christopher@71 89 # Syncopation potential according to its metrical level, which is equal to the metrical weight
christopher@71 90 potential = 1 - pow(0.5,h)
christopher@71 91 level = h # Metrical weight is equal to its metrical level
christopher@71 92 syncopation += min(ave_dif_neighbours(index, level))*potential
christopher@71 93 else:
christopher@71 94 print 'Try giving a bigger Lmax so that the rhythm sequence can be measured by the matching metrical weights sequence (H).'
christopher@45 95 return syncopation