#!/usr/bin/python3.4 ## Generate pdf form lilypond file ## by using standard command ## ## Most of programming was done by Sven Axelsson, http://svenax.net/ import codecs, os from argparse import ArgumentParser class MakeDrum: LILYPOND = 'lilypond' VERSION = '0.9.5' TMP_DIR = os.path.join(os.path.abspath(os.curdir),'tmp') TMP_PREFIX = 'tmp_' MASTER_DIR = os.path.dirname(os.path.abspath(__file__)) RUN_DIR = os.path.abspath(os.curdir) def __init__(self): parser = ArgumentParser(__file__) parser.add_argument('--version', action='version', version=self.VERSION) parser.add_argument('--lilyversion', action='store_true', dest='show_lilyversion', default=False, help='show Lilypond version and exit') # options for inclusion of files parser.add_argument('-x', '--drumfile', dest='lilydrum', default='lilydrum.ly', help='Use the specified file for drums') parser.add_argument('-c', '--pipefile', dest='lilypipe', default='bagpipe.ly', help='Use the specified file for pipes') parser.add_argument('-i', '--include', dest='includes', nargs='*', default=[],action='append', help='Include the specified file for compiling') # options for lilypond parser.add_argument('-p', '--paper-size', dest='papersize', default='a4', help='Paper size. Default: A4') parser.add_argument('-o', '--orientation', dest='orientation', default='landscape', help='Paper orientation. Default: landscape') parser.add_argument('-s', '--staff-size', dest='staffsize', default='20', help='Staff size. Default: 20pt.') parser.add_argument('-w', '--view-spacing', action='store_const', dest='view_spacing', default='##f', const='##t', help='Turn on "Paper.annotatespacing".') parser.add_argument('-l', '--line-break', action='store_const', dest='line_break', default='##t', const='##f', help='Turn off explicit linebreaks".') # options for generating and compiling parser.add_argument('-g','--generated', dest='gen_out', default=self.TMP_DIR, help='Put generated lilyfiles in $gen_out') parser.add_argument('--no-compile', action='store_false', dest='compile', default=True, help='Do not compile generated Lilypond files') parser.add_argument('--no-log', action='store_false', dest='log', default=True, help='Do not generate log files.') parser.add_argument('--no-cleanup', action='store_false', dest='clean', default=True, help='Leave all temporary files in place') parser.add_argument('-d', '--out_dir', dest='out_dir', default='pdf', help='Output dir for the lilypond process. If it doesn\'t exist, try to create it') # the file(s) to process parser.add_argument('music_file', default='', nargs='*', help='file to process') parser.add_argument('-@', '--list_file', dest='list_file', default='', help='file containing the list of files to process') self.args = parser.parse_args() if self.args.show_lilyversion: print(os.system(self.LILYPOND+' --version')) return # Input files if self.args.list_file != '': self.args.music_file.append(open(self.args.list_file, 'r').readlines()) close(self.args.list_file) # Check if there are any files if not self.args.music_file: parser.print_usage() return # Check for inclusion options self.args.includes = [el for elements in self.args.includes for el in elements] # Whether to clean up tmp_dir if possible self.remove_tmp_dir = self.args.clean # are TMP_DIR, out_dir dirs? if not os.path.exists(self.TMP_DIR): try: os.makedirs(self.TMP_DIR) except: print('Seems like no temporary directory can be created') return if not os.path.exists(self.args.out_dir): try: os.makedirs(self.args.out_dir) except: print('Seems like no output directory can be created') return # do the work! for file_path in self.args.music_file: self.process_it(file_path) #if dir is empty: #os.rmdir(self.TMP_DIR) def process_it(self, file): tmp_file = self.maketemplate(file) if self.args.gen_out is not None and self.args.gen_out != self.TMP_DIR: new_tmp_file = os.path.basename(tmp_file).replace(self.TMP_PREFIX, ''); print ('Moving ', tmp_file, ' to ', new_tmp_file, end=' ', flush=True) gen_dir = os.path.join(self.RUN_DIR, self.args.gen_out); # if not dir $gen_out, make it if not os.path.exists(gen_dir): try: os.makedirs(gen_dir) except: print('[Error]') print(' ! Seems like the {} directory cannot be created'.format(gen_dir)) return # mv file to dir, remove self.TMP_PREFIX os.rename(tmp_file, os.path.join(gen_dir, new_tmp_file)) tmp_file = new_tmp_file print('[OK]') if self.args.compile: if self.args.log: logfile = os.path.join(self.TMP_DIR, os.path.relpath(file).replace(".ly", '').replace('/', '-')+'.log') log = ' > '+logfile+' 2>&1' else: log = '' print ('Compiling ', file, end=' ', flush=True) if not self.args.log: print() lilyout = os.path.join(self.args.out_dir, os.path.basename(tmp_file).replace(self.TMP_PREFIX, '').replace(".ly", '')) print (lilyout) lilycmd = self.LILYPOND+' --pdf --output='+lilyout+' '+tmp_file+log if os.system(lilycmd) != 0: self.remove_tmp_dir = False print ('[Error]') if self.args.log: print (' ! Did not compile, please see the log at ', logfile) else : print ('[OK]') if self.args.clean: #remove files if self.args.log: os.remove(logfile) os.remove(tmp_file) def maketemplate(self, file): lily_includes = '' include_drum_file = False include_pipe_file = False # find out whether drum, pipes, or full score for ext in ['full', 'side', 'tenor', 'bass', 'drum', 'snare']: if ext in file: include_drum_file = True break for ext in ['full', 'pipes']: if ext in file: include_pipe_file = True break if include_drum_file: self.args.includes.insert(0,self.args.lilydrum) if include_pipe_file: self.args.includes.insert(0, self.args.lilypipe) for f in self.args.includes: lily_includes = lily_includes + "\n\\include \"{}\"".format(f) # Set up a tmp file with template and file combined tmp_file = self.TMP_PREFIX + os.path.relpath(file).replace('/', '-').replace('..', '').replace('//','').lstrip('-') tmp_file = os.path.join(self.TMP_DIR, tmp_file) out_file = codecs.open(tmp_file, 'w+', 'utf8') out_file.write(u'\ufeff') # Write the file out_file.write( u"""% Generated from {filename} by {script} Version {version} \\version "2.18.0" #(ly:set-option 'point-and-click #f) {lily_includes} #(set-global-staff-size {staffsize}) #(set-default-paper-size \"{papersize}\" '{orientation}) \\paper {{ annotatespacing = {view_spacing} }} \layout {{ \context {{ \Score {{ \override NonMusicalPaperColumn #'line-break-permission = {line_break} }} }} }} % The tune to generate. """.format( filename=file, script=__file__, version=self.VERSION, lily_includes=lily_includes, staffsize=self.args.staffsize, papersize=self.args.papersize, orientation=self.args.orientation, view_spacing=self.args.view_spacing, line_break=self.args.line_break ) ) # Read lily file into tmp file music = codecs.open(file, 'r', 'utf8').read() if music.startswith(u'\ufeff'): music = music[1:] music = music.split(u'\n') printit = 1 for line in music: if line.startswith(u'\\include'): if line.startswith(u'\\include "lilydrum.ly"'): continue if line.startswith(u'\\include "bagpipe.ly"'): continue # Rewrite includes to absolute location of file incline = line.replace('\\include', '').strip('"\' ') if not incline.startswith('\\'): #already absolute incline = os.path.join(os.path.abspath(os.path.dirname(file)), incline) line = "\\include \""+incline+"\"" if printit: out_file.write(line.replace('\r', '')+'\n') out_file.close() # Return tmp_file_path return tmp_file if __name__ == "__main__": MakeDrum();