Hello Dirck, > 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-handler
(lambda (part)
(lambda (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))
(ly:output-def-set-variable! paper 'output-suffix (format #f "~a" part))
(if (not header)
(set! header #{ \header { } #})
(set! header (ly:module-copy header)))
(if (assoc-get part partnames)
(module-define! header 'instrument (assoc-get part partnames)))
(set! new-book (ly:make-book paper header '()))
(for-each (lambda (s) (ly:book-add-score! new-book s)) (reverse parsed-scores))
(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))))))
\score {
<<
\new Staff = "staff1" \with { instrumentName = "I1" } { c' 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"
signature.asc
Description: This is a digitally signed message part.
