csong@9
|
1
|
csong@22
|
2 from basic_functions import ceiling, string_to_sequence, calculate_bar_ticks
|
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):
|
csong@13
|
38 noteSequenceString = rhythm_parser.discardSpaces(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):
|
csong@22
|
53 def __init__(self, velocitySequenceString = None):
|
csong@22
|
54 if velocitySequenceString != None:
|
csong@22
|
55 self.string_to_velocity_sequence(velocitySequenceString)
|
csong@9
|
56
|
csong@22
|
57 def string_to_velocity_sequence(self,inputString):
|
csong@22
|
58 self.extend(string_to_sequence(inputString))
|
csong@9
|
59
|
csong@22
|
60 def to_string(self):
|
csong@22
|
61 return str(self)[1:-1].replace(" ","")
|
csong@22
|
62
|
csong@22
|
63
|
csong@23
|
64 def velocity_sequence_to_note_sequence(velocitySequence, nextbarVelocitySequence = None):
|
csong@22
|
65
|
csong@22
|
66 noteSequence = NoteSequence()
|
csong@22
|
67
|
csong@22
|
68 for index in range(len(velocitySequence)):
|
csong@22
|
69 if (velocitySequence[index]!= 0): # onset detected
|
csong@22
|
70 startTime = index
|
csong@22
|
71 velocity = velocitySequence[index]
|
csong@22
|
72
|
csong@22
|
73 # if there are previous notes added
|
csong@22
|
74 if( len(noteSequence) > 0):
|
csong@22
|
75 previousNote = noteSequence[-1]
|
csong@22
|
76 previousNote.duration = startTime - previousNote.startTime
|
csong@22
|
77
|
csong@22
|
78 # add the current note into note sequence
|
csong@22
|
79 noteSequence.append( Note(startTime, 0, velocity) )
|
csong@22
|
80
|
csong@22
|
81 # to set the duration for the last note
|
csong@22
|
82 if( len(noteSequence) > 0):
|
csong@23
|
83 lastNote = noteSequence[-1]
|
csong@23
|
84
|
csong@23
|
85 if nextbarVelocitySequence == None:
|
csong@23
|
86 lastNote.duration = len(velocitySequence) - lastNote.startTime
|
csong@23
|
87 else:
|
csong@23
|
88 nextNoteStartTime = next((index for index, v in enumerate(nextbarVelocitySequence) if v), None)
|
csong@23
|
89 lastNote.duration = len(velocitySequence) + nextNoteStartTime-lastNote.startTime
|
csong@23
|
90
|
csong@22
|
91
|
csong@22
|
92 return noteSequence
|
csong@22
|
93
|
csong@22
|
94
|
csong@22
|
95 def note_sequence_to_velocity_sequence(noteSequence, timespanTicks = None):
|
csong@22
|
96
|
csong@22
|
97 velocitySequence = VelocitySequence()
|
csong@22
|
98
|
csong@22
|
99 previousNoteStartTime = -1
|
csong@22
|
100
|
csong@22
|
101 for note in noteSequence:
|
csong@22
|
102
|
csong@22
|
103 interOnsetInterval = note.startTime - previousNoteStartTime
|
csong@22
|
104 velocitySequence += [0]*(interOnsetInterval-1)
|
csong@22
|
105 velocitySequence += [note.velocity]
|
csong@22
|
106
|
csong@22
|
107 previousNoteStartTime = note.startTime
|
csong@22
|
108
|
csong@22
|
109 if timespanTicks!=None:
|
csong@22
|
110 velocitySequence += [0]*(timespanTicks - len(velocitySequence))
|
csong@22
|
111 else:
|
csong@22
|
112 velocitySequence += [0]*(noteSequence[-1].duration-1)
|
csong@22
|
113
|
csong@22
|
114 # normalising velocity sequence between 0-1
|
csong@22
|
115 velocitySequence = [float(v)/max(velocitySequence) for v in velocitySequence]
|
csong@22
|
116
|
csong@22
|
117 return velocitySequence
|
csong@9
|
118
|
csong@9
|
119
|
csong@9
|
120 class BarList(list):
|
csong@9
|
121 def append(self,bar):
|
csong@9
|
122 if(len(self)>0):
|
csong@9
|
123 bar.set_previous_bar(self[-1])
|
csong@9
|
124 self[-1].set_next_bar(bar)
|
csong@9
|
125 super(BarList, self).append(bar)
|
csong@9
|
126
|
csong@9
|
127
|
csong@9
|
128 class Bar:
|
csong@9
|
129 def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None):
|
csong@9
|
130 if isinstance(rhythmSequence, NoteSequence):
|
csong@9
|
131 self.noteSequence = rhythmSequence
|
csong@9
|
132 self.velocitySequence = None
|
csong@9
|
133 elif isinstance(rhythmSequence, VelocitySequence):
|
csong@9
|
134 self.velocitySequence = rhythmSequence
|
csong@9
|
135 self.noteSequence = None
|
csong@9
|
136
|
csong@9
|
137 self.tpq = ticksPerQuarter
|
csong@9
|
138 self.qpm = qpmTempo
|
csong@18
|
139 self.timeSignature = TimeSignature(timeSignature)
|
csong@9
|
140 self.nextBar = nextBar
|
csong@9
|
141 self.prevBar = prevBar
|
csong@9
|
142
|
csong@9
|
143 def get_note_sequence(self):
|
csong@22
|
144 if self.noteSequence == None:
|
csong@23
|
145 nextbarVelocitySequence = None
|
csong@23
|
146 if self.nextBar != None:
|
csong@23
|
147 nextbarVelocitySequence = self.nextBar.get_velocity_sequence()
|
csong@23
|
148 self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence)
|
csong@9
|
149 return self.noteSequence
|
csong@9
|
150
|
csong@9
|
151 def get_velocity_sequence(self):
|
csong@22
|
152 if self.velocitySequence == None:
|
csong@23
|
153 self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence)
|
csong@9
|
154 return self.velocitySequence
|
csong@9
|
155
|
csong@9
|
156 def get_binary_sequence(self):
|
csong@9
|
157 return ceiling(self.get_velocity_sequence())
|
csong@9
|
158
|
csong@9
|
159 def get_next_bar(self):
|
csong@9
|
160 return self.nextBar
|
csong@9
|
161
|
csong@9
|
162 def get_previous_bar(self):
|
csong@9
|
163 return self.prevBar
|
csong@9
|
164
|
csong@9
|
165 def set_next_bar(self, bar):
|
csong@9
|
166 self.nextBar = bar
|
csong@9
|
167
|
csong@9
|
168 def set_previous_bar(self, bar):
|
csong@9
|
169 self.prevBar = bar
|
csong@9
|
170
|
csong@9
|
171 def get_subdivision_sequence(self):
|
csong@18
|
172 return self.timeSignature.get_subdivision_sequence()
|
csong@9
|
173
|
csong@9
|
174 def get_beat_level(self):
|
csong@20
|
175 return self.timeSignature.get_beat_level()
|
csong@9
|
176
|
csong@9
|
177 def get_time_signature(self):
|
csong@9
|
178 return self.timeSignature
|
csong@9
|
179
|
csong@21
|
180 # return the length of a bar in time units (ticks)
|
csong@22
|
181 def get_bar_ticks(self):
|
csong@23
|
182 return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq)
|
csong@22
|
183
|
csong@9
|
184
|
csong@18
|
185 class TimeSignature():
|
csong@18
|
186 def __init__(self, inputString):
|
csong@20
|
187 if inputString in parameter_setter.read_time_signature():
|
csong@18
|
188 self.tsString = inputString
|
csong@18
|
189 else:
|
csong@18
|
190 print "Error: undefined time-signature ", inputString
|
csong@18
|
191 raise NullTimeSignatureError
|
csong@18
|
192
|
csong@18
|
193 def get_subdivision_sequence(self):
|
csong@20
|
194 return parameter_setter.timeSignatureBase[self.tsString][0]
|
csong@18
|
195
|
csong@18
|
196 def get_beat_level(self):
|
csong@20
|
197 return parameter_setter.timeSignatureBase[self.tsString][1]
|
csong@18
|
198
|
csong@18
|
199 def get_numerator(self):
|
csong@18
|
200 return int(self.tsString.split('/')[0])
|
csong@18
|
201
|
csong@18
|
202 def get_denominator(self):
|
csong@18
|
203 return int(self.tsString.split('/')[1])
|
csong@18
|
204
|
csong@18
|
205
|
csong@18
|
206
|