christopher@45: ''' christopher@45: Authors: Chunyang Song, Christopher Harte christopher@45: Institution: Centre for Digital Music, Queen Mary University of London christopher@45: ''' christopher@45: christopher@45: # Parse the rhythm file and return a list of Bar objects christopher@45: #Piece = [] christopher@45: christopher@45: from parameter_setter import timeSignatureBase christopher@45: from music_objects import * christopher@45: christopher@45: comment_sign = '#' christopher@45: christopher@45: def discard_comments(line): christopher@45: if comment_sign in line: christopher@45: line = line[0:line.find(comment_sign)] christopher@45: return line christopher@45: christopher@45: def discard_spaces(line): christopher@45: line = line.replace(" ", '').replace("\t", '') christopher@45: return line christopher@45: christopher@45: def discard_linereturns(line): christopher@45: line = line.replace("\n","").replace("\r","") christopher@45: return line christopher@45: christopher@45: christopher@45: # def extractInfo(line): christopher@45: # try: christopher@45: # if '{' not in line and '}' not in line: christopher@45: # raise RhythmSyntaxError(line) christopher@45: # else: christopher@45: # return line[line.find('{')+1 : line.find('}')] christopher@45: # except RhythmSyntaxError: christopher@45: # print 'Rhythmic information needs to be enclosed by "{" and "}"' christopher@45: christopher@45: christopher@45: def read_rhythm(fileName): christopher@45: fileContent = file(fileName) christopher@45: christopher@45: barList = BarList() christopher@45: christopher@45: tempo=None christopher@45: timeSignature=None christopher@45: ticksPerQuarter=None christopher@45: christopher@45: # for each line in the file, parse the line and add any christopher@45: # new bars to the main bar list for the piece christopher@45: for line in fileContent: christopher@45: christopher@45: # ignore the line if it's only a comment christopher@45: if is_comment(line) or line=="\n": christopher@45: continue christopher@45: christopher@45: # if time signature has not yet been set then it should be the first christopher@45: # thing we find in a file after the comments at the top christopher@45: if timeSignature==None: christopher@45: (field, line) = get_next_field(line) christopher@45: # if there is a valid field, it should be a time signature christopher@45: if field!=None: christopher@45: [fieldname,value] = field christopher@45: if fieldname.lower()=="t": christopher@45: timeSignature = TimeSignature(value) christopher@45: else: christopher@45: print 'Error, first field in the file should set the time signature.' christopher@45: christopher@45: # parse the line christopher@45: (newbarlist, tempo, timeSignature, ticksPerQuarter) = parse_line(line, timeSignature, tempo, ticksPerQuarter) christopher@45: christopher@45: # if we found some bars in this line then add them to the overall bar list christopher@45: if len(newbarlist)>0: christopher@45: barList.concat(newbarlist) christopher@45: christopher@45: return barList christopher@45: christopher@45: def is_comment(line): christopher@45: if discard_spaces(line)[0]==comment_sign: christopher@45: return True christopher@45: else: christopher@45: return False christopher@45: christopher@45: def parse_line(line, timeSignature=None, tempo=None, ticksPerQuarter=None): christopher@45: christopher@45: #strip the line of line returns, spaces and comments christopher@45: line = discard_linereturns(discard_spaces(discard_comments(line))) christopher@45: christopher@45: bars = BarList() christopher@45: christopher@45: #work through each field in the line christopher@45: while len(line)>0: christopher@45: (field, line) = get_next_field(line) christopher@45: christopher@45: if field!=None: christopher@45: christopher@45: [fieldname, value] = field christopher@45: christopher@45: if fieldname.lower() == "v": christopher@45: #velocity sequence christopher@45: bar = Bar(VelocitySequence(value),timeSignature, ticksPerQuarter, tempo) christopher@45: bars.append(bar) christopher@45: christopher@45: elif fieldname.lower() == "y": christopher@45: #note sequence christopher@45: bar = Bar(NoteSequence(value), timeSignature, ticksPerQuarter, tempo) christopher@45: bars.append(bar) christopher@45: christopher@45: elif fieldname.lower() == "t": christopher@45: #time signature christopher@45: timeSignature = TimeSignature(value) christopher@45: christopher@45: elif fieldname.lower() == "tpq": christopher@45: #ticks per quarter christopher@45: ticksPerQuarter = int(value) christopher@45: christopher@45: elif fieldname.lower() == "qpm": christopher@45: #tempo christopher@45: tempo = int(value) christopher@45: christopher@45: else: christopher@45: print 'Unrecognised field type: "' + fieldname + '"' christopher@45: christopher@45: return bars, tempo, timeSignature, ticksPerQuarter christopher@45: christopher@45: class RhythmSyntaxError(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: def get_next_field(line): christopher@45: index = line.find("}") christopher@45: field = None christopher@45: if index>=0: christopher@45: fieldtext = line[:index] christopher@45: line = line[index+1:] christopher@45: field = fieldtext.split("{") christopher@45: else: christopher@45: print 'Error, incorrect syntax: "'+line+'"' christopher@45: raise RhythmSyntaxError(line) christopher@45: christopher@45: return field,line christopher@45: christopher@45: christopher@45: christopher@45: christopher@45: