annotate Syncopation models/SG.py @ 28:5de1cb45c145

Parameters setting implemented.
author csong <csong@eecs.qmul.ac.uk>
date Sun, 12 Apr 2015 22:34:35 +0100
parents d9d22e6f396d
children 273450d5980a
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@26 7 from basic_functions import get_H, velocity_sequence_to_min_timespan, get_rhythm_category, upsample_velocity_sequence
csong@0 8
csong@20 9 def get_syncopation(bar, parameters = None):
csong@1 10 syncopation = None
csong@20 11 velocitySequence = bar.get_velocity_sequence()
csong@20 12 subdivisionSequence = bar.get_subdivision_sequence()
csong@20 13
csong@20 14 if get_rhythm_category(velocitySequence, subdivisionSequence) == 'poly':
csong@20 15 print 'Warning: SG model detects polyrhythms so returning None.'
csong@0 16 else:
csong@26 17 #velocitySequence = velocity_sequence_to_min_timespan(velocitySequence) # converting to the minimum time-span format
csong@20 18
csong@28 19 # set the defaults
csong@28 20 Lmax = 5
csong@28 21 weightSequence = range(Lmax+1) # i.e. [0,1,2,3,4,5]
csong@28 22 if parameters!= None:
csong@28 23 if 'Lmax' in parameters:
csong@28 24 Lmax = parameters['Lmax']
csong@28 25 if 'W' in parameters:
csong@28 26 weightSequence = parameters['W']
csong@28 27
csong@28 28 if not are_parameters_valid(Lmax, weightSequence, subdivisionSequence):
csong@28 29 print 'Error: the given parameters are not valid.'
csong@20 30 else:
csong@28 31 # generate the metrical weights of level Lmax, and upsample(stretch) the velocity sequence to match the length of H
csong@28 32 H = get_H(weightSequence,subdivisionSequence, Lmax)
csong@28 33 velocitySequence = upsample_velocity_sequence(velocitySequence, len(H))
csong@0 34
csong@28 35 # 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@28 36 def ave_dif_neighbours(index, level):
csong@0 37
csong@28 38 averages = []
csong@28 39 parameterGarma = 0.8
csong@28 40
csong@28 41 # The findPre function is to calculate the index of the previous neighbour at a certain metrical level.
csong@28 42 def find_pre(index, level):
csong@28 43 preIndex = (index - 1)%len(H) # using % is to restrict the index varies within range(0, len(H))
csong@28 44 while(H[preIndex] > level):
csong@28 45 preIndex = (preIndex - 1)%len(H)
csong@28 46 #print 'preIndex', preIndex
csong@28 47 return preIndex
csong@20 48
csong@28 49 # The findPost function is to calculate the index of the next neighbour at a certain metrical level.
csong@28 50 def find_post(index, level):
csong@28 51 postIndex = (index + 1)%len(H)
csong@28 52 while(H[postIndex] > level):
csong@28 53 postIndex = (postIndex + 1)%len(H)
csong@28 54 #print 'postIndex', postIndex
csong@28 55 return postIndex
csong@28 56
csong@28 57 # The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence
csong@28 58 def dif(index1,index2):
csong@28 59 parameterBeta = 0.5
csong@28 60 dif_v = velocitySequence[index1]-velocitySequence[index2]
csong@28 61 dif_h = abs(H[index1]-H[index2])
csong@28 62 dif = dif_v*(parameterBeta*dif_h/4+1-parameterBeta)
csong@28 63 #print 'dif', dif
csong@28 64 return dif
csong@28 65
csong@28 66 # 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@28 67 for l in range(level, max(H)+1):
csong@28 68 ave = (parameterGarma*dif(index,find_pre(index,l))+dif(index,find_post(index,l)) )/(1+parameterGarma)
csong@28 69 averages.append(ave)
csong@28 70 #print 'averages', averages
csong@28 71 return averages
csong@28 72
csong@28 73 # if the upsampling was successfully done
csong@28 74 if velocitySequence != None:
csong@28 75 syncopation = 0
csong@28 76 # Calculate the syncopation value for each note
csong@28 77 for index in range(len(velocitySequence)):
csong@28 78 if velocitySequence[index] != 0: # Onset detected
csong@28 79 h = H[index]
csong@28 80 # Syncopation potential according to its metrical level, which is equal to the metrical weight
csong@28 81 potential = 1 - pow(0.5,h)
csong@28 82 level = h # Metrical weight is equal to its metrical level
csong@28 83 syncopation += min(ave_dif_neighbours(index, level))*potential
csong@26 84
csong@1 85 return syncopation