annotate synpy/music_objects.py @ 76:90b68f259541 tip

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