Mercurial > hg > syncopation-dataset
diff synpy/music_objects.py @ 72:ef891481231e
reorganising the repo in a major way ready for going public
author | christopherh <christopher.harte@eecs.qmul.ac.uk> |
---|---|
date | Tue, 12 May 2015 08:53:12 +0100 |
parents | Syncopation models/synpy/music_objects.py@9a60ca4ae0fb |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/synpy/music_objects.py Tue May 12 08:53:12 2015 +0100 @@ -0,0 +1,286 @@ + +from basic_functions import ceiling, string_to_sequence, calculate_bar_ticks, velocity_sequence_to_min_timespan +import parameter_setter +import rhythm_parser + +class Note(): + def __init__(self, firstarg = None, duration = None, velocity = None): + self.startTime = 0 + self.duration = 0 + self.velocity = 0 + + if firstarg != None: + if isinstance(firstarg,basestring): + intlist = string_to_sequence(firstarg,int) + self.startTime = intlist[0] + self.duration = intlist[1] + self.velocity = intlist[2] + elif isinstance(firstarg,int): + self.startTime = firstarg + + if duration != None: + self.duration = duration + if velocity != None: + self.velocity = velocity + + + def to_string(self): + return "(%d,%d,%f)" %(self.startTime, self.duration, self.velocity) + + +# NoteSequence is a list of Note +class NoteSequence(list): + def __init__(self, noteSequenceString = None): + if noteSequenceString != None: + self.string_to_note_sequence(noteSequenceString) + + def string_to_note_sequence(self, noteSequenceString): + noteSequenceString = rhythm_parser.discard_spaces(noteSequenceString) + # try: + # Turning "(1,2,3),(4,5,6),(7,8,9)" into ["1,2,3","4,5,6,","7,8,9"] + listStrings = noteSequenceString[1:-1].split("),(") + for localString in listStrings: + self.append(Note(localString)) + + def to_string(self): + noteSequenceString = "" + for note in self: + noteSequenceString += note.to_string() + "," + return noteSequenceString[:-1] + + +class NormalisedVelocityValueOutOfRange(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +# VelocitySequence is a list of float numbers +class VelocitySequence(list): + def __init__(self, velocitySequence = None): + if velocitySequence != None: + if isinstance(velocitySequence,basestring): + self.string_to_velocity_sequence(velocitySequence) + elif isinstance(velocitySequence, list): + self+=velocitySequence + + def string_to_velocity_sequence(self,inputString): + + def convert_velocity_value(argstring): + value = float(argstring) + if value>=0 and value<=1: + return value + else: + raise NormalisedVelocityValueOutOfRange("Value: "+argstring+" in " + inputString) + + self.extend(string_to_sequence(inputString,convert_velocity_value)) + + + def to_string(self): + return str(velocity_sequence_to_min_timespan(self))[1:-1].replace(" ","") + + +def velocity_sequence_to_note_sequence(velocitySequence, nextbarVelocitySequence = None): + + noteSequence = NoteSequence() + + for index in range(len(velocitySequence)): + if (velocitySequence[index]!= 0): # onset detected + startTime = index + velocity = velocitySequence[index] + + # if there are previous notes added + if( len(noteSequence) > 0): + previousNote = noteSequence[-1] + previousNote.duration = startTime - previousNote.startTime + + # add the current note into note sequence + noteSequence.append( Note(startTime, 0, velocity) ) + + # to set the duration for the last note + if( len(noteSequence) > 0): + lastNote = noteSequence[-1] + + if nextbarVelocitySequence == None: + lastNote.duration = len(velocitySequence) - lastNote.startTime + else: + nextNoteStartTime = next((index for index, v in enumerate(nextbarVelocitySequence) if v), None) + lastNote.duration = len(velocitySequence) + nextNoteStartTime-lastNote.startTime + + + return noteSequence + + +def note_sequence_to_velocity_sequence(noteSequence, timespanTicks = None): + + velocitySequence = VelocitySequence() + + previousNoteStartTime = -1 + + for note in noteSequence: + + interOnsetInterval = note.startTime - previousNoteStartTime + #ignore note if it is part of a chord... + if interOnsetInterval!=0: + velocitySequence += [0]*(interOnsetInterval-1) + velocitySequence += [note.velocity] + + previousNoteStartTime = note.startTime + + if timespanTicks!=None: + velocitySequence += [0]*(timespanTicks - len(velocitySequence)) + else: + velocitySequence += [0]*(noteSequence[-1].duration-1) + + # normalising velocity sequence between 0-1 + if max(velocitySequence)>0: + velocitySequence = VelocitySequence([float(v)/max(velocitySequence) for v in velocitySequence]) + + return velocitySequence + + +class BarList(list): + def append(self,bar): + if(len(self)>0): + bar.set_previous_bar(self[-1]) + self[-1].set_next_bar(bar) + super(BarList, self).append(bar) + + def concat(self, barList): + while(len(barList)!=0): + localbar = barList[0] + self.append(localbar) + barList.remove(localbar) + + def to_string(self, sequenceType="y"): + + output = "" + + for bar in self: + prev = bar.get_previous_bar() + + params = "t"+sequenceType + + if prev!=None and prev.get_time_signature()==bar.get_time_signature(): + params = "-"+params + + output += " " + bar.to_string(params) + + return output + +class Bar: + def __init__(self, rhythmSequence, timeSignature, ticksPerQuarter=None, qpmTempo=None, nextBar=None, prevBar=None): + if isinstance(rhythmSequence, NoteSequence): + self.noteSequence = rhythmSequence + self.velocitySequence = None + elif isinstance(rhythmSequence, VelocitySequence): + self.velocitySequence = rhythmSequence + self.noteSequence = None + + if isinstance(timeSignature, basestring): + self.timeSignature = TimeSignature(timeSignature) + else: + self.timeSignature = timeSignature + + if ticksPerQuarter==None: + self.tpq = len(self.get_velocity_sequence())*self.timeSignature.get_denominator()/(4*self.timeSignature.get_numerator()) + else: + self.tpq = ticksPerQuarter + + self.qpm = qpmTempo + + + + self.nextBar = nextBar + self.prevBar = prevBar + + def get_note_sequence(self): + if self.noteSequence == None: + nextbarVelocitySequence = None + if self.nextBar != None: + nextbarVelocitySequence = self.nextBar.get_velocity_sequence() + self.noteSequence = velocity_sequence_to_note_sequence(self.velocitySequence, nextbarVelocitySequence) + return self.noteSequence + + def get_velocity_sequence(self): + if self.velocitySequence == None: + self.velocitySequence = note_sequence_to_velocity_sequence(self.noteSequence, self.get_bar_ticks()) + return self.velocitySequence + + def get_binary_sequence(self): + return ceiling(self.get_velocity_sequence()) + + def get_next_bar(self): + return self.nextBar + + def get_previous_bar(self): + return self.prevBar + + def set_next_bar(self, bar): + self.nextBar = bar + + def set_previous_bar(self, bar): + self.prevBar = bar + + def get_subdivision_sequence(self): + return self.timeSignature.get_subdivision_sequence() + + def get_beat_level(self): + return self.timeSignature.get_beat_level() + + def get_time_signature(self): + return self.timeSignature + + # return the length of a bar in time units (ticks) + def get_bar_ticks(self): + return calculate_bar_ticks(self.timeSignature.get_numerator(),self.timeSignature.get_denominator(), self.tpq) + + def is_empty(self): + if max(self.get_velocity_sequence())>0: + return False + else: + return True + + def to_string(self, sequenceType="ty"): + + # prev = self.get_previous_bar() + # if prev!=None: + # if prev.get_time_signature()==self.get_time_signature(): + # output="" + output = "" + + if "-t" not in sequenceType: + output = "t{"+self.timeSignature.to_string()+"}" + + if "v" in sequenceType: + output += "v{"+self.get_velocity_sequence().to_string()+"}" + else: + output += "y{"+self.get_note_sequence().to_string()+"}" + + return output + + +class TimeSignature(): + def __init__(self, inputString): + if inputString in parameter_setter.read_time_signature(): + self.tsString = inputString + else: + print "Error: undefined time-signature: ", inputString + raise NullTimeSignatureError + + def get_subdivision_sequence(self): + return parameter_setter.timeSignatureBase[self.tsString][0] + + def get_beat_level(self): + return parameter_setter.timeSignatureBase[self.tsString][1] + + def get_numerator(self): + return int(self.tsString.split('/')[0]) + + def get_denominator(self): + return int(self.tsString.split('/')[1]) + + def to_string(self): + return self.tsString + +