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))

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to