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 ** Toussaint's Metric Complexity Model **
|
csong@0
|
6
|
csong@0
|
7 Algorithm:
|
csong@0
|
8
|
csong@0
|
9 Only applicable to monorhythms.
|
csong@0
|
10
|
csong@0
|
11 Define metrical hierarchy by given time signature;
|
csong@0
|
12 Calculate how many onsets and determine Maximum Metricality Max_Metric;
|
csong@0
|
13 Calculate the Metrical Simplicity - the weights of all onsets;
|
csong@0
|
14 Syncopation = Max_Metric - Metric_simplicity.
|
csong@0
|
15 Output the predicted syncopation score; -1 indicates non-applicable
|
csong@0
|
16
|
csong@0
|
17 '''
|
csong@0
|
18
|
csong@0
|
19 from MeterStructure import MeterStructure
|
csong@0
|
20
|
csong@0
|
21 def metricalModel(rhythm, time_sig, category, bar):
|
csong@0
|
22 ms = MeterStructure(time_sig)
|
csong@0
|
23 meter = ms.getLJWeights(bar)
|
csong@0
|
24 if len(meter) !=0:
|
csong@0
|
25
|
csong@0
|
26 metricalSimplicity = 0 # sum of weights of onsets per bar
|
csong@0
|
27 maxMetrical = 0 # maximum metricity per bar
|
csong@0
|
28 onsetCount = 0 # The number of onsets per bar
|
csong@0
|
29
|
csong@0
|
30 if 'poly' in category: # not applicable to polyrhythms
|
csong@0
|
31 return -1
|
csong@0
|
32
|
csong@0
|
33 # Calculate metricalSimplicity
|
csong@0
|
34 else:
|
csong@0
|
35 l = len(rhythm)
|
csong@0
|
36 for i in range(l):
|
csong@0
|
37 if rhythm[i] == 1: # onset detected
|
csong@0
|
38 pos = int((float(i)/l) *len(meter)) # looking for the metrical position where this note locates
|
csong@0
|
39 metricalSimplicity = metricalSimplicity+meter[pos]
|
csong@0
|
40 onsetCount = onsetCount+1
|
csong@0
|
41
|
csong@0
|
42 # Calculate max metricity
|
csong@0
|
43 meter.sort(reverse=True)
|
csong@0
|
44 for i in range(0,onsetCount):
|
csong@0
|
45 maxMetrical = maxMetrical+meter[i]
|
csong@0
|
46
|
csong@0
|
47 #print 'test', onsetCount, maxMetrical, metricalSimplicity
|
csong@0
|
48 syncopation = (maxMetrical - metricalSimplicity)
|
csong@0
|
49
|
csong@0
|
50 return syncopation
|
csong@0
|
51 else:
|
csong@0
|
52 return -1
|
csong@0
|
53
|
csong@0
|
54 # Retrieve the stimuli
|
csong@0
|
55 f = file('stimuli.txt')
|
csong@0
|
56 #f = file('stimuli_34only.txt')
|
csong@0
|
57
|
csong@0
|
58 #Calculate syncopation for each rhythm pattern
|
csong@0
|
59 while True:
|
csong@0
|
60 line = f.readline().split(';')
|
csong@0
|
61 if len(line) == 1:
|
csong@0
|
62 break
|
csong@0
|
63 else:
|
csong@0
|
64 sti_name = line[0]
|
csong@0
|
65 rhythmString = line[1].split()
|
csong@0
|
66 time_sig = line[2]
|
csong@0
|
67 category = line[3]
|
csong@0
|
68 bar = int(line[4])
|
csong@0
|
69
|
csong@0
|
70 rhythm = map(int,rhythmString[0].split(','))
|
csong@0
|
71
|
csong@0
|
72 print sti_name, metricalModel(rhythm, time_sig, category, bar)
|