csong@2
|
1 # This python file is a collection of basic functions that are used in the syncopation models.
|
csong@2
|
2
|
csong@2
|
3 import math
|
csong@2
|
4
|
csong@2
|
5 # The concatenation function is used to concatenate two sequences.
|
csong@2
|
6 def concatenate(seq1,seq2):
|
csong@2
|
7 return seq1+seq2
|
csong@2
|
8
|
csong@2
|
9 # The repetition function is to concatenate a sequence to itself for 'times' number of times.
|
csong@2
|
10 def repeat(seq,times):
|
csong@2
|
11 new_seq = list(seq)
|
csong@2
|
12 if times >= 1:
|
csong@2
|
13 for i in range(times-1):
|
csong@2
|
14 new_seq = concatenate(new_seq,seq)
|
csong@2
|
15 else:
|
csong@2
|
16 #print 'Error: repetition times needs to be no less than 1.'
|
csong@2
|
17 new_seq = []
|
csong@2
|
18 return new_seq
|
csong@2
|
19
|
csong@2
|
20 # The subdivision function is to equally subdivide a sequence into 'divisor' number of segments.
|
csong@2
|
21 def subdivide(seq,divisor):
|
csong@2
|
22 subSeq = []
|
csong@2
|
23 if len(seq) % divisor != 0:
|
csong@2
|
24 print 'Error: rhythmic sequence cannot be equally subdivided.'
|
csong@2
|
25 else:
|
csong@2
|
26 n = len(seq) / divisor
|
csong@2
|
27 start , end = 0, n
|
csong@2
|
28 for i in range(divisor):
|
csong@2
|
29 subSeq.append(seq[start : end])
|
csong@2
|
30 start = end
|
csong@2
|
31 end = end + n
|
csong@2
|
32 return subSeq
|
csong@2
|
33
|
csong@2
|
34
|
csong@2
|
35 # The ceiling function is to round each number inside a sequence up to its nearest integer.
|
csong@2
|
36 def ceiling(seq):
|
csong@2
|
37 seq_ceil = []
|
csong@2
|
38 for s in seq:
|
csong@2
|
39 seq_ceil.append(int(math.ceil(s)))
|
csong@2
|
40 return seq_ceil
|
csong@2
|
41
|
csong@2
|
42 # The find_divisor function returns a list of all possible divisors for a length of sequence.
|
csong@2
|
43 def find_divisor(number):
|
csong@2
|
44 divisors = [1]
|
csong@2
|
45 for i in range(2,number+1):
|
csong@2
|
46 if number%i ==0:
|
csong@2
|
47 divisors.append(i)
|
csong@2
|
48 return divisors
|
csong@2
|
49
|
csong@2
|
50 # The find_divisor function returns a list of all possible divisors for a length of sequence.
|
csong@2
|
51 def find_prime_factors(number):
|
csong@2
|
52 prime_factors = find_divisor(number)
|
csong@2
|
53
|
csong@2
|
54 def is_prime(num):
|
csong@2
|
55 if num < 2:
|
csong@2
|
56 return False
|
csong@2
|
57 if num == 2:
|
csong@2
|
58 return True
|
csong@2
|
59 else:
|
csong@2
|
60 for div in range(2,num):
|
csong@2
|
61 if num % div == 0:
|
csong@2
|
62 return False
|
csong@2
|
63 return True
|
csong@2
|
64
|
csong@2
|
65 for i in range(len(prime_factors)-1,0,-1):
|
csong@2
|
66 if is_prime(prime_factors[i]) == False:
|
csong@2
|
67 del prime_factors[i]
|
csong@2
|
68
|
csong@2
|
69 return prime_factors
|
csong@2
|
70
|
csong@2
|
71 # The min_timeSpan function searches for the shortest possible time-span representation for a sequence.
|
csong@2
|
72 def get_min_timeSpan(seq):
|
csong@2
|
73 min_ts = [1]
|
csong@2
|
74 for d in find_divisor(len(seq)):
|
csong@2
|
75 segments = subdivide(seq,d)
|
csong@2
|
76 if len(segments)!=0:
|
csong@2
|
77 del min_ts[:]
|
csong@2
|
78 for s in segments:
|
csong@2
|
79 min_ts.append(s[0])
|
csong@2
|
80 if sum(min_ts) == sum(seq):
|
csong@2
|
81 break
|
csong@2
|
82 return min_ts
|
csong@2
|
83
|
csong@2
|
84 # get_note_indices returns all the indices of all the notes in this sequence
|
csong@2
|
85 def get_note_indices(seq):
|
csong@2
|
86 note_indices = []
|
csong@2
|
87
|
csong@2
|
88 for index in range(len(seq)):
|
csong@2
|
89 if seq[index] != 0:
|
csong@2
|
90 note_indices.append(index)
|
csong@2
|
91
|
csong@2
|
92 return note_indices
|
csong@2
|
93
|
csong@2
|
94 # The get_H returns a sequence of metrical weight for a certain metrical level (horizontal),
|
csong@2
|
95 # given the sequence of metrical weights in a hierarchy (vertical) and a sequence of subdivisions.
|
csong@2
|
96 def get_H(weight_seq,subdivision_seq, level):
|
csong@2
|
97 H = []
|
csong@2
|
98 #print len(weight_seq), len(subdivision_seq), level
|
csong@2
|
99 if (level <= len(subdivision_seq)-1) & (level <= len(weight_seq)-1):
|
csong@2
|
100 if level == 0:
|
csong@2
|
101 H = repeat([weight_seq[0]],subdivision_seq[0])
|
csong@2
|
102 else:
|
csong@2
|
103 H_pre = get_H(weight_seq,subdivision_seq,level-1)
|
csong@2
|
104 for h in H_pre:
|
csong@2
|
105 H = concatenate(H, concatenate([h], repeat([weight_seq[level]],subdivision_seq[level]-1)))
|
csong@2
|
106 else:
|
csong@2
|
107 print 'Error: a subdivision factor or metrical weight is not defined for the request metrical level.'
|
csong@2
|
108 return H
|
csong@2
|
109
|
csong@2
|
110 # The get_subdivision_seq function returns the subdivision sequence of several common time-signatures defined by GTTM,
|
csong@2
|
111 # or ask for the top three level of subdivision_seq manually set by the user.
|
csong@2
|
112 def get_subdivision_seq(timesig, L_max):
|
csong@2
|
113 subdivision_seq = []
|
csong@2
|
114
|
csong@2
|
115 if timesig == '2/4' or timesig == '4/4':
|
csong@2
|
116 subdivision_seq = [1,2,2]
|
csong@2
|
117 elif timesig == '3/4' or timesig == '3/8':
|
csong@2
|
118 subdivision_seq = [1,3,2]
|
csong@2
|
119 elif timesig == '6/8':
|
csong@2
|
120 subdivision_seq = [1,2,3]
|
csong@2
|
121 elif timesig == '9/8':
|
csong@2
|
122 subdivision_seq = [1,3,3]
|
csong@2
|
123 elif timesig == '12/8':
|
csong@2
|
124 subdivision_seq = [1,4,3]
|
csong@2
|
125 elif timesig == '5/4' or timesig == '5/8':
|
csong@2
|
126 subdivision_seq = [1,5,2]
|
csong@2
|
127 elif timesig == '7/4' or timesig == '7/8':
|
csong@2
|
128 subdivision_seq = [1,7,2]
|
csong@2
|
129 elif timesig == '11/4' or timesig == '11/8':
|
csong@2
|
130 subdivision_seq = [1,11,2]
|
csong@2
|
131 else:
|
csong@2
|
132 print 'Time-signature',timesig,'is undefined. Please indicate subdivision sequence for this requested time-signature, e.g. [1,2,2] for 4/4 meter.'
|
csong@2
|
133 for i in range(3):
|
csong@2
|
134 s = int(input('Enter the subdivision factor at metrical level '+str(i)+':'))
|
csong@2
|
135 subdivision_seq.append(s)
|
csong@2
|
136
|
csong@2
|
137 if L_max > 2:
|
csong@2
|
138 subdivision_seq = subdivision_seq + [2]*(L_max-2)
|
csong@2
|
139 else:
|
csong@2
|
140 subdivision_seq = subdivision_seq[0:L_max+1]
|
csong@2
|
141
|
csong@2
|
142 return subdivision_seq
|
csong@2
|
143
|
csong@9
|
144
|
csong@9
|
145 def get_rhythm_category(sequence, subdivision_seq):
|
csong@9
|
146 rhythm_category = 'mono'
|
csong@9
|
147 for f in find_prime_factors(len(get_min_timeSpan(sequence))):
|
csong@9
|
148 if not (f in subdivision_seq):
|
csong@9
|
149 rhythm_category = 'poly'
|
csong@9
|
150 break
|
csong@9
|
151 return rhythm_category
|
csong@9
|
152
|
csong@9
|
153
|
csong@2
|
154 # The split_by_bar function seperates the score representation of rhythm by bar lines,
|
csong@2
|
155 # resulting in a list representingbar-by-bar rhythm sequence,
|
csong@2
|
156 # e.g. rhythm = ['|',[ts1,td1,v1], [ts2,td2,v2], '|',[ts3,td3,v3],'|'...]
|
csong@2
|
157 # rhythm_bybar = [ [ [ts1,td1,v1], [ts2,td2,v2] ], [ [ts3,td3,v3] ], [...]]
|
csong@2
|
158 # def split_by_bar(rhythm):
|
csong@2
|
159 # rhythm_bybar = []
|
csong@2
|
160 # bar_index = []
|
csong@2
|
161 # for index in range(len(rhythm)):
|
csong@2
|
162 # if rhythm[index] == '|':
|
csong@2
|
163
|
csong@2
|
164 # return rhythm_bybar
|
csong@2
|
165
|
csong@2
|
166 # def yseq_to_vseq(yseq):
|
csong@2
|
167 # vseq = []
|
csong@2
|
168
|
csong@2
|
169 # return vseq
|
csong@2
|
170
|
csong@2
|
171
|
csong@2
|
172 # # testing
|
csong@2
|
173 # print find_prime_factors(10) |