Mercurial > hg > syncopation-dataset
comparison 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 |
comparison
equal
deleted
inserted
replaced
19:9030967a05f8 | 20:b959c2acb927 |
---|---|
2 Author: Chunyang Song | 2 Author: Chunyang Song |
3 Institution: Centre for Digital Music, Queen Mary University of London | 3 Institution: Centre for Digital Music, Queen Mary University of London |
4 | 4 |
5 ''' | 5 ''' |
6 | 6 |
7 from BasicFuncs import get_H, get_min_timeSpan | 7 from basic_functions import get_H, get_min_timeSpan, get_rhythm_category |
8 from TMC import find_L | |
8 | 9 |
9 def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category): | 10 #def get_syncopation(seq, subdivision_seq, weight_seq, L_max, rhythm_category): |
11 def get_syncopation(bar, parameters = None): | |
10 syncopation = None | 12 syncopation = None |
11 if rhythm_category == 'poly': | 13 velocitySequence = bar.get_velocity_sequence() |
12 print 'Error: SG model cannot deal with polyrhythms.' | 14 subdivisionSequence = bar.get_subdivision_sequence() |
15 | |
16 if get_rhythm_category(velocitySequence, subdivisionSequence) == 'poly': | |
17 print 'Warning: SG model detects polyrhythms so returning None.' | |
13 else: | 18 else: |
14 | 19 velocitySequence = get_min_timeSpan(velocitySequence) # converting to the minimum time-span format |
15 seq = get_min_timeSpan(seq) # converting to the minimum time-span format | 20 |
16 | 21 # If the parameters are not given, use the default settings |
17 # checking whether the given L_max is enough to analyse the given sequence, if not, request a bigger L_max | 22 if parameters == None: |
18 new_L_max = True | 23 Lmax = 5 |
19 matching_level = L_max | 24 weightSequence = range(Lmax+1) # i.e. [0,1,2,3,4,5] |
20 while matching_level >= 0: | 25 else: |
21 if len(get_H(weight_seq,subdivision_seq, matching_level)) == len(seq): | 26 if are_parameters_valid(parameters): |
22 new_L_max = False | 27 Lmax = parameters['Lmax'] |
23 break | 28 weightSequence = parameters['W'] |
24 else: | 29 else: |
25 matching_level = matching_level - 1 | 30 pass |
31 #raise InvalidParameterError | |
26 | 32 |
27 if new_L_max == True: | 33 L = find_L(velocitySequence, Lmax, weightSequence, subdivisionSequence) |
28 print 'Error: needs a bigger L_max (i.e. the lowest metrical level) to match the given rhythm sequence.' | 34 print 'L', L |
29 | 35 if L != None: |
30 else: | |
31 syncopation = 0 | 36 syncopation = 0 |
32 # generate the metrical weights of the lowest level | 37 # generate the metrical weights of the lowest level |
33 H = get_H(weight_seq,subdivision_seq, matching_level) | 38 H = get_H(weightSequence,subdivisionSequence, L) |
39 print 'H', H | |
34 | 40 |
35 # The aveDif_neighbours function calculates the (weighted) average of the difference between the note at a certain index and its neighbours in a certain metrical level | 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 |
36 def aveDif_neighbours(index, level): | 42 def ave_dif_neighbours(index, level): |
43 | |
37 averages = [] | 44 averages = [] |
38 parameter_garma = 0.8 | 45 parameterGarma = 0.8 |
39 | 46 |
40 # The findPre function is to calculate the index of the previous neighbour at a certain metrical level. | 47 # The findPre function is to calculate the index of the previous neighbour at a certain metrical level. |
41 def findPre(index, level): | 48 def find_pre(index, level): |
42 pre_index = (index - 1)%len(H) | 49 preIndex = (index - 1)%len(H) # using % is to restrict the index varies within range(0, len(H)) |
43 while(H[pre_index] > level): | 50 while(H[preIndex] > level): |
44 pre_index = (pre_index - 1)%len(H) | 51 preIndex = (preIndex - 1)%len(H) |
45 return pre_index | 52 print 'preIndex', preIndex |
53 return preIndex | |
46 | 54 |
47 # The findPost function is to calculate the index of the next neighbour at a certain metrical level. | 55 # The findPost function is to calculate the index of the next neighbour at a certain metrical level. |
48 def findPost(index, level): | 56 def find_post(index, level): |
49 post_index = (index + 1)%len(H) | 57 postIndex = (index + 1)%len(H) |
50 while(H[post_index] > level): | 58 while(H[postIndex] > level): |
51 post_index = (post_index + 1)%len(H) | 59 postIndex = (postIndex + 1)%len(H) |
52 return post_index | 60 print 'postIndex', postIndex |
61 return postIndex | |
53 | 62 |
54 # The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence | 63 # The dif function is to calculate a difference level factor between two notes (at note position index1 and index 2) in velocity sequence |
55 def dif(index1,index2): | 64 def dif(index1,index2): |
56 parameter_beta = 0.5 | 65 parameterBeta = 0.5 |
57 dif_v = seq[index1]-seq[index2] | 66 dif_v = velocitySequence[index1]-velocitySequence[index2] |
58 dif_h = abs(H[index1]-H[index2]) | 67 dif_h = abs(H[index1]-H[index2]) |
59 dif = dif_v*(parameter_beta*dif_h/4+1-parameter_beta) | 68 dif = dif_v*(parameterBeta*dif_h/4+1-parameterBeta) |
69 print 'dif', dif | |
60 return dif | 70 return dif |
61 | 71 |
62 # 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 | 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 |
63 for l in range(level, max(H)+1): | 73 for l in range(level, max(H)+1): |
64 ave = ( parameter_garma*dif(index,findPre(index,l))+dif(index,findPost(index,l)) )/(1+parameter_garma) | 74 ave = (parameterGarma*dif(index,find_pre(index,l))+dif(index,find_post(index,l)) )/(1+parameterGarma) |
65 averages.append(ave) | 75 averages.append(ave) |
76 print 'averages', averages | |
66 return averages | 77 return averages |
67 | 78 |
68 # Calculate the syncopation value for each note | 79 # Calculate the syncopation value for each note |
69 for index in range(len(seq)): | 80 for index in range(len(velocitySequence)): |
70 if seq[index] != 0: # Onset detected | 81 if velocitySequence[index] != 0: # Onset detected |
71 h = H[index] | 82 h = H[index] |
72 potential = 1 - pow(0.5,h) # Syncopation potential according to its metrical level, which is equal to the metrical weight | 83 # Syncopation potential according to its metrical level, which is equal to the metrical weight |
73 level = h # Metrical weight happens to be equal to its metrical level | 84 potential = 1 - pow(0.5,h) |
74 syncopation += min(aveDif_neighbours(index, h))*potential | 85 level = h # Metrical weight is equal to its metrical level |
86 syncopation += min(ave_dif_neighbours(index, level))*potential | |
75 | 87 |
76 return syncopation | 88 return syncopation |