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