csong@9
|
1
|
christopher@29
|
2 from basic_functions import ceiling, string_to_sequence, calculate_bar_ticks, velocity_sequence_to_min_timespan
|
csong@13
|
3 import parameter_setter
|
csong@13
|
4 import rhythm_parser
|
csong@9
|
5
|
csong@9
|
6 class Note():
|
csong@22
|
7 def __init__(self, firstarg = None, duration = None, velocity = None):
|
csong@22
|
8 self.startTime = 0
|
csong@22
|
9 self.duration = 0
|
csong@22
|
10 self.velocity = 0
|
csong@22
|
11
|
csong@22
|
12 if firstarg != None:
|
csong@22
|
13 if isinstance(firstarg,basestring):
|
csong@22
|
14 intlist = string_to_sequence(firstarg)
|
csong@22
|
15 self.startTime = intlist[0]
|
csong@22
|
16 self.duration = intlist[1]
|
csong@22
|
17 self.velocity = intlist[2]
|
csong@22
|
18 elif isinstance(firstarg,int):
|
csong@22
|
19 self.startTime = firstarg
|
csong@22
|
20
|
csong@22
|
21 if duration != None:
|
csong@22
|
22 self.duration = duration
|
csong@22
|
23 if velocity != None:
|
csong@22
|
24 self.velocity = velocity
|
csong@22
|
25
|
csong@22
|
26
|
csong@22
|
27 def to_string(self):
|
csong@22
|
28 return "(%d,%d,%f)" %(self.startTime, self.duration, self.velocity)
|
csong@22
|
29
|
csong@9
|
30
|
csong@9
|
31 # NoteSequence is a list of Note
|
csong@9
|
32 class NoteSequence(list):
|
csong@22
|
33 def __init__(self, noteSequenceString = None):
|
csong@22
|
34 if noteSequenceString != None:
|
csong@9
|
35 self.string_to_note_sequence(noteSequenceString)
|
csong@9
|
36
|
csong@9
|
37 def string_to_note_sequence(self, noteSequenceString):
|
christopher@29
|
38 noteSequenceString = rhythm_parser.discard_spaces(noteSequenceString)
|
csong@9
|
39 # try:
|
csong@9
|
40 # Turning "(1,2,3),(4,5,6),(7,8,9)" into ["1,2,3","4,5,6,","7,8,9"]
|
csong@9
|
41 listStrings = noteSequenceString[1:-1].split("),(")
|
csong@9
|
42 for localString in listStrings:
|
csong@9
|
43 self.append(Note(localString))
|
csong@9
|
44
|
csong@22
|
45 def to_string(self):
|
csong@22
|
46 noteSequenceString = ""
|
csong@22
|
47 for note in self:
|
csong@22
|
48 noteSequenceString += note.to_string() + ","
|
csong@22
|
49 return noteSequenceString[:-1]
|
csong@9
|
50
|
csong@22
|
51 # VelocitySequence is a list of float numbers
|
csong@22
|
52 class VelocitySequence(list):
|
christopher@29
|
53 def __init__(self, velocitySequence = None):
|
christopher@29
|
54 if velocitySequence != None:
|
christopher@29
|
55 if isinstance(velocitySequence,basestring):
|
christopher@29
|
56 self.string_to_velocity_sequence(velocitySequence)
|
christopher@29
|
57 elif isinstance(velocitySequence, list):
|
christopher@29
|
58 self+=velocitySequence
|
csong@9
|
59
|
csong@22
|
60 def string_to_velocity_sequence(self,inputString):
|
csong@22
|
61 self.extend(string_to_sequence(inputString))
|
csong@9
|
62
|
csong@22
|
63 def to_string(self):
|
christopher@29
|
64 return str(velocity_sequence_to_min_timespan(self))[1:-1].replace(" ","")
|
csong@22
|
65
|
csong@22
|
66
|
csong@23
|
67 def velocity_sequence_to_note_sequence(velocitySequence, nextbarVelocitySequence = None):
|
csong@22
|
68
|
csong@22
|
69 noteSequence = NoteSequence()
|
csong@22
|
70
|
csong@22
|
71 for index in range(len(velocitySequence)):
|
csong@22
|
72 if (velocitySequence[index]!= 0): # onset detected
|
csong@22
|
73 startTime = index
|
csong@22
|
74 velocity = velocitySequence[index]
|
csong@22
|
75
|
csong@22
|
76 # if there are previous notes added
|
csong@22
|
77 if( len(noteSequence) > 0):
|
csong@22
|
78 previousNote = noteSequence[-1]
|
csong@22
|
79 previousNote.duration = startTime - previousNote.startTime
|
csong@22
|
80
|
csong@22
|
81 # add the current note into note sequence
|
csong@22
|
82 noteSequence.append( Note(startTime, 0, velocity) )
|
csong@22
|
83
|
csong@22
|
84 # to set the duration for the last note
|
csong@22
|
85 if( len(noteSequence) > 0):
|
csong@23
|
86 lastNote = noteSequence[-1]
|
csong@23
|
87
|
csong@23
|
88 if nextbarVelocitySequence == None:
|
csong@23
|
89 lastNote.duration = len(velocitySequence) - lastNote.startTime
|
csong@23
|
90 else:
|
csong@23
|
91 nextNoteStartTime = next((index for index, v in enumerate(nextbarVelocitySequence) if v), None)
|
csong@23
|
92 lastNote.duration = len(velocitySequence) + nextNoteStartTime-lastNote.startTime
|
csong@23
|
93
|
csong@22
|
94
|
csong@22
|
95 return noteSequence
|
csong@22
|
96
|
csong@22
|
97
|
csong@22
|
98 def note_sequence_to_velocity_sequence(noteSequence, timespanTicks = None):
|
csong@22
|
99
|
csong@22
|
100 velocitySequence = VelocitySequence()
|
csong@22
|
101
|
csong@22
|
102 previousNoteStartTime = -1
|
csong@22
|
103
|
csong@22
|
104 for note in noteSequence:
|
csong@22
|
105
|
csong@22
|
106 interOnsetInterval = note.startTime - previousNoteStartTime
|
csong@22
|
107 velocitySequence += [0]*(interOnsetInterval-1)
|
csong@22
|
108 velocitySequence += [note.velocity]
|
csong@22
|
109
|
csong@22
|
110 previousNoteStartTime = note.startTime
|
csong@22
|
111
|
csong@22
|
112 if timespanTicks!=None:
|
csong@22
|
113 velocitySequence += [0]*(timespanTicks - len(velocitySequence))
|
csong@22
|
114 else:
|
csong@22
|
115 velocitySequence += [0]*(noteSequence[-1].duration-1)
|
csong@22
|
116
|
csong@22
|
117 # normalising velocity sequence between 0-1
|
christopher@38
|
118 if max(velocitySequence)>0:
|
christopher@38
|
119 velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence])
|
csong@22
|
120
|
csong@22
|
121 return velocitySequence
|
csong@9
|
122
|
csong@9
|
123
|
csong@9
|
124 class BarList(list):
|
csong@9
|
125 def append(self,bar):
|
csong@9
|
126 if(len(self)>0):
|
csong@9
|
127 bar.set_previous_bar(self[-1])
|
csong@9
|
128 self[-1].set_next_bar(bar)
|
csong@9
|
129 super(BarList, self).append(bar)
|
csong@9
|
130
|
christopher@29
|
131 def concat(self, barList):
|
christopher@29
|
132 while(len(barList)!=0):
|
christopher@29
|
133 localbar = barList[0]
|
christopher@29
|
134 self.append(localbar)
|
christopher@29
|
135 barList.remove(localbar)
|
christopher@29
|
136
|
csong@9
|
137
|
csong@9
|
138 class Bar:
|
csong@9
|
139 def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None):
|
csong@9
|
140 if isinstance(rhythmSequence, NoteSequence):
|
csong@9
|
141 self.noteSequence = rhythmSequence
|
csong@9
|
142 self.velocitySequence = None
|
csong@9
|
143 elif isinstance(rhythmSequence, VelocitySequence):
|
csong@9
|
144 self.velocitySequence = rhythmSequence
|
csong@9
|
145 self.noteSequence = None
|
csong@9
|
146
|
csong@9
|
147 self.tpq = ticksPerQuarter
|
csong@9
|
148 self.qpm = qpmTempo
|
christopher@30
|
149 if isinstance(timeSignature, basestring):
|
christopher@30
|
150 self.timeSignature = TimeSignature(timeSignature)
|
christopher@30
|
151 else:
|
christopher@30
|
152 self.timeSignature = timeSignature
|
csong@9
|
153 self.nextBar = nextBar
|
csong@9
|
154 self.prevBar = prevBar
|
csong@9
|
155
|
csong@9
|
156 def get_note_sequence(self):
|
csong@22
|
157 if self.noteSequence == None:
|
csong@23
|
158 nextbarVelocitySequence = None
|
csong@23
|
159 if self.nextBar != None:
|
csong@23
|
160 nextbarVelocitySequence = self.nextBar.get_velocity_sequence()
|
csong@23
|
161 self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence)
|
csong@9
|
162 return self.noteSequence
|
csong@9
|
163
|
csong@9
|
164 def get_velocity_sequence(self):
|
csong@22
|
165 if self.velocitySequence == None:
|
christopher@38
|
166 self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence, self.get_bar_ticks())
|
csong@9
|
167 return self.velocitySequence
|
csong@9
|
168
|
csong@9
|
169 def get_binary_sequence(self):
|
csong@9
|
170 return ceiling(self.get_velocity_sequence())
|
csong@9
|
171
|
csong@9
|
172 def get_next_bar(self):
|
csong@9
|
173 return self.nextBar
|
csong@9
|
174
|
csong@9
|
175 def get_previous_bar(self):
|
csong@9
|
176 return self.prevBar
|
csong@9
|
177
|
csong@9
|
178 def set_next_bar(self, bar):
|
csong@9
|
179 self.nextBar = bar
|
csong@9
|
180
|
csong@9
|
181 def set_previous_bar(self, bar):
|
csong@9
|
182 self.prevBar = bar
|
csong@9
|
183
|
csong@9
|
184 def get_subdivision_sequence(self):
|
csong@18
|
185 return self.timeSignature.get_subdivision_sequence()
|
csong@9
|
186
|
csong@9
|
187 def get_beat_level(self):
|
csong@20
|
188 return self.timeSignature.get_beat_level()
|
csong@9
|
189
|
csong@9
|
190 def get_time_signature(self):
|
csong@9
|
191 return self.timeSignature
|
csong@9
|
192
|
csong@21
|
193 # return the length of a bar in time units (ticks)
|
csong@22
|
194 def get_bar_ticks(self):
|
csong@23
|
195 return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq)
|
csong@22
|
196
|
christopher@38
|
197 def is_empty(self):
|
christopher@38
|
198 if max(self.get_velocity_sequence())>0:
|
christopher@38
|
199 return False
|
christopher@38
|
200 else:
|
christopher@38
|
201 return True
|
christopher@38
|
202
|
christopher@29
|
203 def to_string(self, sequenceType=None):
|
christopher@38
|
204 output = "t{"+self.timeSignature.to_string()+"}"
|
christopher@38
|
205 prev = self.get_previous_bar()
|
christopher@38
|
206 if prev!=None:
|
christopher@38
|
207 if prev.get_time_signature()==self.get_time_signature():
|
christopher@38
|
208 output=""
|
christopher@38
|
209
|
christopher@29
|
210 if sequenceType==None or sequenceType=="v":
|
christopher@38
|
211 output += "v{"+self.get_velocity_sequence().to_string()+"}"
|
christopher@29
|
212 else:
|
christopher@38
|
213 output += "y{"+self.get_note_sequence().to_string()+"}"
|
christopher@29
|
214 return output
|
christopher@29
|
215
|
csong@9
|
216
|
csong@18
|
217 class TimeSignature():
|
csong@18
|
218 def __init__(self, inputString):
|
csong@20
|
219 if inputString in parameter_setter.read_time_signature():
|
csong@18
|
220 self.tsString = inputString
|
csong@18
|
221 else:
|
csong@35
|
222 print "Error: undefined time-signature: ", inputString
|
csong@18
|
223 raise NullTimeSignatureError
|
csong@18
|
224
|
csong@18
|
225 def get_subdivision_sequence(self):
|
csong@20
|
226 return parameter_setter.timeSignatureBase[self.tsString][0]
|
csong@18
|
227
|
csong@18
|
228 def get_beat_level(self):
|
csong@20
|
229 return parameter_setter.timeSignatureBase[self.tsString][1]
|
csong@18
|
230
|
csong@18
|
231 def get_numerator(self):
|
csong@18
|
232 return int(self.tsString.split('/')[0])
|
csong@18
|
233
|
csong@18
|
234 def get_denominator(self):
|
csong@18
|
235 return int(self.tsString.split('/')[1])
|
csong@18
|
236
|
christopher@24
|
237 def to_string(self):
|
christopher@24
|
238 return self.tsString
|
csong@18
|
239
|
csong@18
|
240
|