csong@9: christopher@29: from basic_functions import ceiling, string_to_sequence, calculate_bar_ticks, velocity_sequence_to_min_timespan csong@13: import parameter_setter csong@13: import rhythm_parser csong@9: csong@9: class Note(): csong@22: def __init__(self, firstarg = None, duration = None, velocity = None): csong@22: self.startTime = 0 csong@22: self.duration = 0 csong@22: self.velocity = 0 csong@22: csong@22: if firstarg != None: csong@22: if isinstance(firstarg,basestring): csong@22: intlist = string_to_sequence(firstarg) csong@22: self.startTime = intlist[0] csong@22: self.duration = intlist[1] csong@22: self.velocity = intlist[2] csong@22: elif isinstance(firstarg,int): csong@22: self.startTime = firstarg csong@22: csong@22: if duration != None: csong@22: self.duration = duration csong@22: if velocity != None: csong@22: self.velocity = velocity csong@22: csong@22: csong@22: def to_string(self): csong@22: return "(%d,%d,%f)" %(self.startTime, self.duration, self.velocity) csong@22: csong@9: csong@9: # NoteSequence is a list of Note csong@9: class NoteSequence(list): csong@22: def __init__(self, noteSequenceString = None): csong@22: if noteSequenceString != None: csong@9: self.string_to_note_sequence(noteSequenceString) csong@9: csong@9: def string_to_note_sequence(self, noteSequenceString): christopher@29: noteSequenceString = rhythm_parser.discard_spaces(noteSequenceString) csong@9: # try: csong@9: # Turning "(1,2,3),(4,5,6),(7,8,9)" into ["1,2,3","4,5,6,","7,8,9"] csong@9: listStrings = noteSequenceString[1:-1].split("),(") csong@9: for localString in listStrings: csong@9: self.append(Note(localString)) csong@9: csong@22: def to_string(self): csong@22: noteSequenceString = "" csong@22: for note in self: csong@22: noteSequenceString += note.to_string() + "," csong@22: return noteSequenceString[:-1] csong@9: csong@22: # VelocitySequence is a list of float numbers csong@22: class VelocitySequence(list): christopher@29: def __init__(self, velocitySequence = None): christopher@29: if velocitySequence != None: christopher@29: if isinstance(velocitySequence,basestring): christopher@29: self.string_to_velocity_sequence(velocitySequence) christopher@29: elif isinstance(velocitySequence, list): christopher@29: self+=velocitySequence csong@9: csong@22: def string_to_velocity_sequence(self,inputString): csong@22: self.extend(string_to_sequence(inputString)) csong@9: csong@22: def to_string(self): christopher@29: return str(velocity_sequence_to_min_timespan(self))[1:-1].replace(" ","") csong@22: csong@22: csong@23: def velocity_sequence_to_note_sequence(velocitySequence, nextbarVelocitySequence = None): csong@22: csong@22: noteSequence = NoteSequence() csong@22: csong@22: for index in range(len(velocitySequence)): csong@22: if (velocitySequence[index]!= 0): # onset detected csong@22: startTime = index csong@22: velocity = velocitySequence[index] csong@22: csong@22: # if there are previous notes added csong@22: if( len(noteSequence) > 0): csong@22: previousNote = noteSequence[-1] csong@22: previousNote.duration = startTime - previousNote.startTime csong@22: csong@22: # add the current note into note sequence csong@22: noteSequence.append( Note(startTime, 0, velocity) ) csong@22: csong@22: # to set the duration for the last note csong@22: if( len(noteSequence) > 0): csong@23: lastNote = noteSequence[-1] csong@23: csong@23: if nextbarVelocitySequence == None: csong@23: lastNote.duration = len(velocitySequence) - lastNote.startTime csong@23: else: csong@23: nextNoteStartTime = next((index for index, v in enumerate(nextbarVelocitySequence) if v), None) csong@23: lastNote.duration = len(velocitySequence) + nextNoteStartTime-lastNote.startTime csong@23: csong@22: csong@22: return noteSequence csong@22: csong@22: csong@22: def note_sequence_to_velocity_sequence(noteSequence, timespanTicks = None): csong@22: csong@22: velocitySequence = VelocitySequence() csong@22: csong@22: previousNoteStartTime = -1 csong@22: csong@22: for note in noteSequence: csong@22: csong@22: interOnsetInterval = note.startTime - previousNoteStartTime csong@22: velocitySequence += [0]*(interOnsetInterval-1) csong@22: velocitySequence += [note.velocity] csong@22: csong@22: previousNoteStartTime = note.startTime csong@22: csong@22: if timespanTicks!=None: csong@22: velocitySequence += [0]*(timespanTicks - len(velocitySequence)) csong@22: else: csong@22: velocitySequence += [0]*(noteSequence[-1].duration-1) csong@22: csong@22: # normalising velocity sequence between 0-1 christopher@38: if max(velocitySequence)>0: christopher@38: velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence]) csong@22: csong@22: return velocitySequence csong@9: csong@9: csong@9: class BarList(list): csong@9: def append(self,bar): csong@9: if(len(self)>0): csong@9: bar.set_previous_bar(self[-1]) csong@9: self[-1].set_next_bar(bar) csong@9: super(BarList, self).append(bar) csong@9: christopher@29: def concat(self, barList): christopher@29: while(len(barList)!=0): christopher@29: localbar = barList[0] christopher@29: self.append(localbar) christopher@29: barList.remove(localbar) christopher@29: csong@9: csong@9: class Bar: csong@9: def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None): csong@9: if isinstance(rhythmSequence, NoteSequence): csong@9: self.noteSequence = rhythmSequence csong@9: self.velocitySequence = None csong@9: elif isinstance(rhythmSequence, VelocitySequence): csong@9: self.velocitySequence = rhythmSequence csong@9: self.noteSequence = None csong@9: csong@9: self.tpq = ticksPerQuarter csong@9: self.qpm = qpmTempo christopher@30: if isinstance(timeSignature, basestring): christopher@30: self.timeSignature = TimeSignature(timeSignature) christopher@30: else: christopher@30: self.timeSignature = timeSignature csong@9: self.nextBar = nextBar csong@9: self.prevBar = prevBar csong@9: csong@9: def get_note_sequence(self): csong@22: if self.noteSequence == None: csong@23: nextbarVelocitySequence = None csong@23: if self.nextBar != None: csong@23: nextbarVelocitySequence = self.nextBar.get_velocity_sequence() csong@23: self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence) csong@9: return self.noteSequence csong@9: csong@9: def get_velocity_sequence(self): csong@22: if self.velocitySequence == None: christopher@38: self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence, self.get_bar_ticks()) csong@9: return self.velocitySequence csong@9: csong@9: def get_binary_sequence(self): csong@9: return ceiling(self.get_velocity_sequence()) csong@9: csong@9: def get_next_bar(self): csong@9: return self.nextBar csong@9: csong@9: def get_previous_bar(self): csong@9: return self.prevBar csong@9: csong@9: def set_next_bar(self, bar): csong@9: self.nextBar = bar csong@9: csong@9: def set_previous_bar(self, bar): csong@9: self.prevBar = bar csong@9: csong@9: def get_subdivision_sequence(self): csong@18: return self.timeSignature.get_subdivision_sequence() csong@9: csong@9: def get_beat_level(self): csong@20: return self.timeSignature.get_beat_level() csong@9: csong@9: def get_time_signature(self): csong@9: return self.timeSignature csong@9: csong@21: # return the length of a bar in time units (ticks) csong@22: def get_bar_ticks(self): csong@23: return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq) csong@22: christopher@38: def is_empty(self): christopher@38: if max(self.get_velocity_sequence())>0: christopher@38: return False christopher@38: else: christopher@38: return True christopher@38: christopher@29: def to_string(self, sequenceType=None): christopher@38: output = "t{"+self.timeSignature.to_string()+"}" christopher@38: prev = self.get_previous_bar() christopher@38: if prev!=None: christopher@38: if prev.get_time_signature()==self.get_time_signature(): christopher@38: output="" christopher@38: christopher@29: if sequenceType==None or sequenceType=="v": christopher@38: output += "v{"+self.get_velocity_sequence().to_string()+"}" christopher@29: else: christopher@38: output += "y{"+self.get_note_sequence().to_string()+"}" christopher@29: return output christopher@29: csong@9: csong@18: class TimeSignature(): csong@18: def __init__(self, inputString): csong@20: if inputString in parameter_setter.read_time_signature(): csong@18: self.tsString = inputString csong@18: else: csong@35: print "Error: undefined time-signature: ", inputString csong@18: raise NullTimeSignatureError csong@18: csong@18: def get_subdivision_sequence(self): csong@20: return parameter_setter.timeSignatureBase[self.tsString][0] csong@18: csong@18: def get_beat_level(self): csong@20: return parameter_setter.timeSignatureBase[self.tsString][1] csong@18: csong@18: def get_numerator(self): csong@18: return int(self.tsString.split('/')[0]) csong@18: csong@18: def get_denominator(self): csong@18: return int(self.tsString.split('/')[1]) csong@18: christopher@24: def to_string(self): christopher@24: return self.tsString csong@18: csong@18: