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@29
|
118 velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence])
|
csong@22
|
119
|
csong@22
|
120 return velocitySequence
|
csong@9
|
121
|
csong@9
|
122
|
csong@9
|
123 class BarList(list):
|
csong@9
|
124 def append(self,bar):
|
csong@9
|
125 if(len(self)>0):
|
csong@9
|
126 bar.set_previous_bar(self[-1])
|
csong@9
|
127 self[-1].set_next_bar(bar)
|
csong@9
|
128 super(BarList, self).append(bar)
|
csong@9
|
129
|
christopher@29
|
130 def concat(self, barList):
|
christopher@29
|
131 while(len(barList)!=0):
|
christopher@29
|
132 localbar = barList[0]
|
christopher@29
|
133 self.append(localbar)
|
christopher@29
|
134 barList.remove(localbar)
|
christopher@29
|
135
|
csong@9
|
136
|
csong@9
|
137 class Bar:
|
csong@9
|
138 def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None):
|
csong@9
|
139 if isinstance(rhythmSequence, NoteSequence):
|
csong@9
|
140 self.noteSequence = rhythmSequence
|
csong@9
|
141 self.velocitySequence = None
|
csong@9
|
142 elif isinstance(rhythmSequence, VelocitySequence):
|
csong@9
|
143 self.velocitySequence = rhythmSequence
|
csong@9
|
144 self.noteSequence = None
|
csong@9
|
145
|
csong@9
|
146 self.tpq = ticksPerQuarter
|
csong@9
|
147 self.qpm = qpmTempo
|
christopher@30
|
148 if isinstance(timeSignature, basestring):
|
christopher@30
|
149 self.timeSignature = TimeSignature(timeSignature)
|
christopher@30
|
150 else:
|
christopher@30
|
151 self.timeSignature = timeSignature
|
csong@9
|
152 self.nextBar = nextBar
|
csong@9
|
153 self.prevBar = prevBar
|
csong@9
|
154
|
csong@9
|
155 def get_note_sequence(self):
|
csong@22
|
156 if self.noteSequence == None:
|
csong@23
|
157 nextbarVelocitySequence = None
|
csong@23
|
158 if self.nextBar != None:
|
csong@23
|
159 nextbarVelocitySequence = self.nextBar.get_velocity_sequence()
|
csong@23
|
160 self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence)
|
csong@9
|
161 return self.noteSequence
|
csong@9
|
162
|
csong@9
|
163 def get_velocity_sequence(self):
|
csong@22
|
164 if self.velocitySequence == None:
|
csong@23
|
165 self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence)
|
csong@9
|
166 return self.velocitySequence
|
csong@9
|
167
|
csong@9
|
168 def get_binary_sequence(self):
|
csong@9
|
169 return ceiling(self.get_velocity_sequence())
|
csong@9
|
170
|
csong@9
|
171 def get_next_bar(self):
|
csong@9
|
172 return self.nextBar
|
csong@9
|
173
|
csong@9
|
174 def get_previous_bar(self):
|
csong@9
|
175 return self.prevBar
|
csong@9
|
176
|
csong@9
|
177 def set_next_bar(self, bar):
|
csong@9
|
178 self.nextBar = bar
|
csong@9
|
179
|
csong@9
|
180 def set_previous_bar(self, bar):
|
csong@9
|
181 self.prevBar = bar
|
csong@9
|
182
|
csong@9
|
183 def get_subdivision_sequence(self):
|
csong@18
|
184 return self.timeSignature.get_subdivision_sequence()
|
csong@9
|
185
|
csong@9
|
186 def get_beat_level(self):
|
csong@20
|
187 return self.timeSignature.get_beat_level()
|
csong@9
|
188
|
csong@9
|
189 def get_time_signature(self):
|
csong@9
|
190 return self.timeSignature
|
csong@9
|
191
|
csong@21
|
192 # return the length of a bar in time units (ticks)
|
csong@22
|
193 def get_bar_ticks(self):
|
csong@23
|
194 return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq)
|
csong@22
|
195
|
christopher@29
|
196 def to_string(self, sequenceType=None):
|
christopher@29
|
197 if sequenceType==None or sequenceType=="v":
|
christopher@29
|
198 output = "v{"+self.get_velocity_sequence().to_string()+"}"
|
christopher@29
|
199 else:
|
christopher@29
|
200 output = "y{"+self.get_note_sequence().to_string()+"}"
|
christopher@29
|
201 return output
|
christopher@29
|
202
|
csong@9
|
203
|
csong@18
|
204 class TimeSignature():
|
csong@18
|
205 def __init__(self, inputString):
|
csong@20
|
206 if inputString in parameter_setter.read_time_signature():
|
csong@18
|
207 self.tsString = inputString
|
csong@18
|
208 else:
|
csong@35
|
209 print "Error: undefined time-signature: ", inputString
|
csong@18
|
210 raise NullTimeSignatureError
|
csong@18
|
211
|
csong@18
|
212 def get_subdivision_sequence(self):
|
csong@20
|
213 return parameter_setter.timeSignatureBase[self.tsString][0]
|
csong@18
|
214
|
csong@18
|
215 def get_beat_level(self):
|
csong@20
|
216 return parameter_setter.timeSignatureBase[self.tsString][1]
|
csong@18
|
217
|
csong@18
|
218 def get_numerator(self):
|
csong@18
|
219 return int(self.tsString.split('/')[0])
|
csong@18
|
220
|
csong@18
|
221 def get_denominator(self):
|
csong@18
|
222 return int(self.tsString.split('/')[1])
|
csong@18
|
223
|
christopher@24
|
224 def to_string(self):
|
christopher@24
|
225 return self.tsString
|
csong@18
|
226
|
csong@18
|
227
|