@ -87,17 +87,44 @@ def lilyfy(string):
string = string . replace ( ' " ' , ' \\ " ' )
return string
def fromTemplate ( session , templateFile , data , meta , tempoStaff ) :
def fromTemplate ( session , data , meta , tempoStaff ) :
""" Returns a string built from already ly-exported track data and a lilypond template.
Called by score . lilypond ( ) , which is called by session . lilypond ( ) .
A template is either one of the built - ins " foo.ly " or
if the templateFile is None / " " the current filename + ly is used : " bar.lbj.ly "
Laborejo Markers in the template have the syntax % $ $ DATE $ $ . That is pretty unique and additionaly a lilypond
comment .
meta is the actual score . metaData dictionary , not a copy . We use this to modify the template
path entry .
Laborejo Markers in the template have the syntax % $ $ DATE $ $ .
That is pretty unique and additionally a lilypondcomment .
The template file is in metaData [ " template-file " ] . The default is empty string ,
which means we use the programs " default.ly " template .
For session management reasons this the user template must be a file in the session dir .
However , a system wide user library of lilypond export templates is very useful and convenient .
Thus we allow absolute paths as well . Or even relative and ~ / if the user wants . They will be
converted automatically to a symlink into the session dir and the absolute path will be
auto - replaced by the local filename to the symlink . ( The absolute path will remain in metadata
and gui field until the file is found . Thus a typo will not lead to a broken symlink
creation )
If template file lookup fails for any reason we use the internal default . ly and log an error
message .
"""
#Load the template
templatePath = findTemplate ( session , templateFile )
#Find and load the template
templateFile = meta [ " template-file " ]
try :
templatePath = findTemplate ( session , meta , templateFile )
except FileNotFoundError : #Fall back to default.py and try again
logger . error ( f " User lilypond template { templateFile } not found. Will use the builtin default.ly instead. " )
templatePath = findTemplate ( session , meta , " " ) #If this fails something is indeed wrong and we let the error raise
except PermissionError : #Fall back to default.py and try again
logger . error ( f " User lilypond template { templateFile } not readable. Will use the builtin default.ly instead. " )
templatePath = findTemplate ( session , meta , " " ) #If this fails something is indeed wrong and we let the error raise
#Now we know the templatePath exists and it is either default.ly or a file/link in our session dir.
with open ( templatePath , ' r ' ) as f :
templateString = f . read ( )
@ -109,27 +136,39 @@ def fromTemplate(session, templateFile, data, meta, tempoStaff):
templateString = templateString . replace ( " % $$VOICES$$ " , voicesString )
templateString = templateString . replace ( " % $$STRUCTURE$$ " , structureString )
templateString = templateString . replace ( " % $$TEMPOSTAFF$$ " , tempoStaff )
templateString = templateString . replace ( " % $$TRANSPOSITION$$ " , ' \\ transpose ' + " " . join ( meta [ " transposition " ] . split ( ) ) ) #something like "c' f". Defaults to "c c ". Lilypond output without ""!
return templateString
def findTemplate ( session , templateFile : str = None ) - > str :
""" returns a path. checks for existence.
There are two options :
- Use a standard template in SHARE / lilypondTemplates
- Use a template that belongs to the save file .
The one that belongs to the save file needs to be created by hand by the user .
If not we throw a FileNotFoundError """
if templateFile :
path = os . path . join ( PATHS [ " share " ] , " lilypondTemplates " , templateFile )
else :
path = os . path . join ( session . sessionPrefix , " template.laborejo2.ly " ) #the name is always the same because the sessionPrefix is the unqiue part
assert path . endswith ( " .ly " )
if os . path . exists ( path ) :
return path
else :
raise FileNotFoundError ( templateFile )
def findTemplate ( session , meta , templateFile : str ) - > str :
""" returns a path. checks for existence and read access through NSMclient functionality.
This will create a symlink in our session dir and always use this . It will also destructively
change the user metadata to this symlink file , if present . """
if not templateFile :
path = os . path . join ( PATHS [ " share " ] , " lilypondTemplates " , " default.ly " )
return path #we don't need the checks below for our own file
#User provided a template file name or path
#Our NSM client can safely import any file. If we try to "import" a file already in our session dir nothing bad will happen, we just use the file.
assert session . nsmClient . importResource
logger . info ( " Trying to use user provided ly template: " + templateFile )
#This can throw FileNotFoundError or PermissionError, which we catch in the parent function. No need to check for ourselves again here.
#We get just the filename for symlinks in our session dir. Quickly check that and adjust to absolute path.
templateFile = os . path . expanduser ( templateFile ) # ~home
if os . path . basename ( templateFile ) == templateFile :
templateFile = os . path . join ( session . sessionPrefix , templateFile )
#no need to check. even if that fails it will be caught safely below and reported to the log
path = session . nsmClient . importResource ( templateFile ) #it will always be an absolute path. Check the nsm INFO log.
meta [ " template-file " ] = os . path . basename ( path )
logger . info ( " Imported or re-used: " + path )
return path
def processData ( data ) :
""" returns two strings. the first actual music data, VOICES, the second the structure and order,