FiguredBass settings: Allow figures above rests, define 100 to be implicit (=> extend...
[orchestrallily.git] / generate_oly_score.py
blob64e9b20ad1cda4b6047284916b8af60182d7d041
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 import sys
5 import os
6 import os.path
7 import getopt
8 import re
9 import filecmp
10 import string
12 program_name = 'generate_oly_score'
13 settings_file = 'oly_structure.def'
14 output_dir = ''
15 script_path = os.path.dirname(__file__)
16 basename = ""
18 settings_files = []
19 src_files = []
20 score_files = []
21 tex_files = []
23 ######################################################################
24 # Options handling
25 ######################################################################
27 help_text = r"""Usage: %(program_name)s [OPTIONS]... [DEF-FILE]
28 Create a complete file structure for a score using OrchestralLily.
29 If no definitions file it given, the file oly_structure.def is used
31 Options:
32 -h, --help print this help
33 -o, --output=NAME write tely doc to NAME (default: read from settings or current directory)
34 """
36 def help (text):
37 sys.stdout.write ( text)
38 sys.exit (0)
40 (options, files) = getopt.getopt (sys.argv[1:], 'ho:',
41 ['help', 'output='])
43 for opt in options:
44 o = opt[0]
45 a = opt[1]
46 if o == '-h' or o == '--help':
47 help (help_text % vars ())
48 #elif o == '-s' or o == '--settings':
49 #settings_file = a
50 elif o == '-o' or o == '--output':
51 output_dir = a
52 else:
53 raise Exception ('unknown option: ' + o)
55 if files:
56 settings_file = files[0]
59 ######################################################################
60 # Settings loading
61 ######################################################################
63 def load_settings (file_name):
64 global output_dir, basename;
65 try:
66 in_f = open (file_name)
67 s = in_f.read()
68 in_f.close()
69 settings_expr = eval(s);
70 except IOError:
71 print ("Unable to load settings file '%s'. Exiting..." % file_name)
72 exit (-1);
73 except SyntaxError as ex:
74 print ex;
75 print ("Unable to interpret settings file '%s', it's syntax is invalid. Exiting..." % file_name);
76 exit (-1);
78 basename = settings_expr.get ("basename", "Score")
79 if not output_dir:
80 output_dir = settings_expr.get ("output_dir", output_dir) + "/";
81 return settings_expr;
84 ######################################################################
85 # File Writing
86 ######################################################################
88 def write_file (file_name, contents):
89 fn = file_name
90 if os.path.exists (file_name):
91 fn += ".new"
93 dir = os.path.dirname (fn);
94 if not os.path.exists (dir):
95 os.mkdir (dir)
97 try:
98 out_f = open (fn, "w")
99 s = out_f.write(contents)
100 out_f.close()
101 except IOError:
102 print ("Unable to write to output file '%s'. Exiting..." % fn)
103 exit (-1);
105 # If the file already existed, check if the new file is identical.
106 if (fn != file_name):
107 if filecmp.cmp (fn, file_name):
108 os.unlink (fn);
109 else:
110 print ("A file %s already existed, created new file %s." % (file_name, fn))
114 ######################################################################
115 # Templates
116 ######################################################################
118 def init_replacements (settings):
119 rep = settings.copy ();
120 del rep["parts"];
121 del rep["instruments"];
122 del rep["lyrics"];
123 del rep["scores"];
125 return rep
128 ######################################################################
129 # Templates
130 ######################################################################
132 template_names = {
133 "Makefile": "Makefile",
135 "movement": "TEMPLATE_Include_Movement.ily",
136 "snippet_def_lyrics": "TEMPLATE_Snippet_DefinitionLyrics.ily",
137 "snippet_def_music": "TEMPLATE_Snippet_DefinitionMusic.ily",
138 "snippet_def_include": "TEMPLATE_Snippet_DefinitionInclude.ily",
140 "settings": "TEMPLATE_Settings.ily",
141 "settings_global": "TEMPLATE_Settings_Global.ily",
142 "settings_fullscore": "TEMPLATE_Settings_FullScore.ily",
143 "settings_instrument": "TEMPLATE_Settings_Instrument.ily",
144 "settings_vocal": "TEMPLATE_Settings_Vocal.ily",
146 "snippet_part_score": "TEMPLATE_Snippet_PartScore.ily",
148 "score_full": "TEMPLATE_Score_FullScore.ly",
149 "score_instrument": "TEMPLATE_Score_Instrument.ly",
150 "score_vocal": "TEMPLATE_Score_VocalVoice.ly",
152 "itex_settings": "TEXTEMPLATE_Settings.itex",
153 "itex_about": "TEXTEMPLATE_Include_About.itex",
154 "itex_contents": "TEXTEMPLATE_Include_ContentsMaterial.itex",
155 "itex_leben": "TEXTEMPLATE_Include_Leben.itex",
156 "itex_text": "TEXTEMPLATE_Include_Text.itex",
157 "itex_kritbericht": "TEXTEMPLATE_Include_KritBericht.itex",
158 "tex_score": "TEXTEMPLATE_Score.tex",
159 "tex_instruments": "TEXTEMPLATE_Score_Instruments.tex",
161 "itex_snippet_textmovement": "TEXTEMPLATE_Snippet_TextMovement.itex",
162 "itex_snippet_kritbericht": "TEXTEMPLATE_Snippet_KritBericht_Movement.itex",
163 "itex_snippet_material": "TEXTEMPLATE_Snippet_Material_Score.itex",
164 "itex_snippet_instrument": "TEXTEMPLATE_Snippet_Instrument.itex",
167 def load_file (file_name):
168 s = False;
169 try:
170 in_f = open (file_name, "rb")
171 s = in_f.read()
172 in_f.close()
173 except IOError:
174 print ("Unable to load file %s" % file_name);
175 return s
177 def load_templates (settings):
178 templates = {};
179 template_path = script_path + "/Templates/";
181 for id in template_names:
182 filename = template_names[id]
183 s = load_file (template_path + filename);
184 if s:
185 templates[id] = s
186 else:
187 print ("Unable to load template file %s (id %s).\n" % (filename, id));
188 return templates;
191 ######################################################################
192 # Creating settings files
193 ######################################################################
195 def write_settings_file (fn, contents):
196 write_file (fn, contents );
197 settings_files.append (fn)
199 def generate_settings_files (settings, templates, replacements):
200 inc = "";
201 for m in src_files:
202 replacements["filename"] = m
203 inc += (templates["snippet_def_include"] % replacements)
204 del replacements["filename"];
205 replacements["includefiles"] = inc
207 write_settings_file (output_dir + basename + "_Settings.ily", templates["settings"] % replacements );
208 write_file (output_dir + basename + "_Settings_Global.ily", templates["settings_global"] % replacements );
210 if (settings.get("scores", [])):
211 write_settings_file (output_dir + basename + "_Settings_FullScore.ily", templates["settings_fullscore"] % replacements );
212 if (settings.get("instruments", [])):
213 write_settings_file (output_dir + basename + "_Settings_Instrument.ily", templates["settings_instrument"] % replacements );
214 else:
215 print ("WARNING: No instruments: %s" % settings.get("instruments", []));
216 if (settings.get("lyrics", [])):
217 write_settings_file (output_dir + basename + "_Settings_Vocal.ily", templates["settings_vocal"] % replacements );
218 del replacements["includefiles"]
221 ######################################################################
222 # Creating movement files
223 ######################################################################
225 def generate_movement_files (settings, templates, replacements):
226 movements = settings.get ("parts", []);
227 instruments = settings.get ("instruments", []);
228 lyrics = settings.get ("lyrics", []);
229 if (movements == {}):
230 print ("No parts defined in settings file...");
231 exit (-1);
232 if (instruments == []):
233 print ("No instruments defined in settings file...");
234 exit (-1);
236 for m in movements:
237 filename_ext = ""
238 if type (m) == dict:
239 name = m.get ("name", "TODO")
240 filename_ext = m.get ("filename", name)
241 replacements["movement"] = name
242 replacements["movementname"] = m.get ("piece", name)
243 replacements["movementtacet"] = m.get ("piecetacet", replacements["movementname"] + " tacet")
244 elif type(m) == str:
245 filename_ext = m
246 replacements["movement"] = m
247 replacements["movementname"] = m
248 replacements["movementtacet"] = (m + " tacet")
249 else:
250 print ("Type of movement entry %s is not a dict or a string" % m)
251 continue
253 defs = ""
254 for i in instruments:
255 replacements["instrument"] = i
256 defs += (templates["snippet_def_music"] % replacements);
257 if (i in lyrics):
258 defs += (templates["snippet_def_lyrics"] % replacements);
259 del replacements["instrument"]
260 replacements["movementinstrumentdefinitions"] = defs
261 fn = basename + "_Music_" + filename_ext + ".ily"
262 write_file (output_dir + fn, templates["movement"] % replacements);
263 src_files.append (fn)
264 del replacements["movement"]
265 del replacements["movementname"]
266 del replacements["movementtacet"]
269 ######################################################################
270 # Creating instrumental score files
271 ######################################################################
273 def generate_instrument_files (settings, templates, replacements):
274 movements = settings.get ("parts", []);
275 instruments = settings.get ("instruments", []);
276 lyrics = settings.get ("lyrics", []);
278 for i in instruments:
279 replacements["instrument"] = i
280 defs = ""
281 for m in movements:
282 if type(m) == dict:
283 replacements["movement"] = m.get ("name", "TODO")
284 replacements["movementname"] = m.get ("piece", replacements["movement"])
285 else:
286 replacements["movement"] = m
287 replacements["movementname"] = m
288 defs += (templates["snippet_part_score"] % replacements);
289 del replacements["movement"]
290 del replacements["movementname"]
291 replacements["partlist"] = defs
292 if i in lyrics:
293 template = "score_vocal"
294 else:
295 template = "score_instrument"
296 fn = output_dir + basename + "_Instrument_" + i + ".ly"
297 write_file (fn, templates[template] % replacements);
298 score_files.append (fn)
299 del replacements["instrument"]
302 ######################################################################
303 # Creating score files
304 ######################################################################
306 def generate_score_files (settings, templates, replacements):
307 movements = settings.get ("parts",[]);
308 scores = settings.get ("scores", []);
310 for i in scores:
311 replacements["score"] = (i + "Score")
312 replacements["instrument"] = replacements["score"]
313 defs = ""
314 for m in movements:
315 if type(m) == dict:
316 replacements["movement"] = m.get ("name", "TODO")
317 replacements["movementname"] = m.get ("piece", replacements["movement"])
318 else:
319 replacements["movement"] = m
320 replacements["movementname"] = m
321 defs += (templates["snippet_part_score"] % replacements);
322 del replacements["movement"]
323 del replacements["movementname"]
324 replacements["partlist"] = defs
325 filename = output_dir + basename + "_Score_" + i + ".ly";
326 if i == "":
327 filename = output_dir + basename + "_Score.ly"
328 write_file (filename, templates["score_full"] % replacements);
329 score_files.append (filename)
330 del replacements["score"]
331 del replacements["instrument"]
334 ######################################################################
335 # Creating LaTeX files
336 ######################################################################
338 def write_tex_file (fn, contents):
339 write_file (output_dir + "/"+ fn, contents );
340 tex_files.append (fn)
342 def generate_tex_files (settings, templates, replacements):
343 write_tex_file ("TeX_" + basename + "_Settings.itex", templates["itex_settings"] % replacements);
344 write_tex_file ("TeX_" + basename + "_Include_About.itex", templates["itex_about"] % replacements);
345 write_tex_file ("TeX_" + basename + "_Include_Leben.itex", templates["itex_leben"] % replacements);
346 txt = ""
347 kb = ""
348 for m in settings.get ("parts",[]):
349 if type(m) == dict:
350 replacements["movement"] = m.get ("name", "TODO")
351 replacements["movementname"] = m.get ("piece", replacements["movement"])
352 else:
353 replacements["movement"] = m
354 replacements["movementname"] = m
355 txt += (templates["itex_snippet_textmovement"] % replacements);
356 kb += (templates["itex_snippet_kritbericht"] % replacements);
357 del replacements["movement"]
358 del replacements["movementname"]
359 replacements["movementtexts"] = txt
360 replacements["kritbericht_movements"] = kb
361 write_tex_file ("TeX_" + basename + "_Include_Text.itex", templates["itex_text"] % replacements);
362 write_tex_file ("TeX_" + basename + "_Include_KritBericht.itex", templates["itex_kritbericht"] % replacements);
363 del replacements["movementtexts"]
364 del replacements["kritbericht_movements"]
366 ### Contents and Material:
367 lst = ""
368 for i in settings.get ("scores", []):
369 replacements["type"] = i + "Score";
370 lst += templates["itex_snippet_material"] % replacements
371 replacements["type"] = "Instruments"
372 lst += templates["itex_snippet_material"] % replacements
373 for i in settings.get ("instruments", []):
374 replacements["type"] = i;
375 lst += templates["itex_snippet_material"] % replacements
376 del replacements["type"]
377 replacements["material_list"] = lst;
378 write_tex_file ("TeX_" + basename + "_Include_ContentsMaterial.itex", templates["itex_contents"] % replacements);
379 del replacements["material_list"]
381 ### Score files
382 for s in settings.get ("scores", []):
383 replacements["scoretype"] = s;
384 write_tex_file ("TeX_" + basename + "_Score_" + s + ".tex", templates["tex_score"] % replacements);
385 del replacements["scoretype"];
387 ### Orchestra material
388 replacements["scoretype"] = "InstrumentalParts"
389 lst = ""
390 for i in settings.get ("instruments", []):
391 replacements["instrument"] = i
392 lst += templates["itex_snippet_instrument"] % replacements;
393 del replacements["instrument"]
394 replacements["instrumentscores"] = lst;
395 write_tex_file ("TeX_" + basename + "_Score_Instruments.tex", templates["tex_instruments"] % replacements);
396 del replacements["instrumentscores"];
400 ######################################################################
401 # Creating Make files
402 ######################################################################
404 def generate_make_files (settings, templates, replacements):
405 movements = settings.get ("parts", {});
407 replacements["instruments"] = string.join (settings.get ("instruments", []));
408 replacements["scores"] = string.join (settings.get ("scores", []))## + " Instruments";
409 replacements["srcfiles"] = string.join (src_files);
411 write_file (output_dir + "Makefile", templates["Makefile"] % replacements);
413 del replacements["instruments"]
414 del replacements["scores"]
415 del replacements["srcfiles"]
416 return;
419 ######################################################################
420 # Link the orchestrallily package
421 ######################################################################
423 def generate_oly_link (settings, templates, replacements):
424 print ("Creating symlink %s to %s" % ("orchestrallily/", script_path))
425 try:
426 os.symlink ("../"+script_path, output_dir+"orchestrallily")
427 except OSError:
428 pass
430 ######################################################################
431 # Main function
432 ######################################################################
434 settings = load_settings (settings_file);
435 templates = load_templates (settings);
436 replacements = init_replacements (settings);
438 generate_movement_files (settings, templates, replacements);
439 generate_settings_files (settings, templates, replacements);
440 generate_instrument_files (settings, templates, replacements);
441 generate_score_files (settings, templates, replacements);
442 generate_tex_files (settings, templates, replacements);
443 generate_make_files (settings, templates, replacements);
444 generate_oly_link (settings, templates, replacements);