annotate Syncopation models/rhythm_parser.py @ 40:6371e8f21f7d

updating the syncopation functions to fix a few problems
author christopherh <christopher.harte@eecs.qmul.ac.uk>
date Thu, 23 Apr 2015 15:46:58 +0100
parents cc38b3047ed9
children
rev   line source
csong@9 1 '''
csong@35 2 Authors: Chunyang Song, Christopher Harte
csong@9 3 Institution: Centre for Digital Music, Queen Mary University of London
csong@9 4 '''
csong@9 5
csong@9 6 # Parse the rhythm file and return a list of Bar objects
christopher@29 7 #Piece = []
csong@9 8
csong@20 9 from parameter_setter import timeSignatureBase
christopher@29 10 from music_objects import *
csong@9 11
csong@9 12 comment_sign = '#'
christopher@38 13
christopher@29 14 def discard_comments(line):
csong@9 15 if comment_sign in line:
csong@9 16 line = line[0:line.find(comment_sign)]
csong@9 17 return line
csong@9 18
christopher@29 19 def discard_spaces(line):
csong@9 20 line = line.replace(" ", '').replace("\t", '')
csong@9 21 return line
csong@9 22
christopher@40 23 def discard_linereturns(line):
christopher@40 24 line = line.replace("\n","").replace("\r","")
christopher@40 25 return line
christopher@40 26
christopher@40 27
csong@35 28 # def extractInfo(line):
csong@35 29 # try:
csong@35 30 # if '{' not in line and '}' not in line:
csong@35 31 # raise RhythmSyntaxError(line)
csong@35 32 # else:
csong@35 33 # return line[line.find('{')+1 : line.find('}')]
csong@35 34 # except RhythmSyntaxError:
csong@35 35 # print 'Rhythmic information needs to be enclosed by "{" and "}"'
csong@9 36
christopher@29 37
christopher@29 38 def read_rhythm(fileName):
christopher@29 39 fileContent = file(fileName)
christopher@29 40
christopher@29 41 barList = BarList()
christopher@29 42
christopher@29 43 tempo=None
christopher@29 44 timeSignature=None
christopher@29 45 ticksPerQuarter=None
christopher@29 46
christopher@29 47 # for each line in the file, parse the line and add any
christopher@29 48 # new bars to the main bar list for the piece
christopher@29 49 for line in fileContent:
christopher@29 50
christopher@29 51 # ignore the line if it's only a comment
christopher@29 52 if is_comment(line) or line=="\n":
christopher@29 53 continue
christopher@29 54
christopher@29 55 # if time signature has not yet been set then it should be the first
christopher@29 56 # thing we find in a file after the comments at the top
christopher@29 57 if timeSignature==None:
christopher@29 58 (field, line) = get_next_field(line)
christopher@29 59 # if there is a valid field, it should be a time signature
christopher@29 60 if field!=None:
christopher@29 61 [fieldname,value] = field
christopher@40 62 if fieldname.lower()=="t":
christopher@29 63 timeSignature = TimeSignature(value)
christopher@29 64 else:
christopher@29 65 print 'Error, first field in the file should set the time signature.'
christopher@29 66
christopher@29 67 # parse the line
christopher@29 68 (newbarlist, tempo, timeSignature, ticksPerQuarter) = parse_line(line, timeSignature, tempo, ticksPerQuarter)
christopher@29 69
christopher@29 70 # if we found some bars in this line then add them to the overall bar list
christopher@29 71 if len(newbarlist)>0:
christopher@29 72 barList.concat(newbarlist)
christopher@29 73
christopher@29 74 return barList
christopher@29 75
christopher@29 76 def is_comment(line):
csong@35 77 if discard_spaces(line)[0]==comment_sign:
christopher@29 78 return True
christopher@29 79 else:
christopher@29 80 return False
christopher@29 81
christopher@29 82 def parse_line(line, timeSignature=None, tempo=None, ticksPerQuarter=None):
christopher@29 83
christopher@40 84 #strip the line of line returns, spaces and comments
christopher@40 85 line = discard_linereturns(discard_spaces(discard_comments(line)))
christopher@29 86
christopher@29 87 bars = BarList()
christopher@29 88
christopher@29 89 #work through each field in the line
christopher@29 90 while len(line)>0:
christopher@29 91 (field, line) = get_next_field(line)
christopher@29 92
christopher@29 93 if field!=None:
christopher@29 94
christopher@29 95 [fieldname, value] = field
christopher@29 96
christopher@29 97 if fieldname.lower() == "v":
christopher@29 98 #velocity sequence
christopher@29 99 bar = Bar(VelocitySequence(value),timeSignature, ticksPerQuarter, tempo)
christopher@29 100 bars.append(bar)
christopher@29 101
christopher@29 102 elif fieldname.lower() == "y":
christopher@29 103 #note sequence
christopher@29 104 bar = Bar(NoteSequence(value), timeSignature, ticksPerQuarter, tempo)
christopher@29 105 bars.append(bar)
christopher@29 106
christopher@29 107 elif fieldname.lower() == "t":
christopher@29 108 #time signature
christopher@29 109 timeSignature = TimeSignature(value)
christopher@29 110
christopher@29 111 elif fieldname.lower() == "tpq":
christopher@29 112 #ticks per quarter
christopher@29 113 ticksPerQuarter = int(value)
christopher@29 114
christopher@29 115 elif fieldname.lower() == "qpm":
christopher@29 116 #tempo
christopher@29 117 tempo = int(value)
christopher@29 118
csong@9 119 else:
christopher@29 120 print 'Unrecognised field type: "' + fieldname + '"'
csong@9 121
christopher@29 122 return bars, tempo, timeSignature, ticksPerQuarter
csong@9 123
christopher@40 124 class RhythmSyntaxError(Exception):
christopher@40 125 def __init__(self, value):
christopher@40 126 self.value = value
christopher@40 127 def __str__(self):
christopher@40 128 return repr(self.value)
csong@9 129
christopher@29 130 def get_next_field(line):
christopher@29 131 index = line.find("}")
christopher@29 132 field = None
christopher@29 133 if index>=0:
christopher@29 134 fieldtext = line[:index]
christopher@29 135 line = line[index+1:]
christopher@29 136 field = fieldtext.split("{")
christopher@29 137 else:
christopher@29 138 print 'Error, incorrect syntax: "'+line+'"'
christopher@40 139 raise RhythmSyntaxError(line)
csong@9 140
christopher@29 141 return field,line
csong@9 142
csong@9 143
csong@9 144
csong@9 145
csong@9 146