Mercurial > hg > syncopation-dataset
comparison synpy/music_objects.py @ 72:ef891481231e
reorganising the repo in a major way ready for going public
author | christopherh <christopher.harte@eecs.qmul.ac.uk> |
---|---|
date | Tue, 12 May 2015 08:53:12 +0100 |
parents | Syncopation models/synpy/music_objects.py@9a60ca4ae0fb |
children |
comparison
equal
deleted
inserted
replaced
71:9a60ca4ae0fb | 72:ef891481231e |
---|---|
1 | |
2 from basic_functions import ceiling, string_to_sequence, calculate_bar_ticks, velocity_sequence_to_min_timespan | |
3 import parameter_setter | |
4 import rhythm_parser | |
5 | |
6 class Note(): | |
7 def __init__(self, firstarg = None, duration = None, velocity = None): | |
8 self.startTime = 0 | |
9 self.duration = 0 | |
10 self.velocity = 0 | |
11 | |
12 if firstarg != None: | |
13 if isinstance(firstarg,basestring): | |
14 intlist = string_to_sequence(firstarg,int) | |
15 self.startTime = intlist[0] | |
16 self.duration = intlist[1] | |
17 self.velocity = intlist[2] | |
18 elif isinstance(firstarg,int): | |
19 self.startTime = firstarg | |
20 | |
21 if duration != None: | |
22 self.duration = duration | |
23 if velocity != None: | |
24 self.velocity = velocity | |
25 | |
26 | |
27 def to_string(self): | |
28 return "(%d,%d,%f)" %(self.startTime, self.duration, self.velocity) | |
29 | |
30 | |
31 # NoteSequence is a list of Note | |
32 class NoteSequence(list): | |
33 def __init__(self, noteSequenceString = None): | |
34 if noteSequenceString != None: | |
35 self.string_to_note_sequence(noteSequenceString) | |
36 | |
37 def string_to_note_sequence(self, noteSequenceString): | |
38 noteSequenceString = rhythm_parser.discard_spaces(noteSequenceString) | |
39 # try: | |
40 # Turning "(1,2,3),(4,5,6),(7,8,9)" into ["1,2,3","4,5,6,","7,8,9"] | |
41 listStrings = noteSequenceString[1:-1].split("),(") | |
42 for localString in listStrings: | |
43 self.append(Note(localString)) | |
44 | |
45 def to_string(self): | |
46 noteSequenceString = "" | |
47 for note in self: | |
48 noteSequenceString += note.to_string() + "," | |
49 return noteSequenceString[:-1] | |
50 | |
51 | |
52 class NormalisedVelocityValueOutOfRange(Exception): | |
53 def __init__(self, value): | |
54 self.value = value | |
55 def __str__(self): | |
56 return repr(self.value) | |
57 | |
58 # VelocitySequence is a list of float numbers | |
59 class VelocitySequence(list): | |
60 def __init__(self, velocitySequence = None): | |
61 if velocitySequence != None: | |
62 if isinstance(velocitySequence,basestring): | |
63 self.string_to_velocity_sequence(velocitySequence) | |
64 elif isinstance(velocitySequence, list): | |
65 self+=velocitySequence | |
66 | |
67 def string_to_velocity_sequence(self,inputString): | |
68 | |
69 def convert_velocity_value(argstring): | |
70 value = float(argstring) | |
71 if value>=0 and value<=1: | |
72 return value | |
73 else: | |
74 raise NormalisedVelocityValueOutOfRange("Value: "+argstring+" in " + inputString) | |
75 | |
76 self.extend(string_to_sequence(inputString,convert_velocity_value)) | |
77 | |
78 | |
79 def to_string(self): | |
80 return str(velocity_sequence_to_min_timespan(self))[1:-1].replace(" ","") | |
81 | |
82 | |
83 def velocity_sequence_to_note_sequence(velocitySequence, nextbarVelocitySequence = None): | |
84 | |
85 noteSequence = NoteSequence() | |
86 | |
87 for index in range(len(velocitySequence)): | |
88 if (velocitySequence[index]!= 0): # onset detected | |
89 startTime = index | |
90 velocity = velocitySequence[index] | |
91 | |
92 # if there are previous notes added | |
93 if( len(noteSequence) > 0): | |
94 previousNote = noteSequence[-1] | |
95 previousNote.duration = startTime - previousNote.startTime | |
96 | |
97 # add the current note into note sequence | |
98 noteSequence.append( Note(startTime, 0, velocity) ) | |
99 | |
100 # to set the duration for the last note | |
101 if( len(noteSequence) > 0): | |
102 lastNote = noteSequence[-1] | |
103 | |
104 if nextbarVelocitySequence == None: | |
105 lastNote.duration = len(velocitySequence) - lastNote.startTime | |
106 else: | |
107 nextNoteStartTime = next((index for index, v in enumerate(nextbarVelocitySequence) if v), None) | |
108 lastNote.duration = len(velocitySequence) + nextNoteStartTime-lastNote.startTime | |
109 | |
110 | |
111 return noteSequence | |
112 | |
113 | |
114 def note_sequence_to_velocity_sequence(noteSequence, timespanTicks = None): | |
115 | |
116 velocitySequence = VelocitySequence() | |
117 | |
118 previousNoteStartTime = -1 | |
119 | |
120 for note in noteSequence: | |
121 | |
122 interOnsetInterval = note.startTime - previousNoteStartTime | |
123 #ignore note if it is part of a chord... | |
124 if interOnsetInterval!=0: | |
125 velocitySequence += [0]*(interOnsetInterval-1) | |
126 velocitySequence += [note.velocity] | |
127 | |
128 previousNoteStartTime = note.startTime | |
129 | |
130 if timespanTicks!=None: | |
131 velocitySequence += [0]*(timespanTicks - len(velocitySequence)) | |
132 else: | |
133 velocitySequence += [0]*(noteSequence[-1].duration-1) | |
134 | |
135 # normalising velocity sequence between 0-1 | |
136 if max(velocitySequence)>0: | |
137 velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence]) | |
138 | |
139 return velocitySequence | |
140 | |
141 | |
142 class BarList(list): | |
143 def append(self,bar): | |
144 if(len(self)>0): | |
145 bar.set_previous_bar(self[-1]) | |
146 self[-1].set_next_bar(bar) | |
147 super(BarList, self).append(bar) | |
148 | |
149 def concat(self, barList): | |
150 while(len(barList)!=0): | |
151 localbar = barList[0] | |
152 self.append(localbar) | |
153 barList.remove(localbar) | |
154 | |
155 def to_string(self, sequenceType="y"): | |
156 | |
157 output = "" | |
158 | |
159 for bar in self: | |
160 prev = bar.get_previous_bar() | |
161 | |
162 params = "t"+sequenceType | |
163 | |
164 if prev!=None and prev.get_time_signature()==bar.get_time_signature(): | |
165 params = "-"+params | |
166 | |
167 output += " " + bar.to_string(params) | |
168 | |
169 return output | |
170 | |
171 class Bar: | |
172 def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None): | |
173 if isinstance(rhythmSequence, NoteSequence): | |
174 self.noteSequence = rhythmSequence | |
175 self.velocitySequence = None | |
176 elif isinstance(rhythmSequence, VelocitySequence): | |
177 self.velocitySequence = rhythmSequence | |
178 self.noteSequence = None | |
179 | |
180 if isinstance(timeSignature, basestring): | |
181 self.timeSignature = TimeSignature(timeSignature) | |
182 else: | |
183 self.timeSignature = timeSignature | |
184 | |
185 if ticksPerQuarter==None: | |
186 self.tpq = len(self.get_velocity_sequence())*self.timeSignature.get_denominator()/(4*self.timeSignature.get_numerator()) | |
187 else: | |
188 self.tpq = ticksPerQuarter | |
189 | |
190 self.qpm = qpmTempo | |
191 | |
192 | |
193 | |
194 self.nextBar = nextBar | |
195 self.prevBar = prevBar | |
196 | |
197 def get_note_sequence(self): | |
198 if self.noteSequence == None: | |
199 nextbarVelocitySequence = None | |
200 if self.nextBar != None: | |
201 nextbarVelocitySequence = self.nextBar.get_velocity_sequence() | |
202 self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence) | |
203 return self.noteSequence | |
204 | |
205 def get_velocity_sequence(self): | |
206 if self.velocitySequence == None: | |
207 self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence, self.get_bar_ticks()) | |
208 return self.velocitySequence | |
209 | |
210 def get_binary_sequence(self): | |
211 return ceiling(self.get_velocity_sequence()) | |
212 | |
213 def get_next_bar(self): | |
214 return self.nextBar | |
215 | |
216 def get_previous_bar(self): | |
217 return self.prevBar | |
218 | |
219 def set_next_bar(self, bar): | |
220 self.nextBar = bar | |
221 | |
222 def set_previous_bar(self, bar): | |
223 self.prevBar = bar | |
224 | |
225 def get_subdivision_sequence(self): | |
226 return self.timeSignature.get_subdivision_sequence() | |
227 | |
228 def get_beat_level(self): | |
229 return self.timeSignature.get_beat_level() | |
230 | |
231 def get_time_signature(self): | |
232 return self.timeSignature | |
233 | |
234 # return the length of a bar in time units (ticks) | |
235 def get_bar_ticks(self): | |
236 return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq) | |
237 | |
238 def is_empty(self): | |
239 if max(self.get_velocity_sequence())>0: | |
240 return False | |
241 else: | |
242 return True | |
243 | |
244 def to_string(self, sequenceType="ty"): | |
245 | |
246 # prev = self.get_previous_bar() | |
247 # if prev!=None: | |
248 # if prev.get_time_signature()==self.get_time_signature(): | |
249 # output="" | |
250 output = "" | |
251 | |
252 if "-t" not in sequenceType: | |
253 output = "t{"+self.timeSignature.to_string()+"}" | |
254 | |
255 if "v" in sequenceType: | |
256 output += "v{"+self.get_velocity_sequence().to_string()+"}" | |
257 else: | |
258 output += "y{"+self.get_note_sequence().to_string()+"}" | |
259 | |
260 return output | |
261 | |
262 | |
263 class TimeSignature(): | |
264 def __init__(self, inputString): | |
265 if inputString in parameter_setter.read_time_signature(): | |
266 self.tsString = inputString | |
267 else: | |
268 print "Error: undefined time-signature: ", inputString | |
269 raise NullTimeSignatureError | |
270 | |
271 def get_subdivision_sequence(self): | |
272 return parameter_setter.timeSignatureBase[self.tsString][0] | |
273 | |
274 def get_beat_level(self): | |
275 return parameter_setter.timeSignatureBase[self.tsString][1] | |
276 | |
277 def get_numerator(self): | |
278 return int(self.tsString.split('/')[0]) | |
279 | |
280 def get_denominator(self): | |
281 return int(self.tsString.split('/')[1]) | |
282 | |
283 def to_string(self): | |
284 return self.tsString | |
285 | |
286 |