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@22
|
64 def velocity_sequence_to_note_sequence(velocitySequence):
|
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@22
|
83 previousNote = noteSequence[-1]
|
csong@22
|
84 previousNote.duration = len(velocitySequence) - previousNote.startTime
|
csong@22
|
85
|
csong@22
|
86 return noteSequence
|
csong@22
|
87
|
csong@22
|
88
|
csong@22
|
89 def note_sequence_to_velocity_sequence(noteSequence, timespanTicks = None):
|
csong@22
|
90
|
csong@22
|
91 velocitySequence = VelocitySequence()
|
csong@22
|
92
|
csong@22
|
93 previousNoteStartTime = -1
|
csong@22
|
94
|
csong@22
|
95 for note in noteSequence:
|
csong@22
|
96
|
csong@22
|
97 interOnsetInterval = note.startTime - previousNoteStartTime
|
csong@22
|
98 velocitySequence += [0]*(interOnsetInterval-1)
|
csong@22
|
99 velocitySequence += [note.velocity]
|
csong@22
|
100
|
csong@22
|
101 previousNoteStartTime = note.startTime
|
csong@22
|
102
|
csong@22
|
103 if timespanTicks!=None:
|
csong@22
|
104 velocitySequence += [0]*(timespanTicks - len(velocitySequence))
|
csong@22
|
105 else:
|
csong@22
|
106 velocitySequence += [0]*(noteSequence[-1].duration-1)
|
csong@22
|
107
|
csong@22
|
108 # normalising velocity sequence between 0-1
|
csong@22
|
109 velocitySequence = [float(v)/max(velocitySequence) for v in velocitySequence]
|
csong@22
|
110
|
csong@22
|
111 return velocitySequence
|
csong@9
|
112
|
csong@9
|
113
|
csong@9
|
114 class BarList(list):
|
csong@9
|
115 def append(self,bar):
|
csong@9
|
116 if(len(self)>0):
|
csong@9
|
117 bar.set_previous_bar(self[-1])
|
csong@9
|
118 self[-1].set_next_bar(bar)
|
csong@9
|
119 super(BarList, self).append(bar)
|
csong@9
|
120
|
csong@9
|
121
|
csong@9
|
122 class Bar:
|
csong@9
|
123
|
csong@9
|
124 def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None):
|
csong@9
|
125 if isinstance(rhythmSequence, NoteSequence):
|
csong@9
|
126 self.noteSequence = rhythmSequence
|
csong@9
|
127 self.velocitySequence = None
|
csong@9
|
128 elif isinstance(rhythmSequence, VelocitySequence):
|
csong@9
|
129 self.velocitySequence = rhythmSequence
|
csong@9
|
130 self.noteSequence = None
|
csong@9
|
131
|
csong@9
|
132 self.tpq = ticksPerQuarter
|
csong@9
|
133 self.qpm = qpmTempo
|
csong@18
|
134 self.timeSignature = TimeSignature(timeSignature)
|
csong@9
|
135 self.nextBar = nextBar
|
csong@9
|
136 self.prevBar = prevBar
|
csong@9
|
137
|
csong@9
|
138 def get_note_sequence(self):
|
csong@22
|
139 if self.noteSequence == None:
|
csong@22
|
140 self.noteSequence = velocitySequence_to_noteSequence(self.velocitySequence)
|
csong@9
|
141 return self.noteSequence
|
csong@9
|
142
|
csong@9
|
143 def get_velocity_sequence(self):
|
csong@22
|
144 if self.velocitySequence == None:
|
csong@22
|
145 self.velocitySequence = noteSequence_to_velocitySequence(self.noteSequence)
|
csong@9
|
146 return self.velocitySequence
|
csong@9
|
147
|
csong@9
|
148 def get_binary_sequence(self):
|
csong@9
|
149 return ceiling(self.get_velocity_sequence())
|
csong@9
|
150
|
csong@9
|
151 def get_next_bar(self):
|
csong@9
|
152 return self.nextBar
|
csong@9
|
153
|
csong@9
|
154 def get_previous_bar(self):
|
csong@9
|
155 return self.prevBar
|
csong@9
|
156
|
csong@9
|
157 def set_next_bar(self, bar):
|
csong@9
|
158 self.nextBar = bar
|
csong@9
|
159
|
csong@9
|
160 def set_previous_bar(self, bar):
|
csong@9
|
161 self.prevBar = bar
|
csong@9
|
162
|
csong@9
|
163 def get_subdivision_sequence(self):
|
csong@18
|
164 return self.timeSignature.get_subdivision_sequence()
|
csong@9
|
165
|
csong@9
|
166 def get_beat_level(self):
|
csong@20
|
167 return self.timeSignature.get_beat_level()
|
csong@9
|
168
|
csong@9
|
169 def get_time_signature(self):
|
csong@9
|
170 return self.timeSignature
|
csong@9
|
171
|
csong@21
|
172 # return the length of a bar in time units (ticks)
|
csong@22
|
173 def get_bar_ticks(self):
|
csong@22
|
174 return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.ticksPerQuarter)
|
csong@22
|
175
|
csong@9
|
176
|
csong@18
|
177 class TimeSignature():
|
csong@18
|
178 def __init__(self, inputString):
|
csong@20
|
179 if inputString in parameter_setter.read_time_signature():
|
csong@18
|
180 self.tsString = inputString
|
csong@18
|
181 else:
|
csong@18
|
182 print "Error: undefined time-signature ", inputString
|
csong@18
|
183 raise NullTimeSignatureError
|
csong@18
|
184
|
csong@18
|
185 def get_subdivision_sequence(self):
|
csong@20
|
186 return parameter_setter.timeSignatureBase[self.tsString][0]
|
csong@18
|
187
|
csong@18
|
188 def get_beat_level(self):
|
csong@20
|
189 return parameter_setter.timeSignatureBase[self.tsString][1]
|
csong@18
|
190
|
csong@18
|
191 def get_numerator(self):
|
csong@18
|
192 return int(self.tsString.split('/')[0])
|
csong@18
|
193
|
csong@18
|
194 def get_denominator(self):
|
csong@18
|
195 return int(self.tsString.split('/')[1])
|
csong@18
|
196
|
csong@18
|
197
|
csong@18
|
198
|