annotate Syncopation models/music_objects.py @ 41:903aec3d5b9f

merged
author christopherh <christopher.harte@eecs.qmul.ac.uk>
date Thu, 23 Apr 2015 15:47:48 +0100
parents 6371e8f21f7d
children
rev   line source
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):
christopher@40 14 intlist = string_to_sequence(firstarg,int)
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
christopher@40 51
christopher@40 52 class NormalisedVelocityValueOutOfRange(Exception):
christopher@40 53 def __init__(self, value):
christopher@40 54 self.value = value
christopher@40 55 def __str__(self):
christopher@40 56 return repr(self.value)
christopher@40 57
csong@22 58 # VelocitySequence is a list of float numbers
csong@22 59 class VelocitySequence(list):
christopher@29 60 def __init__(self, velocitySequence = None):
christopher@29 61 if velocitySequence != None:
christopher@29 62 if isinstance(velocitySequence,basestring):
christopher@29 63 self.string_to_velocity_sequence(velocitySequence)
christopher@29 64 elif isinstance(velocitySequence, list):
christopher@29 65 self+=velocitySequence
csong@9 66
csong@22 67 def string_to_velocity_sequence(self,inputString):
christopher@40 68
christopher@40 69 def convert_velocity_value(argstring):
christopher@40 70 value = float(argstring)
christopher@40 71 if value>=0 and value<=1:
christopher@40 72 return value
christopher@40 73 else:
christopher@40 74 raise NormalisedVelocityValueOutOfRange("Value: "+argstring+" in " + inputString)
christopher@40 75
christopher@40 76 self.extend(string_to_sequence(inputString,convert_velocity_value))
christopher@40 77
csong@9 78
csong@22 79 def to_string(self):
christopher@29 80 return str(velocity_sequence_to_min_timespan(self))[1:-1].replace(" ","")
csong@22 81
csong@22 82
csong@23 83 def velocity_sequence_to_note_sequence(velocitySequence, nextbarVelocitySequence = None):
csong@22 84
csong@22 85 noteSequence = NoteSequence()
csong@22 86
csong@22 87 for index in range(len(velocitySequence)):
csong@22 88 if (velocitySequence[index]!= 0): # onset detected
csong@22 89 startTime = index
csong@22 90 velocity = velocitySequence[index]
csong@22 91
csong@22 92 # if there are previous notes added
csong@22 93 if( len(noteSequence) > 0):
csong@22 94 previousNote = noteSequence[-1]
csong@22 95 previousNote.duration = startTime - previousNote.startTime
csong@22 96
csong@22 97 # add the current note into note sequence
csong@22 98 noteSequence.append( Note(startTime, 0, velocity) )
csong@22 99
csong@22 100 # to set the duration for the last note
csong@22 101 if( len(noteSequence) > 0):
csong@23 102 lastNote = noteSequence[-1]
csong@23 103
csong@23 104 if nextbarVelocitySequence == None:
csong@23 105 lastNote.duration = len(velocitySequence) - lastNote.startTime
csong@23 106 else:
csong@23 107 nextNoteStartTime = next((index for index, v in enumerate(nextbarVelocitySequence) if v), None)
csong@23 108 lastNote.duration = len(velocitySequence) + nextNoteStartTime-lastNote.startTime
csong@23 109
csong@22 110
csong@22 111 return noteSequence
csong@22 112
csong@22 113
csong@22 114 def note_sequence_to_velocity_sequence(noteSequence, timespanTicks = None):
christopher@40 115
csong@22 116 velocitySequence = VelocitySequence()
csong@22 117
csong@22 118 previousNoteStartTime = -1
csong@22 119
csong@22 120 for note in noteSequence:
csong@22 121
csong@22 122 interOnsetInterval = note.startTime - previousNoteStartTime
csong@22 123 velocitySequence += [0]*(interOnsetInterval-1)
csong@22 124 velocitySequence += [note.velocity]
csong@22 125
csong@22 126 previousNoteStartTime = note.startTime
csong@22 127
csong@22 128 if timespanTicks!=None:
csong@22 129 velocitySequence += [0]*(timespanTicks - len(velocitySequence))
csong@22 130 else:
csong@22 131 velocitySequence += [0]*(noteSequence[-1].duration-1)
csong@22 132
csong@22 133 # normalising velocity sequence between 0-1
christopher@38 134 if max(velocitySequence)>0:
christopher@38 135 velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence])
csong@22 136
csong@22 137 return velocitySequence
csong@9 138
csong@9 139
csong@9 140 class BarList(list):
csong@9 141 def append(self,bar):
csong@9 142 if(len(self)>0):
csong@9 143 bar.set_previous_bar(self[-1])
csong@9 144 self[-1].set_next_bar(bar)
csong@9 145 super(BarList, self).append(bar)
csong@9 146
christopher@29 147 def concat(self, barList):
christopher@29 148 while(len(barList)!=0):
christopher@29 149 localbar = barList[0]
christopher@29 150 self.append(localbar)
christopher@29 151 barList.remove(localbar)
christopher@29 152
csong@9 153
csong@9 154 class Bar:
csong@9 155 def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None):
csong@9 156 if isinstance(rhythmSequence, NoteSequence):
csong@9 157 self.noteSequence = rhythmSequence
csong@9 158 self.velocitySequence = None
csong@9 159 elif isinstance(rhythmSequence, VelocitySequence):
csong@9 160 self.velocitySequence = rhythmSequence
csong@9 161 self.noteSequence = None
csong@9 162
csong@9 163 self.tpq = ticksPerQuarter
csong@9 164 self.qpm = qpmTempo
christopher@30 165 if isinstance(timeSignature, basestring):
christopher@30 166 self.timeSignature = TimeSignature(timeSignature)
christopher@30 167 else:
christopher@30 168 self.timeSignature = timeSignature
csong@9 169 self.nextBar = nextBar
csong@9 170 self.prevBar = prevBar
csong@9 171
csong@9 172 def get_note_sequence(self):
csong@22 173 if self.noteSequence == None:
csong@23 174 nextbarVelocitySequence = None
csong@23 175 if self.nextBar != None:
csong@23 176 nextbarVelocitySequence = self.nextBar.get_velocity_sequence()
csong@23 177 self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence)
csong@9 178 return self.noteSequence
csong@9 179
csong@9 180 def get_velocity_sequence(self):
csong@22 181 if self.velocitySequence == None:
christopher@38 182 self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence, self.get_bar_ticks())
csong@9 183 return self.velocitySequence
csong@9 184
csong@9 185 def get_binary_sequence(self):
csong@9 186 return ceiling(self.get_velocity_sequence())
csong@9 187
csong@9 188 def get_next_bar(self):
csong@9 189 return self.nextBar
csong@9 190
csong@9 191 def get_previous_bar(self):
csong@9 192 return self.prevBar
csong@9 193
csong@9 194 def set_next_bar(self, bar):
csong@9 195 self.nextBar = bar
csong@9 196
csong@9 197 def set_previous_bar(self, bar):
csong@9 198 self.prevBar = bar
csong@9 199
csong@9 200 def get_subdivision_sequence(self):
csong@18 201 return self.timeSignature.get_subdivision_sequence()
csong@9 202
csong@9 203 def get_beat_level(self):
csong@20 204 return self.timeSignature.get_beat_level()
csong@9 205
csong@9 206 def get_time_signature(self):
csong@9 207 return self.timeSignature
csong@9 208
csong@21 209 # return the length of a bar in time units (ticks)
csong@22 210 def get_bar_ticks(self):
csong@23 211 return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq)
csong@22 212
christopher@38 213 def is_empty(self):
christopher@38 214 if max(self.get_velocity_sequence())>0:
christopher@38 215 return False
christopher@38 216 else:
christopher@38 217 return True
christopher@38 218
christopher@29 219 def to_string(self, sequenceType=None):
christopher@38 220 output = "t{"+self.timeSignature.to_string()+"}"
christopher@38 221 prev = self.get_previous_bar()
christopher@38 222 if prev!=None:
christopher@38 223 if prev.get_time_signature()==self.get_time_signature():
christopher@38 224 output=""
christopher@38 225
christopher@29 226 if sequenceType==None or sequenceType=="v":
christopher@38 227 output += "v{"+self.get_velocity_sequence().to_string()+"}"
christopher@29 228 else:
christopher@38 229 output += "y{"+self.get_note_sequence().to_string()+"}"
christopher@29 230 return output
christopher@29 231
csong@9 232
csong@18 233 class TimeSignature():
csong@18 234 def __init__(self, inputString):
csong@20 235 if inputString in parameter_setter.read_time_signature():
csong@18 236 self.tsString = inputString
csong@18 237 else:
csong@35 238 print "Error: undefined time-signature: ", inputString
csong@18 239 raise NullTimeSignatureError
csong@18 240
csong@18 241 def get_subdivision_sequence(self):
csong@20 242 return parameter_setter.timeSignatureBase[self.tsString][0]
csong@18 243
csong@18 244 def get_beat_level(self):
csong@20 245 return parameter_setter.timeSignatureBase[self.tsString][1]
csong@18 246
csong@18 247 def get_numerator(self):
csong@18 248 return int(self.tsString.split('/')[0])
csong@18 249
csong@18 250 def get_denominator(self):
csong@18 251 return int(self.tsString.split('/')[1])
csong@18 252
christopher@24 253 def to_string(self):
christopher@24 254 return self.tsString
csong@18 255
csong@18 256