Hello Eef, if I understand you correctly you essentially want to put the content of a Lilypond file into a variable and evaluate that. This is not possible with Lilypond as such, but instead you can avoid Lilypond syntax and directly use the scheme hooks.
Instead of doing
all = ...
you can have a scheme function do
(set! all ...)
(but for this to work you need to have the binding "all" existing before by
doing #(define all #f) (or any other value).
Instead of simply creating a \score ... and let the parser delegate this to
the correct hook you can pass scores directly via scheme by doing
(add-score #{ \score { ... } #})
Generally there are many ways to do things, and we’d need to know more about
your specific situation to be able to elaborate a good solution.
Recently I did a mass for which I created a small framework which allows me to
first register parts and such by doing
\registerPart partname
\partSetTitle partname "Title"
\partSetStaff partname staffname { music }
...
and then when needed do
\partPrint name layoutfunction
to create a specific score or
\printParts layoutfunction
to print all scores.
layoutfunction is then a function taking partname and creating the desired
score.
I’d then have a folder "layouts" specifying layout functions, a folder
"styles" specifying stylesheets, and a folder of files registering scores, and
one or multiple masters reading these files and printing scores with one or
multiple layout functions.
I’ve included the core library and an example layout function. Maybe this
approach could be useful for you (I’ve also sent this to the list not too long
ago).
Cheers,
Valentin
Am Freitag, 7. April 2023, 16:11:43 CEST schrieb Eef Weenink:
> I have this project: I make arrangements of figured bass pieces.
> (Generalbass Wolf). In total 100 pieces. Uptill now I organised it this
> way:
> - 1 file with all pieces in it (I did about 10, 90 to go).
> The file starts with an include of a startup.ily, with some settings for the
> whole book then the first piece.
> I include a file (arrangeit.ily) to change the music into several voices,
> etcetera using arranger.ly<http://arranger.ly>. I add some lines to change
> 1-2 voices a bit using also arranger.ly<http://arranger.ly> then I include
> a file (Generalbassmakescore.ily with the settings to create the score.
> Second piece (with the same variablenames!)
> and repeat the includes like mentioned above.
> etcetera.
>
> It works, looks well. At the end I have 1 file with alle the pieces and 3-4
> files to do small jobs, It is not fast.
>
> But somehow I have the idea this could be easier/better. But how?
> - One idea would be to put all pieces in separate files and include this in
> one file with all jobs: arranging, extra changes, create voice/score. But
> then I will have 101 files
>
> Most easy would be to create a file with procedures I need, include the file
> and call the procedures when needed. . But how? Lilypond does not have
> procedures (as far I know?). Using functions gives lots of errors.
> I tried it with variables, but no luck either.
>
> I try to put these lines in a variable/function/procedures (as an example):
> What to do, to make lilypond use the lines between {} simply as a
> replacement of the variable?
>
> arrangeit = {
> %----- verwerking-------
> all = #'(pright pleft soprano alto tenor bass viola contrabas soprano)
> #(init all)
>
> #(begin
> ;;pianopartij
> (rm 'pright '(1-4) (rel 1 'melody) )
> (rm 'pleft '(1-4) (rel 'bassline) )
>
> ;; koorpartijen
> ;; sopraan
> (rm 'soprano '(1-4) (note 1 (rel 'melody) ))
> ;;alt
> (rm 'alto '(1-4) (note 2 (rel 1 'melody)) )
> ;; tenor
> (rm 'tenor '(1-4) (note 3 (rel 1 'melody) ))
> ;; bass
> (rm 'bass '(1-4) (rel 'bassline) )
> ;;ciontrabass
> (rm 'contrabas ' (1-4) (rel 'bassline) )
> )
> }
>
> Eef
\include "../lib/send-to-context.ily"
% Layout function for a full-score
#(define (full-score partname)
#{
\score {
\header {
title = \partGetTitle #partname
}
\layout { }
\midi { }
<<
\new Devnull \partGetStaff #partname tempo
\partCreateStaff
\with {
instrumentName = \partGetStaffName "2 Flöten" #partname flöte
shortInstrumentName = \partGetShortStaffName "Fl." #partname flöte
%midiInstrument = flute
}
\accidentalStyle modern
#partname flöte
\new StaffGroup <<
\partCreateTwoStaff
\with {
instrumentName = \partGetStaffName "Trompeten" #partname
trompeten
shortInstrumentName = \partGetShortStaffName "Trp." #partname
trompeten
%midiInstrument = trumpet
}
\accidentalStyle modern
\with {
instrumentName = \partGetStaffName "Trompete I" #partname
trompeteI
shortInstrumentName = \partGetShortStaffName "Trp. I" #partname
trompeteI
%midiInstrument = trumpet
}
\accidentalStyle modern
\with {
instrumentName = \partGetStaffName "Trompete II" #partname
trompeteII
shortInstrumentName = \partGetShortStaffName "Trp. II" #partname
trompeteII
%midiInstrument = trumpet
}
\accidentalStyle modern
#partname trompeteI trompeteII
\partCreateStaff
\with {
instrumentName = \partGetStaffName "Tenorhorn" #partname
tenorhorn
shortInstrumentName = \partGetShortStaffName "Th." #partname
tenorhorn
%midiInstrument = trombone
\clef "treble_8"
}
\accidentalStyle modern
#partname tenorhorn
\partCreateTwoStaff
\with {
instrumentName = \partGetStaffName "Posaunen" #partname posaunen
shortInstrumentName = \partGetShortStaffName "Pos." #partname
posaunen
%midiInstrument = trombone
\clef bass
}
\accidentalStyle modern
\with {
instrumentName = \partGetStaffName "Posaune I" #partname posauneI
shortInstrumentName = \partGetShortStaffName "Pos. I" #partname
posauneI
%midiInstrument = trombone
\clef bass
}
\accidentalStyle modern
\with {
instrumentName = \partGetStaffName "Posaune II" #partname
posauneII
shortInstrumentName = \partGetShortStaffName "Pos. II" #partname
posauneII
%midiInstrument = trombone
\clef bass
}
\accidentalStyle modern
#partname posauneI posauneII
>>
\partCreateStaff
\with {
instrumentName = \partGetStaffName "Glockenspiel" #partname
glockenspiel
shortInstrumentName = \partGetShortStaffName "Glsp." #partname
glockenspiel
%midiInstrument = glockenspiel
}
\accidentalStyle modern
#partname glockenspiel
\partCreateStaff
\with {
instrumentName = \partGetStaffName "Xylophon" #partname xylophon
shortInstrumentName = \partGetShortStaffName "Xyl." #partname
xylophon
%midiInstrument = xylophone
}
\accidentalStyle modern
#partname xylophon
\new StaffGroup <<
\partCreateStaff
\with {
instrumentName = \partGetStaffName "Pauken" #partname pauken
shortInstrumentName = \partGetShortStaffName "Pk." #partname
pauken
%midiInstrument = timpani
\clef bass
}
\accidentalStyle modern
#partname pauken
\partCreateTwoDrumStaff
\with {
\override StaffSymbol.line-count = #1
instrumentName = \markup \center-column {
#(partGetStaffName "Triangel" partname 'triangel)
#(partGetStaffName "Zimbeln" partname 'zimbel)
}
shortInstrumentName = \markup \center-column {
#(partGetShortStaffName "Trgl." partname 'triangel)
#(partGetShortStaffName "Zimb." partname 'zimbel)
}
}
{ }
\with {
\override StaffSymbol.line-count = #1
instrumentName = \partGetStaffName "Triangel" #partname triangel
shortInstrumentName = \partGetShortStaffName "Trgl." #partname
triangel
}
{ }
\with {
\override StaffSymbol.line-count = #1
instrumentName = \partGetStaffName "Zimbeln" #partname zimbel
shortInstrumentName = \partGetShortStaffName "Zimb." #partname
zimbel
}
{ }
#partname triangel zimbel
>>
\partCreateCStaff
\with {
instrumentName = \partGetStaffName "" #partname cantus
shortInstrumentName = \partGetShortStaffName "" #partname cantus
%midiInstrument = "choir aahs"
}
\accidentalStyle modern
#partname cantus
\partFormatLyrics #partname cantus
\new ChoirStaff <<
\partCreateCStaff
\with {
instrumentName = \partGetStaffName "Sopran" #partname soprano
shortInstrumentName = \partGetShortStaffName "S." #partname
soprano
%midiInstrument = "choir aahs"
}
\accidentalStyle modern
#partname soprano
\partFormatLyrics #partname soprano
\partCreateCStaff
\with {
instrumentName = \partGetStaffName "Alt" #partname alto
shortInstrumentName = \partGetShortStaffName "A." #partname alto
%midiInstrument = "choir aahs"
}
\accidentalStyle modern
#partname alto
\partFormatLyrics #partname alto
\partCreateCStaff
\with {
instrumentName = \partGetStaffName "Tenor" #partname tenor
shortInstrumentName = \partGetShortStaffName "T." #partname tenor
%midiInstrument = "choir aahs"
\clef "treble_8"
}
\accidentalStyle modern
#partname tenor
\partFormatLyrics #partname tenor
\partCreateCStaff
\with {
instrumentName = \partGetStaffName "Bass" #partname bass
shortInstrumentName = \partGetShortStaffName "B." #partname bass
%midiInstrument = "choir aahs"
\clef bass
}
\accidentalStyle modern
#partname bass
\partFormatLyrics #partname bass
>>
\new PianoStaff \with {
systemStartDelimiter = #'SystemStartBar
} <<
\new PianoStaff \with {
instrumentName = \partGetStaffName "Orgel" #partname orgel
shortInstrumentName = \partGetShortStaffName "Org." #partname orgel
} \moveCenteredDynamics <<
\partCreateStaff %\with { midiInstrument = "church organ" }
\with { }
\accidentalStyle piano
#partname orgelright
\new Dynamics \with { \override VerticalAxisGroup.staff-affinity
= #CENTER } { }
\partCreateStaff %\with { midiInstrument = "church organ" }
\with { \clef bass }
#partname orgelleft
>>
\partCreateStaff
\with {
\clef bass
instrumentName = \partGetStaffName "P" #partname ped
shortInstrumentName = \partGetShortStaffName "P" #partname ped
}
\accidentalStyle modern
#partname orgelped
>>
>>
}
#})
% Given a nested alist sets a value by a path. Does not guaratee to mutate the alist!
#(define (nested-assoc-set! alist path value)
(if (null? path)
value
(assoc-set! alist (car path) (nested-assoc-set! (assoc-get (car path) alist '()) (cdr path) value))))
% Given a nested alist gets a value by a path
#(define* (nested-assoc-get alist path #:optional (default '()))
(if (null? path)
alist
(let ((q (assoc-get (car path) alist default)))
(if (list? q)
(nested-assoc-get q (cdr path) default)
q))))
% Container for our parts. An alist.
#(define parts
(if (defined? 'parts)
parts
'()))
% Assigns a new part to our container. Not strictly necessary, but sets the 'order property
registerPart =
#(define-void-function (partname) (symbol?)
(set! parts (assoc-set! parts partname (list (cons 'order (length parts))))))
% Assign the title as markup of a given part.
partSetTitle =
#(define-void-function (partname title) (symbol? markup?)
(set! parts (nested-assoc-set! parts (list partname 'title) title)))
% Return the title of a given part as markup
partGetTitle =
#(define-scheme-function (partname) (symbol?)
(nested-assoc-get parts (list partname 'title) #f))
% Add a (named) piece of music (such as flute, violin, ...) to a part
partSetStaff =
#(define-void-function (partname staff mus) (symbol? symbol? ly:music?)
(set! parts (nested-assoc-set! parts (list partname 'staves staff) mus)))
% Returns a (named) piece of music (such as flute, violin, ...) from a part
partGetStaff =
#(define-music-function (partname staff) (symbol? symbol?)
(ly:music-deep-copy
(nested-assoc-get parts (list partname 'staves staff) (empty-music))))
% Assign an instrument name to a staff
partSetStaffName =
#(define-void-function (partname staff name) (symbol? symbol? markup?)
(set! parts (nested-assoc-set! parts (list partname 'staff-names staff) name)))
% Returns the instrument name of a staff. May take a default value.
partGetStaffName =
#(define-scheme-function (default partname staff) ((markup? #f) symbol? symbol?)
(nested-assoc-get parts (list partname 'staff-names staff) default))
% Assign an instrument name to a staff
partSetShortStaffName =
#(define-void-function (partname staff name) (symbol? symbol? markup?)
(set! parts (nested-assoc-set! parts (list partname 'short-staff-names staff) name)))
% Returns the short instrument name of a staff. May take a default value.
partGetShortStaffName =
#(define-scheme-function (default partname staff) ((markup? #f) symbol? symbol?)
(if (or (not (defined? 'printShortInstrumentName)) printShortInstrumentName)
(nested-assoc-get parts (list partname 'short-staff-names staff) default)
empty-markup))
% Adds a new line of lyrics to a staff. May optionally specify
% an alist props to provide values such as 'associatedVoice (default: voice-... where ... is
% the name of the music.
partAddLyrics =
#(define-void-function (partname staff props mus) (symbol? symbol? (list? '()) ly:music?)
(set! parts (nested-assoc-set! parts
(list partname 'lyrics staff)
(cons `((lyrics . ,mus) . ,props)
(partGetLyrics partname staff)))))
% Returns the lyrics associated with staff. This is a list of
% alists with keys 'lyrics and optional keys specified during \partAddLyrics
partGetLyrics =
#(define-scheme-function (partname staff) (symbol? symbol?)
(nested-assoc-get parts (list partname 'lyrics staff) '()))
#(define (context-mod-or-procedure? x) (or (ly:context-mod? x) (procedure? x)))
% Creates Lyrics contexts for a staff. May optionally specify a
% context mod or a procedure taking the lyrics alist as argument and returning a context mod
partFormatLyrics =
#(define-music-function (with partname staff)
((context-mod-or-procedure? (ly:make-context-mod)) symbol? symbol?)
(make-music 'SimultaneousMusic
'elements
(map (lambda (x)
(let ((lyr (assoc-get 'lyrics x))
(assoc-voice (assoc-get 'associatedVoice x (format #f "voice-~a" staff)))
(thiswith (if (ly:context-mod? with) with (with x))))
#{ \new Lyrics \with #thiswith \lyricsto #assoc-voice $lyr #}))
(reverse (partGetLyrics partname staff)))))
% Assigns a global block to a part
partSetGlobal =
#(define-void-function (partname mus) (symbol? ly:music?)
(set! parts (nested-assoc-set! parts (list partname 'global) mus)))
% Returns the global block of a part
partGetGlobal =
#(define-music-function (partname) (symbol?)
(nested-assoc-get parts (list partname 'global) (empty-music)))
% Assigns a (choir) global block to a part
partSetCGlobal =
#(define-void-function (partname mus) (symbol? ly:music?)
(set! parts (nested-assoc-set! parts (list partname 'cglobal) mus)))
% Returns the (choir) global block of a part
partGetCGlobal =
#(define-music-function (partname) (symbol?)
(nested-assoc-get parts (list partname 'cglobal) (empty-music)))
#(define (empty-music? x)
(null? (ly:music-property x 'types)))
% Create a Staff from a staff. May optionally specify a context mod
% and a preparation block. Makes use of the global block
partCreateStaff =
#(define-music-function (with prep transp partname staffname)
((ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music)) (ly:pitch? (ly:make-pitch -1 0)) symbol? symbol?)
(let ((staff (partGetStaff partname staffname))
(tacet (and (defined? 'partTacet) partTacet)))
(if (not (empty-music? staff))
#{
\new Staff = #(format #f "staff-~a" staffname) \with #with
\transpose #transp c #(ly:music-deep-copy #{ { \partGetGlobal #partname #prep #staff } #})
#}
(if tacet
#{
\new Dynamics {
\mark "Tacet" r1
}
#}
(empty-music)))))
% Create a two voice Staff from a staff. May optionally specify a context mod
% and a preparation block. Makes use of the global block
partCreateTwoStaff =
#(define-music-function (with prep with1 prep1 with2 prep2 partname staffname1 staffname2)
((ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music))
(ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music))
(ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music))
symbol? symbol? symbol?)
(let ((staff1 (partGetStaff partname staffname1))
(staff2 (partGetStaff partname staffname2)))
(if (empty-music? staff1)
(partCreateStaff with2 prep2 partname staffname2)
(if (empty-music? staff2)
(partCreateStaff with1 prep1 partname staffname1)
#{
\new Staff = #(format #f "staff-~a-~a" staffname1 staffname2) \with #with
{
\partGetGlobal #partname #prep
\partCombine #staff1 #staff2
}
#}))))
% Create a (choir) Staff from staff. May optionally specify a context mod
% and a preparation block. Makes use of the (choir) global block
partCreateCStaff =
#(define-music-function (with prep partname staffname)
((ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music)) symbol? symbol?)
(let ((staff (partGetStaff partname staffname)))
(if (not (empty-music? staff))
#{
\new Staff = #(format #f "staff-~a" staffname) \with #with
\new Voice = #(format #f "voice-~a" staffname)
{ \partGetGlobal #partname \partGetCGlobal #partname #prep #staff }
#}
(empty-music))))
% Create a Rhythmic Staff from a staff. May optionally specify a context mod
% and a preparation block. Makes use of the global block
partCreateRhythmicStaff =
#(define-music-function (with prep partname staffname)
((ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music)) symbol? symbol?)
(let ((staff (partGetStaff partname staffname))
(tacet (and (defined? 'partTacet) partTacet)))
(if (not (empty-music? staff))
#{
\new RhythmicStaff = #(format #f "staff-~a" staffname) \with #with
{ \partGetGlobal #partname #prep #staff }
#}
(if tacet
#{
\new Staff \with {
#with
\override StaffSymbol.line-count = #0
\remove Clef_engraver
\remove Time_signature_engraver
\remove Bar_engraver
} {
\override MultiMeasureRest.stencil =
#(lambda (grob) (ly:stencil-aligned-to (grob-interpret-markup grob "(Tacet)") Y CENTER))
R1
}
#}
(empty-music)))))
% Create a Drum Staff from a staff. May optionally specify a context mod
% and a preparation block. Makes use of the global block
partCreateDrumStaff =
#(define-music-function (with prep partname staffname)
((ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music)) symbol? symbol?)
(let ((staff (partGetStaff partname staffname)))
(if (not (empty-music? staff))
#{
\new DrumStaff = #(format #f "staff-~a" staffname) \with #with
{ \partGetGlobal #partname #prep #staff }
#}
(empty-music))))
% Create a two voice Drum Staff from a staff. May optionally specify a context mod
% and a preparation block. Makes use of the global block
partCreateTwoDrumStaff =
#(define-music-function (with prep with1 prep1 with2 prep2 partname staffname1 staffname2)
((ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music))
(ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music))
(ly:context-mod? (ly:make-context-mod)) (ly:music? (empty-music))
symbol? symbol? symbol?)
(let ((staff1 (partGetStaff partname staffname1))
(staff2 (partGetStaff partname staffname2)))
(if (empty-music? staff1)
(partCreateDrumStaff with2 prep2 partname staffname2)
(if (empty-music? staff2)
(partCreateDrumStaff with1 prep1 partname staffname1)
#{
\new DrumStaff = #(format #f "staff-~a-~a" staffname1 staffname2) \with #with
{
\partGetGlobal #partname #prep
<<
{ \override NoteHead.staff-position = #1 #staff1 } \\
{ \override NoteHead.staff-position = #-1 #staff2 }
>>
}
#}))))
% Create a score from a part name and a layout function.
partPrint =
#(define-scheme-function (partname layout) (symbol? procedure?)
(layout partname))
% Print selection of parts of all parts using a layout function.
printParts =
#(define-void-function (sel layout)
((list? #f) procedure?)
(if (not sel)
(set! sel
(map car
(sort parts
(lambda (x y)
(< (assoc-get 'order (cdr x))
(assoc-get 'order (cdr y))))))))
(map (lambda (x) (add-score (partPrint x layout))) sel))
signature.asc
Description: This is a digitally signed message part.
