Mercurial > hg > syncopation-dataset
comparison Syncopation models/WNBD.py @ 0:76ce27beba95
Have uploaded the syncopation dataset and audio wavefies.
author | Chunyang Song <csong@eecs.qmul.ac.uk> |
---|---|
date | Fri, 21 Mar 2014 15:49:46 +0000 |
parents | |
children | b2da092dc2e0 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:76ce27beba95 |
---|---|
1 ''' | |
2 Author: Chunyang Song | |
3 Institution: Centre for Digital Music, Queen Mary University of London | |
4 | |
5 ** Weighted Note-to-Beat Distance Model (WNBD) ** | |
6 | |
7 Algorithm: | |
8 | |
9 Calculate the distance (d) of onset to the nearest strong beat; | |
10 Calculate the WNBD measure (w) of each onset; | |
11 Syncopation is the sum of WNBD measures divided by the number of onsets. | |
12 | |
13 ''' | |
14 | |
15 from MeterStructure import MeterStructure | |
16 | |
17 def WNBD(rhythm, time_sig, category, bar): | |
18 | |
19 ms = MeterStructure(time_sig) | |
20 beat = ms.getBeats(bar) + [len(rhythm)] # the "beat" array include all "strong-beat" positions across all bars, and the downbeat position of the following bar | |
21 if len(beat)!=0: | |
22 unit = beat[1]-beat[0] # how many digits to represent the length of one beat | |
23 | |
24 onsetPos = [] # The onset positions | |
25 d = [] # The distances of each onset to its nearest strong beat | |
26 beatToLeft = [] # The beat indexes of the beats that are to the left of or coincide with each onset | |
27 wnbdMeasures = [] # the un-normalized measures of wnbd | |
28 | |
29 # Calculate the distance of each onset to the nearest strong beat | |
30 l = len(rhythm) | |
31 for i in range(l): | |
32 if rhythm[i] == 1: # onset detected | |
33 onsetPos.append(i) | |
34 | |
35 # find its distance to the nearest strong beat | |
36 for j in range(len(beat)-1): | |
37 if beat[j]<= i < beat[j+1]: | |
38 d1 = abs(i-beat[j]) | |
39 d2 = abs(i-beat[j+1]) | |
40 d.append( min(d1,d2)/float(unit) ) # Normalize the distance to beat-level | |
41 beatToLeft.append(j) | |
42 else: | |
43 continue | |
44 | |
45 #Calculate the WNBD measure of each onset | |
46 n = len(onsetPos) | |
47 for i in range(n): | |
48 if d[i] ==0: # If on-beat, measure is 0 | |
49 wnbdMeasures.append(0) | |
50 else: | |
51 if i == n-1: # The last note, then | |
52 if beatToLeft[i] == beat[-3]/unit: # if the last note has more than 1- but less than 2-beat distance to the next bar | |
53 wnbdMeasures.append(2.0/d[i]) # measure is 2/d, else 1/d | |
54 else: | |
55 wnbdMeasures.append(1.0/d[i]) | |
56 | |
57 else: # if its not the last note | |
58 if beatToLeft[i+1] == beatToLeft[i] or (beatToLeft[i+1]-beatToLeft[i]==1 and d[i+1]==0): # if this note is no more than 1-beat distance away from the next note | |
59 wnbdMeasures.append(1.0/d[i]) | |
60 elif beatToLeft[i+1] - beatToLeft[i] == 1 or (beatToLeft[i+1]-beatToLeft[i]==2 and d[i+1]==0): # if this note is no more than 2-beat distance away from the next | |
61 wnbdMeasures.append(2.0/d[i]) | |
62 else: # if the note is more than 2-beat distance away from the next note | |
63 wnbdMeasures.append(1.0/d[i]) | |
64 | |
65 syncopation = sum(wnbdMeasures)/float(n) | |
66 return syncopation | |
67 | |
68 else: | |
69 return -1 | |
70 | |
71 | |
72 # Retrieve the stimuli | |
73 f = file('stimuli.txt') | |
74 #f = file('stimuli_34only.txt') | |
75 | |
76 #Calculate syncopation for each rhythm pattern | |
77 while True: | |
78 line = f.readline().split(';') | |
79 if len(line) == 1: | |
80 break | |
81 else: | |
82 sti_name = line[0] | |
83 rhythmString = line[1].split() | |
84 time_sig = line[2] | |
85 category = line[3] | |
86 bar = int(line[4]) | |
87 | |
88 rhythm = map(int,rhythmString[0].split(',')) | |
89 | |
90 print sti_name, WNBD(rhythm, time_sig, category, bar) |