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
|
csong@35
|
23 # def extractInfo(line):
|
csong@35
|
24 # try:
|
csong@35
|
25 # if '{' not in line and '}' not in line:
|
csong@35
|
26 # raise RhythmSyntaxError(line)
|
csong@35
|
27 # else:
|
csong@35
|
28 # return line[line.find('{')+1 : line.find('}')]
|
csong@35
|
29 # except RhythmSyntaxError:
|
csong@35
|
30 # print 'Rhythmic information needs to be enclosed by "{" and "}"'
|
csong@9
|
31
|
christopher@29
|
32
|
christopher@29
|
33 def read_rhythm(fileName):
|
christopher@29
|
34 fileContent = file(fileName)
|
christopher@29
|
35
|
christopher@29
|
36 barList = BarList()
|
christopher@29
|
37
|
christopher@29
|
38 tempo=None
|
christopher@29
|
39 timeSignature=None
|
christopher@29
|
40 ticksPerQuarter=None
|
christopher@29
|
41
|
christopher@29
|
42 # for each line in the file, parse the line and add any
|
christopher@29
|
43 # new bars to the main bar list for the piece
|
christopher@29
|
44 for line in fileContent:
|
christopher@29
|
45
|
christopher@29
|
46 # ignore the line if it's only a comment
|
christopher@29
|
47 if is_comment(line) or line=="\n":
|
christopher@29
|
48 continue
|
christopher@29
|
49
|
christopher@29
|
50 # if time signature has not yet been set then it should be the first
|
christopher@29
|
51 # thing we find in a file after the comments at the top
|
christopher@29
|
52 if timeSignature==None:
|
christopher@29
|
53 (field, line) = get_next_field(line)
|
christopher@29
|
54 # if there is a valid field, it should be a time signature
|
christopher@29
|
55 if field!=None:
|
christopher@29
|
56 [fieldname,value] = field
|
christopher@29
|
57 if fieldname=="t":
|
christopher@29
|
58 timeSignature = TimeSignature(value)
|
christopher@29
|
59 else:
|
christopher@29
|
60 print 'Error, first field in the file should set the time signature.'
|
christopher@29
|
61
|
christopher@29
|
62 # parse the line
|
christopher@29
|
63 (newbarlist, tempo, timeSignature, ticksPerQuarter) = parse_line(line, timeSignature, tempo, ticksPerQuarter)
|
christopher@29
|
64
|
christopher@29
|
65 # if we found some bars in this line then add them to the overall bar list
|
christopher@29
|
66 if len(newbarlist)>0:
|
christopher@29
|
67 barList.concat(newbarlist)
|
christopher@29
|
68
|
christopher@29
|
69 return barList
|
christopher@29
|
70
|
christopher@29
|
71 def is_comment(line):
|
csong@35
|
72 if discard_spaces(line)[0]==comment_sign:
|
christopher@29
|
73 return True
|
christopher@29
|
74 else:
|
christopher@29
|
75 return False
|
christopher@29
|
76
|
christopher@29
|
77 def parse_line(line, timeSignature=None, tempo=None, ticksPerQuarter=None):
|
christopher@29
|
78
|
christopher@29
|
79 #strip the line of spaces and comments
|
christopher@29
|
80 line = discard_spaces(discard_comments(line)).replace("\n","")
|
christopher@29
|
81
|
christopher@29
|
82 bars = BarList()
|
christopher@29
|
83
|
christopher@29
|
84 #work through each field in the line
|
christopher@29
|
85 while len(line)>0:
|
christopher@29
|
86 (field, line) = get_next_field(line)
|
christopher@29
|
87
|
christopher@29
|
88 if field!=None:
|
christopher@29
|
89
|
christopher@29
|
90 [fieldname, value] = field
|
christopher@29
|
91
|
christopher@29
|
92 if fieldname.lower() == "v":
|
christopher@29
|
93 #velocity sequence
|
christopher@29
|
94 bar = Bar(VelocitySequence(value),timeSignature, ticksPerQuarter, tempo)
|
christopher@29
|
95 bars.append(bar)
|
christopher@29
|
96
|
christopher@29
|
97 elif fieldname.lower() == "y":
|
christopher@29
|
98 #note sequence
|
christopher@29
|
99 bar = Bar(NoteSequence(value), timeSignature, ticksPerQuarter, tempo)
|
christopher@29
|
100 bars.append(bar)
|
christopher@29
|
101
|
christopher@29
|
102 elif fieldname.lower() == "t":
|
christopher@29
|
103 #time signature
|
christopher@29
|
104 timeSignature = TimeSignature(value)
|
christopher@29
|
105
|
christopher@29
|
106 elif fieldname.lower() == "tpq":
|
christopher@29
|
107 #ticks per quarter
|
christopher@29
|
108 ticksPerQuarter = int(value)
|
christopher@29
|
109
|
christopher@29
|
110 elif fieldname.lower() == "qpm":
|
christopher@29
|
111 #tempo
|
christopher@29
|
112 tempo = int(value)
|
christopher@29
|
113
|
csong@9
|
114 else:
|
christopher@29
|
115 print 'Unrecognised field type: "' + fieldname + '"'
|
csong@9
|
116
|
christopher@29
|
117 return bars, tempo, timeSignature, ticksPerQuarter
|
csong@9
|
118
|
csong@9
|
119
|
christopher@29
|
120 def get_next_field(line):
|
christopher@29
|
121 index = line.find("}")
|
christopher@29
|
122 field = None
|
christopher@29
|
123 if index>=0:
|
christopher@29
|
124 fieldtext = line[:index]
|
christopher@29
|
125 line = line[index+1:]
|
christopher@29
|
126 field = fieldtext.split("{")
|
christopher@29
|
127 else:
|
christopher@29
|
128 print 'Error, incorrect syntax: "'+line+'"'
|
christopher@29
|
129 #raise RhythmSyntaxError(line)
|
csong@9
|
130
|
christopher@29
|
131 return field,line
|
csong@9
|
132
|
csong@9
|
133
|
csong@9
|
134
|
csong@9
|
135
|
csong@9
|
136
|