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