annotate Syncopation models/SG.py @ 20:b959c2acb927

Refactored all models except for KTH, all past testing except for SG.
author csong <csong@eecs.qmul.ac.uk>
date Tue, 07 Apr 2015 19:05:07 +0100
parents 031e2ccb1fb6
children df1e7c378ee0
rev   line source
csong@0 1 '''
csong@0 2 Author: Chunyang Song
csong@0 3 Institution: Centre for Digital Music, Queen Mary University of London
csong@0 4
csong@0 5 '''
csong@0 6
csong@20 7 from basic_functions import get_H, get_min_timeSpan, get_rhythm_category
csong@20 8 from TMC import find_L
csong@0 9
csong@20 10 #def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category):
csong@20 11 def get_syncopation(bar, parameters = None):
csong@1 12 syncopation = None
csong@20 13 velocitySequence = bar.get_velocity_sequence()
csong@20 14 subdivisionSequence = bar.get_subdivision_sequence()
csong@20 15
csong@20 16 if get_rhythm_category(velocitySequence, subdivisionSequence) == 'poly':
csong@20 17 print 'Warning: SG model detects polyrhythms so returning None.'
csong@0 18 else:
csong@20 19 velocitySequence = get_min_timeSpan(velocitySequence) # converting to the minimum time-span format
csong@20 20
csong@20 21 # If the parameters are not given, use the default settings
csong@20 22 if parameters == None:
csong@20 23 Lmax = 5
csong@20 24 weightSequence = range(Lmax+1) # i.e. [0,1,2,3,4,5]
csong@20 25 else:
csong@20 26 if are_parameters_valid(parameters):
csong@20 27 Lmax = parameters['Lmax']
csong@20 28 weightSequence = parameters['W']
csong@1 29 else:
csong@20 30 pass
csong@20 31 #raise InvalidParameterError
csong@0 32
csong@20 33 L = find_L(velocitySequence, Lmax, weightSequence, subdivisionSequence)
csong@20 34 print 'L', L
csong@20 35 if L != None:
csong@1 36 syncopation = 0
csong@1 37 # generate the metrical weights of the lowest level
csong@20 38 H = get_H(weightSequence,subdivisionSequence, L)
csong@20 39 print 'H', H
csong@0 40
csong@20 41 # 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
csong@20 42 def ave_dif_neighbours(index, level):
csong@20 43
csong@0 44 averages = []
csong@20 45 parameterGarma = 0.8
csong@0 46
csong@1 47 # The findPre function is to calculate the index of the previous neighbour at a certain metrical level.
csong@20 48 def find_pre(index, level):
csong@20 49 preIndex = (index - 1)%len(H) # using % is to restrict the index varies within range(0, len(H))
csong@20 50 while(H[preIndex] > level):
csong@20 51 preIndex = (preIndex - 1)%len(H)
csong@20 52 print 'preIndex', preIndex
csong@20 53 return preIndex
csong@0 54
csong@1 55 # The findPost function is to calculate the index of the next neighbour at a certain metrical level.
csong@20 56 def find_post(index, level):
csong@20 57 postIndex = (index + 1)%len(H)
csong@20 58 while(H[postIndex] > level):
csong@20 59 postIndex = (postIndex + 1)%len(H)
csong@20 60 print 'postIndex', postIndex
csong@20 61 return postIndex
csong@0 62
csong@1 63 # The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence
csong@0 64 def dif(index1,index2):
csong@20 65 parameterBeta = 0.5
csong@20 66 dif_v = velocitySequence[index1]-velocitySequence[index2]
csong@1 67 dif_h = abs(H[index1]-H[index2])
csong@20 68 dif = dif_v*(parameterBeta*dif_h/4+1-parameterBeta)
csong@20 69 print 'dif', dif
csong@0 70 return dif
csong@0 71
csong@1 72 # 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
csong@1 73 for l in range(level, max(H)+1):
csong@20 74 ave = (parameterGarma*dif(index,find_pre(index,l))+dif(index,find_post(index,l)) )/(1+parameterGarma)
csong@0 75 averages.append(ave)
csong@20 76 print 'averages', averages
csong@0 77 return averages
csong@0 78
csong@1 79 # Calculate the syncopation value for each note
csong@20 80 for index in range(len(velocitySequence)):
csong@20 81 if velocitySequence[index] != 0: # Onset detected
csong@20 82 h = H[index]
csong@20 83 # Syncopation potential according to its metrical level, which is equal to the metrical weight
csong@20 84 potential = 1 - pow(0.5,h)
csong@20 85 level = h # Metrical weight is equal to its metrical level
csong@20 86 syncopation += min(ave_dif_neighbours(index, level))*potential
csong@1 87
csong@1 88 return syncopation