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)