No instrument names in instrument score, they are already in the title/header!
[orchestrallily.git] / generate_oly_score.py
blob924bdda80ae5252c5464a4f107a2f90f6d53cd7e
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
11 import subprocess
13 program_name = 'generate_oly_score'
14 settings_file = 'oly_structure.def'
15 output_dir = ''
16 script_path = os.path.dirname(__file__)
17 basename = ""
19 settings_files = []
20 src_files = []
21 score_files = []
22 tex_files = []
24 ######################################################################
25 # Options handling
26 ######################################################################
28 help_text = r"""Usage: %(program_name)s [OPTIONS]... [DEF-FILE]
29 Create a complete file structure for a score using OrchestralLily.
30 If no definitions file it given, the file oly_structure.def is used
32 Options:
33 -h, --help print this help
34 -o, --output=NAME write tely doc to NAME (default: read from settings or current directory)
35 """
37 def help (text):
38 sys.stdout.write ( text)
39 sys.exit (0)
41 (options, files) = getopt.getopt (sys.argv[1:], 'ho:',
42 ['help', 'output='])
44 for opt in options:
45 o = opt[0]
46 a = opt[1]
47 if o == '-h' or o == '--help':
48 help (help_text % vars ())
49 #elif o == '-s' or o == '--settings':
50 #settings_file = a
51 elif o == '-o' or o == '--output':
52 output_dir = a
53 else:
54 raise Exception ('unknown option: ' + o)
56 if files:
57 settings_file = files[0]
60 ######################################################################
61 # Settings loading
62 ######################################################################
64 def load_settings (file_name):
65 global output_dir, basename;
66 try:
67 in_f = open (file_name)
68 s = in_f.read()
69 in_f.close()
70 settings_expr = eval(s);
71 except IOError:
72 print ("Unable to load settings file '%s'. Exiting..." % file_name)
73 exit (-1);
74 except SyntaxError as ex:
75 print ex;
76 print ("Unable to interpret settings file '%s', it's syntax is invalid. Exiting..." % file_name);
77 exit (-1);
79 basename = settings_expr.get ("basename", "Score")
80 if not output_dir:
81 output_dir = settings_expr.get ("output_dir", output_dir) + "/";
82 return settings_expr;
85 ######################################################################
86 # File Writing
87 ######################################################################
89 def write_file (file_name, contents):
90 fn = file_name
91 if os.path.exists (file_name):
92 fn += ".new"
94 dir = os.path.dirname (fn);
95 if not os.path.exists (dir):
96 os.mkdir (dir)
98 try:
99 out_f = open (fn, "w")
100 s = out_f.write(contents)
101 out_f.close()
102 except IOError:
103 print ("Unable to write to output file '%s'. Exiting..." % fn)
104 exit (-1);
106 # If the file already existed, check if the new file is identical.
107 if (fn != file_name):
108 patchfile = os.path.join (dir, "patches", os.path.basename(file_name) + ".patch")
109 if os.path.exists (patchfile):
110 #print ("Trying to apply patch %s" % patchfile)
111 try:
112 #retcode = subprocess.call(["patch ", fn, patchfile], shell=True)
113 retcode = subprocess.call("patch -Ns \""+ fn+ "\" \"" + patchfile + "\"", shell=True)
114 if retcode < 0:
115 print >>sys.stderr, "Unable to apply patch to file \"", fn, "\"."
116 #else:
117 #print >>sys.stderr, "Child returned", retcode
118 except OSError, e:
119 print >>sys.stderr, "Execution failed:", e
120 #else:
121 #print ("Unable to find patch %s" % patchfile)
123 if filecmp.cmp (fn, file_name):
124 os.unlink (fn);
125 else:
126 print ("A file %s already existed, created new file %s." % (os.path.basename(file_name), os.path.basename(fn)))
130 ######################################################################
131 # Templates
132 ######################################################################
134 def init_replacements (settings):
135 rep = settings.copy ();
136 del rep["parts"];
137 del rep["instruments"];
138 del rep["lyrics"];
139 del rep["scores"];
141 return rep
144 ######################################################################
145 # Templates
146 ######################################################################
148 template_names = {
149 "Makefile": "Makefile",
151 "movement": "TEMPLATE_Include_Movement.ily",
152 "snippet_def_lyrics": "TEMPLATE_Snippet_DefinitionLyrics.ily",
153 "snippet_def_music": "TEMPLATE_Snippet_DefinitionMusic.ily",
154 "snippet_def_include": "TEMPLATE_Snippet_DefinitionInclude.ily",
156 "settings": "TEMPLATE_Settings.ily",
157 "settings_global": "TEMPLATE_Settings_Global.ily",
158 "settings_fullscore": "TEMPLATE_Settings_FullScore.ily",
159 "settings_instrument": "TEMPLATE_Settings_Instrument.ily",
160 "settings_vocal": "TEMPLATE_Settings_Vocal.ily",
162 "snippet_part_score": "TEMPLATE_Snippet_PartScore.ily",
164 "score_full": "TEMPLATE_Score_FullScore.ly",
165 "score_instrument": "TEMPLATE_Score_Instrument.ly",
166 "score_vocal": "TEMPLATE_Score_VocalVoice.ly",
168 "itex_settings": "TEXTEMPLATE_Settings.itex",
169 "itex_about": "TEXTEMPLATE_Include_About.itex",
170 "itex_contents": "TEXTEMPLATE_Include_ContentsMaterial.itex",
171 "itex_leben": "TEXTEMPLATE_Include_Leben.itex",
172 "itex_text": "TEXTEMPLATE_Include_Text.itex",
174 "itex_todo": "TEXTEMPLATE_Include_Todo.itex",
175 "itex_preface_long": "TEXTEMPLATE_Include_Preface_Long.itex",
176 "itex_preface_short": "TEXTEMPLATE_Include_Preface_Short.itex",
178 "itex_coverpage": "TEXTEMPLATE_Include_Coverpage.itex",
179 "itex_backpage": "TEXTEMPLATE_Include_Backpage.itex",
181 "itex_kritbericht": "TEXTEMPLATE_Include_KritBericht.itex",
182 "tex_score": "TEXTEMPLATE_Score.tex",
183 "tex_instruments": "TEXTEMPLATE_Score_Instruments.tex",
185 "itex_snippet_textmovement": "TEXTEMPLATE_Snippet_TextMovement.itex",
186 "itex_snippet_kritbericht": "TEXTEMPLATE_Snippet_KritBericht_Movement.itex",
187 "itex_snippet_material": "TEXTEMPLATE_Snippet_Material_Score.itex",
188 "itex_snippet_instrument": "TEXTEMPLATE_Snippet_Instrument.itex",
191 def load_file (file_name):
192 s = False;
193 try:
194 in_f = open (file_name, "rb")
195 s = in_f.read()
196 in_f.close()
197 except IOError:
198 print ("Unable to load file %s" % file_name);
199 return s
201 def load_templates (settings):
202 templates = {};
203 template_path = script_path + "/Templates/";
205 for id in template_names:
206 filename = template_names[id]
207 s = load_file (template_path + filename);
208 if s:
209 templates[id] = s
210 else:
211 print ("Unable to load template file %s (id %s).\n" % (filename, id));
212 return templates;
215 ######################################################################
216 # Creating settings files
217 ######################################################################
219 def write_settings_file (fn, contents):
220 write_file (fn, contents );
221 settings_files.append (fn)
223 def generate_settings_files (settings, templates, replacements):
224 inc = "";
225 for m in src_files:
226 replacements["filename"] = m
227 inc += (templates["snippet_def_include"] % replacements)
228 del replacements["filename"];
229 replacements["includefiles"] = inc
231 write_settings_file (output_dir + basename + "_Settings.ily", templates["settings"] % replacements );
232 write_file (output_dir + basename + "_Settings_Global.ily", templates["settings_global"] % replacements );
234 if (settings.get("scores", [])):
235 write_settings_file (output_dir + basename + "_Settings_FullScore.ily", templates["settings_fullscore"] % replacements );
236 if (settings.get("instruments", [])):
237 write_settings_file (output_dir + basename + "_Settings_Instrument.ily", templates["settings_instrument"] % replacements );
238 else:
239 print ("WARNING: No instruments: %s" % settings.get("instruments", []));
240 if (settings.get("lyrics", [])):
241 write_settings_file (output_dir + basename + "_Settings_Vocal.ily", templates["settings_vocal"] % replacements );
242 del replacements["includefiles"]
245 ######################################################################
246 # Creating movement files
247 ######################################################################
249 def generate_movement_files (settings, templates, replacements):
250 movements = settings.get ("parts", []);
251 instruments = settings.get ("instruments", []);
252 lyrics = settings.get ("lyrics", []);
253 if (movements == {}):
254 print ("No parts defined in settings file...");
255 exit (-1);
256 if (instruments == []):
257 print ("No instruments defined in settings file...");
258 exit (-1);
260 for m in movements:
261 filename_ext = ""
262 if type (m) == dict:
263 name = m.get ("name", "TODO")
264 filename_ext = m.get ("filename", name)
265 replacements["movement"] = name
266 replacements["movementname"] = m.get ("piece", name)
267 replacements["movementtacet"] = m.get ("piecetacet", replacements["movementname"] + " tacet")
268 elif type(m) == str:
269 filename_ext = m
270 replacements["movement"] = m
271 replacements["movementname"] = m
272 replacements["movementtacet"] = (m + " tacet")
273 else:
274 print ("Type of movement entry %s is not a dict or a string" % m)
275 continue
277 defs = ""
278 for i in instruments:
279 replacements["instrument"] = i
280 defs += (templates["snippet_def_music"] % replacements);
281 if (i in lyrics):
282 defs += (templates["snippet_def_lyrics"] % replacements);
283 del replacements["instrument"]
284 replacements["movementinstrumentdefinitions"] = defs
285 fn = basename + "_Music_" + filename_ext + ".ily"
286 write_file (output_dir + fn, templates["movement"] % replacements);
287 src_files.append (fn)
288 del replacements["movement"]
289 del replacements["movementname"]
290 del replacements["movementtacet"]
293 ######################################################################
294 # Creating instrumental score files
295 ######################################################################
297 def generate_instrument_files (settings, templates, replacements):
298 movements = settings.get ("parts", []);
299 instruments = settings.get ("instruments", []);
300 lyrics = settings.get ("lyrics", []);
302 for i in instruments:
303 replacements["instrument"] = i
304 defs = ""
305 for m in movements:
306 if type(m) == dict:
307 replacements["movement"] = m.get ("name", "TODO")
308 replacements["movementname"] = m.get ("piece", replacements["movement"])
309 else:
310 replacements["movement"] = m
311 replacements["movementname"] = m
312 defs += (templates["snippet_part_score"] % replacements);
313 del replacements["movement"]
314 del replacements["movementname"]
315 replacements["partlist"] = defs
316 if i in lyrics:
317 template = "score_vocal"
318 else:
319 template = "score_instrument"
320 fn = output_dir + basename + "_Instrument_" + i + ".ly"
321 write_file (fn, templates[template] % replacements);
322 score_files.append (fn)
323 del replacements["instrument"]
326 ######################################################################
327 # Creating score files
328 ######################################################################
331 score_names = {
332 "ParticellScore": "Particell",
335 def generate_score_files (settings, templates, replacements):
336 movements = settings.get ("parts",[]);
337 scores = settings.get ("scores", []);
339 for i in scores:
340 sn = (i + "Score")
341 replacements["score"] = score_names.get (sn, sn)
342 replacements["instrument"] = replacements["score"]
343 defs = ""
344 for m in movements:
345 if type(m) == dict:
346 replacements["movement"] = m.get ("name", "TODO")
347 replacements["movementname"] = m.get ("piece", replacements["movement"])
348 else:
349 replacements["movement"] = m
350 replacements["movementname"] = m
351 defs += (templates["snippet_part_score"] % replacements);
352 del replacements["movement"]
353 del replacements["movementname"]
354 replacements["partlist"] = defs
355 filename = output_dir + basename + "_Score_" + i + ".ly";
356 if i == "":
357 filename = output_dir + basename + "_Score.ly"
358 write_file (filename, templates["score_full"] % replacements);
359 score_files.append (filename)
360 del replacements["score"]
361 del replacements["instrument"]
364 ######################################################################
365 # Creating LaTeX files
366 ######################################################################
368 def write_tex_file (fn, contents):
369 write_file (output_dir + "/"+ fn, contents );
370 tex_files.append (fn)
372 def generate_tex_files (settings, templates, replacements):
373 write_tex_file ("TeX_" + basename + "_Settings.itex", templates["itex_settings"] % replacements);
374 write_tex_file ("TeX_" + basename + "_Include_Coverpage.itex", templates["itex_coverpage"] % replacements);
375 write_tex_file ("TeX_" + basename + "_Include_Backpage.itex", templates["itex_backpage"] % replacements);
376 write_tex_file ("TeX_" + basename + "_Include_About.itex", templates["itex_about"] % replacements);
377 write_tex_file ("TeX_" + basename + "_Include_Leben.itex", templates["itex_leben"] % replacements);
378 write_tex_file ("TeX_" + basename + "_Include_Todo.itex", templates["itex_todo"] % replacements);
379 write_tex_file ("TeX_" + basename + "_Include_Preface_Long.itex", templates["itex_preface_long"] % replacements);
380 write_tex_file ("TeX_" + basename + "_Include_Preface_Short.itex", templates["itex_preface_short"] % replacements);
382 txt = ""
383 kb = ""
384 for m in settings.get ("parts",[]):
385 if type(m) == dict:
386 replacements["movement"] = m.get ("name", "TODO")
387 replacements["movementname"] = m.get ("piece", replacements["movement"])
388 else:
389 replacements["movement"] = m
390 replacements["movementname"] = m
391 txt += (templates["itex_snippet_textmovement"] % replacements);
392 kb += (templates["itex_snippet_kritbericht"] % replacements);
393 del replacements["movement"]
394 del replacements["movementname"]
395 replacements["movementtexts"] = txt
396 replacements["kritbericht_movements"] = kb
397 write_tex_file ("TeX_" + basename + "_Include_Text.itex", templates["itex_text"] % replacements);
398 write_tex_file ("TeX_" + basename + "_Include_KritBericht.itex", templates["itex_kritbericht"] % replacements);
399 del replacements["movementtexts"]
400 del replacements["kritbericht_movements"]
402 ### Contents and Material:
403 lst = ""
404 for i in settings.get ("scores", []):
405 replacements["type"] = i + "Score";
406 lst += templates["itex_snippet_material"] % replacements
407 replacements["type"] = "Instruments"
408 lst += templates["itex_snippet_material"] % replacements
409 for i in settings.get ("instruments", []):
410 replacements["type"] = i;
411 lst += templates["itex_snippet_material"] % replacements
412 del replacements["type"]
413 replacements["material_list"] = lst;
414 write_tex_file ("TeX_" + basename + "_Include_ContentsMaterial.itex", templates["itex_contents"] % replacements);
415 del replacements["material_list"]
417 ### Score files
418 for s in settings.get ("scores", []):
419 replacements["scoretype"] = s;
420 write_tex_file ("TeX_" + basename + "_Score_" + s + ".tex", templates["tex_score"] % replacements);
421 del replacements["scoretype"];
423 ### Orchestra material
424 replacements["scoretype"] = "InstrumentalParts"
425 lst = ""
426 for i in settings.get ("instruments", []):
427 replacements["instrument"] = i
428 lst += templates["itex_snippet_instrument"] % replacements;
429 del replacements["instrument"]
430 replacements["instrumentscores"] = lst;
431 write_tex_file ("TeX_" + basename + "_Score_Instruments.tex", templates["tex_instruments"] % replacements);
432 del replacements["instrumentscores"];
436 ######################################################################
437 # Creating Make files
438 ######################################################################
440 def generate_make_files (settings, templates, replacements):
441 movements = settings.get ("parts", {});
443 replacements["instruments"] = string.join (settings.get ("instruments", []));
444 replacements["scores"] = string.join (settings.get ("scores", []))## + " Instruments";
445 replacements["srcfiles"] = string.join (src_files);
447 write_file (output_dir + "Makefile", templates["Makefile"] % replacements);
449 del replacements["instruments"]
450 del replacements["scores"]
451 del replacements["srcfiles"]
452 return;
455 ######################################################################
456 # Link the orchestrallily package
457 ######################################################################
459 def generate_oly_link (settings, templates, replacements):
460 print ("Creating symlink %s to %s" % ("orchestrallily/", script_path))
461 try:
462 os.symlink ("../"+script_path, output_dir+"orchestrallily")
463 except OSError:
464 pass
466 ######################################################################
467 # Main function
468 ######################################################################
470 settings = load_settings (settings_file);
471 templates = load_templates (settings);
472 replacements = init_replacements (settings);
474 generate_movement_files (settings, templates, replacements);
475 generate_settings_files (settings, templates, replacements);
476 generate_instrument_files (settings, templates, replacements);
477 generate_score_files (settings, templates, replacements);
478 generate_tex_files (settings, templates, replacements);
479 generate_make_files (settings, templates, replacements);
480 generate_oly_link (settings, templates, replacements);