Mercurial > hg > syncopation-dataset
comparison Syncopation models/synpy/music_objects.py @ 45:6e9154fc58df
moving the code files to the synpy package directory
author | christopherh <christopher.harte@eecs.qmul.ac.uk> |
---|---|
date | Thu, 23 Apr 2015 23:52:04 +0100 |
parents | |
children | e71028851131 |
comparison
equal
deleted
inserted
replaced
44:144460f34b5e | 45:6e9154fc58df |
---|---|
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 velocitySequence += [0]*(interOnsetInterval-1) | |
124 velocitySequence += [note.velocity] | |
125 | |
126 previousNoteStartTime = note.startTime | |
127 | |
128 if timespanTicks!=None: | |
129 velocitySequence += [0]*(timespanTicks - len(velocitySequence)) | |
130 else: | |
131 velocitySequence += [0]*(noteSequence[-1].duration-1) | |
132 | |
133 # normalising velocity sequence between 0-1 | |
134 if max(velocitySequence)>0: | |
135 velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence]) | |
136 | |
137 return velocitySequence | |
138 | |
139 | |
140 class BarList(list): | |
141 def append(self,bar): | |
142 if(len(self)>0): | |
143 bar.set_previous_bar(self[-1]) | |
144 self[-1].set_next_bar(bar) | |
145 super(BarList, self).append(bar) | |
146 | |
147 def concat(self, barList): | |
148 while(len(barList)!=0): | |
149 localbar = barList[0] | |
150 self.append(localbar) | |
151 barList.remove(localbar) | |
152 | |
153 | |
154 class Bar: | |
155 def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None): | |
156 if isinstance(rhythmSequence, NoteSequence): | |
157 self.noteSequence = rhythmSequence | |
158 self.velocitySequence = None | |
159 elif isinstance(rhythmSequence, VelocitySequence): | |
160 self.velocitySequence = rhythmSequence | |
161 self.noteSequence = None | |
162 | |
163 self.tpq = ticksPerQuarter | |
164 self.qpm = qpmTempo | |
165 if isinstance(timeSignature, basestring): | |
166 self.timeSignature = TimeSignature(timeSignature) | |
167 else: | |
168 self.timeSignature = timeSignature | |
169 self.nextBar = nextBar | |
170 self.prevBar = prevBar | |
171 | |
172 def get_note_sequence(self): | |
173 if self.noteSequence == None: | |
174 nextbarVelocitySequence = None | |
175 if self.nextBar != None: | |
176 nextbarVelocitySequence = self.nextBar.get_velocity_sequence() | |
177 self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence) | |
178 return self.noteSequence | |
179 | |
180 def get_velocity_sequence(self): | |
181 if self.velocitySequence == None: | |
182 self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence, self.get_bar_ticks()) | |
183 return self.velocitySequence | |
184 | |
185 def get_binary_sequence(self): | |
186 return ceiling(self.get_velocity_sequence()) | |
187 | |
188 def get_next_bar(self): | |
189 return self.nextBar | |
190 | |
191 def get_previous_bar(self): | |
192 return self.prevBar | |
193 | |
194 def set_next_bar(self, bar): | |
195 self.nextBar = bar | |
196 | |
197 def set_previous_bar(self, bar): | |
198 self.prevBar = bar | |
199 | |
200 def get_subdivision_sequence(self): | |
201 return self.timeSignature.get_subdivision_sequence() | |
202 | |
203 def get_beat_level(self): | |
204 return self.timeSignature.get_beat_level() | |
205 | |
206 def get_time_signature(self): | |
207 return self.timeSignature | |
208 | |
209 # return the length of a bar in time units (ticks) | |
210 def get_bar_ticks(self): | |
211 return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq) | |
212 | |
213 def is_empty(self): | |
214 if max(self.get_velocity_sequence())>0: | |
215 return False | |
216 else: | |
217 return True | |
218 | |
219 def to_string(self, sequenceType=None): | |
220 output = "t{"+self.timeSignature.to_string()+"}" | |
221 prev = self.get_previous_bar() | |
222 if prev!=None: | |
223 if prev.get_time_signature()==self.get_time_signature(): | |
224 output="" | |
225 | |
226 if sequenceType==None or sequenceType=="v": | |
227 output += "v{"+self.get_velocity_sequence().to_string()+"}" | |
228 else: | |
229 output += "y{"+self.get_note_sequence().to_string()+"}" | |
230 return output | |
231 | |
232 | |
233 class TimeSignature(): | |
234 def __init__(self, inputString): | |
235 if inputString in parameter_setter.read_time_signature(): | |
236 self.tsString = inputString | |
237 else: | |
238 print "Error: undefined time-signature: ", inputString | |
239 raise NullTimeSignatureError | |
240 | |
241 def get_subdivision_sequence(self): | |
242 return parameter_setter.timeSignatureBase[self.tsString][0] | |
243 | |
244 def get_beat_level(self): | |
245 return parameter_setter.timeSignatureBase[self.tsString][1] | |
246 | |
247 def get_numerator(self): | |
248 return int(self.tsString.split('/')[0]) | |
249 | |
250 def get_denominator(self): | |
251 return int(self.tsString.split('/')[1]) | |
252 | |
253 def to_string(self): | |
254 return self.tsString | |
255 | |
256 |