Or here a version that also handles book-parts.

> 
> > Is there a (relatively) simple way to extract and print individual parts 
from
> 
> a
> 
> > completed score?
> > 
> > I couldn't find any tutorials. A "start to finish" list of instructions 
> > would
> 
> be
> 
> > nice; does one exist?
> 
> The common way is of course to define modular parts and combine them to
> different scores (which I guess can be a bit much when creating parts for many
> scores.
> 
> I suppose it would be possible to  override the toplevel-book-handler 
function
> to extract a part from all scores within one book.
> 
> I have appended a small working example of this. While technically involved
> something like this could of course make creating parts just a matter of
> defining the parts, and the rest is done automatically.
> 
> Cheers,
> Tina

% Mode of part extraction. Use 'SINGLE_PART to extract only a single part (define the corresponding key in the
% part variable). PARTS will create a book for each defined part, PARTS+TOTAL will also create a full (unfiltered)
% score.
%
% MODE = #'SINGLE_PART, MODE = #'PARTS+TOTAL, MODE = #'PARTS
MODE = #'PARTS+TOTAL

% List of contexts that are filtered.
HANDLE_CONTEXTS = #'(Staff Lyrics Dynamics)
% If #f the excluded contexts are not removed, but turned into Devnull contexts. This way events can still be
% captured by higher contexts (e.g. time changes in just one instrument).
REMOVE_FILTERED = ##t

% Define the parts by an alist of key -> list of used context ids
partlist.partI = #'("staff1")
partlist.partII = #'("staff2" "staff3")
partlist.partIII = #'("staff4")

% Define (optional) instrument names for each part
partnames.partI = "Part 1"
partnames.partII = "Part 2"
partnames.partIII = "Part 3"

% Define an optional alist of individual paper for each part
papers = #(list)
% Define an optional alist of indivdual layouts for each part
layouts = #(list)

% In caste MODE is 'SINGLE_PART define the used key
part = #'partI

%%% Change book handler to filter scores contained in books. Depending on MODE the book is kept as is or new books
%%% (for each part) will be generated. This function reuses the previously set value of toplevel-book-handler, so it
%%% can be combined with custom logic.
$(set!
  toplevel-book-handler
  (let* ((original-book-handler toplevel-book-handler)
         (score-handler
          (lambda (part score)
            (define (mute-staves music)
              (let ((elt (ly:music-property music 'element))
                    (elts (ly:music-property music 'elements)))
                (if (and (equal? (ly:music-property music 'name) 'ContextSpeccedMusic)
                         (member (ly:music-property music 'context-type) HANDLE_CONTEXTS)
                         (not (member (ly:music-property music 'context-id 'Staff) (assoc-get part partlist))))
                    (if REMOVE_FILTERED
                        (set! music (empty-music))
                        (ly:music-set-property! music 'context-type 'Devnull)))
                (if (not (null? elt)) (ly:music-set-property! music 'element (mute-staves elt)))
                (ly:music-set-property! music 'elements (map mute-staves elts))
                music))

            (let* ((music (mute-staves (keepWithTag part (ly:music-deep-copy (ly:score-music score)))))
                   (new-score (ly:make-score music)))
              (if (not (null? (ly:score-header score)))
                  (ly:score-set-header! new-score (ly:module-copy (ly:score-header score))))
              (for-each
               (lambda (def) (ly:score-add-output-def! new-score (ly:module-copy def)))
               (reverse (ly:score-output-defs score)))
              (if (assoc-get part layouts)
                  (ly:score-add-output-def! new-score (ly:module-copy (assoc-get part layouts))))
              new-score)))
         (book-part-handler
          (lambda (part book)
            (let*
             ((scores (ly:book-scores book))
              (header (ly:book-header book))
              (paper (ly:output-def-clone (assoc-get part papers (ly:book-paper book))))
              (parsed-scores
               (map (lambda (s) (if (ly:score? s) (score-handler part s) s)) scores))
              (new-book #f))
             (if header
                 (set! header (ly:module-copy header)))
             (if (and (assoc-get part partnames) (> (length scores) 0))
                 (begin
                  (if (not header)
                      (set! header #{ \header { } #}))
                  (module-define! header 'instrument (assoc-get part partnames))))
             (set! new-book (ly:make-book paper header '()))
             (if (or (null? scores) (not (null? (car scores))) (not (null? (car scores))))
                 (for-each (lambda (s) (ly:book-add-score! new-book s)) (reverse parsed-scores)))
             new-book)))
         (book-handler
          (lambda (part)
            (lambda (book)
              (let*
               ((parts (ly:book-book-parts book))
                (new-book (book-part-handler part book))
                (paper (ly:book-paper new-book)))
               (for-each (lambda (bp) (ly:book-add-bookpart! new-book (book-part-handler part bp)))
                         (reverse parts))
               (ly:output-def-set-variable! paper 'output-suffix (format #f "~a" part))
               (original-book-handler new-book))))))
    (if (equal? MODE 'SINGLE_PART)
        (book-handler part)
        (lambda (book)
          (if (equal? MODE 'PARTS+TOTAL) (original-book-handler book))
          (for-each
           (lambda (pair)
             (let* ((part (car pair)))
               ((book-handler part) book)))
           (reverse partlist))))))

\bookpart {
  \score {
    <<
      \new Staff = "staff1" \with { instrumentName = "I1" } { c'4 d' e' f' }
      \new StaffGroup \with { instrumentName = "I2" } <<
        \new Staff = "staff2" { c'1 }
        \new Staff = "staff3" { e'1 }
      >>
      \new Staff = "staff4" \with { instrumentName = "I3" } { e'1 }
    >>
  }
}

\bookpart {
  \score {
    <<
      \new Staff = "staff1" \with { instrumentName = "I1" } { c'4 d' e' f' }
      \new StaffGroup \with { instrumentName = "I2" } <<
        \new Staff = "staff2" { c'1 }
        \new Staff = "staff3" { e'1 }
      >>
      \new Staff = "staff4" \with { instrumentName = "I3" } { e'1 }
    >>
  }
}

%\markup "Some markup"

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

Reply via email to