1937 lines
72 KiB
Plaintext
1937 lines
72 KiB
Plaintext
\version "2.15.19"
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% OrchestralLily
|
|
% ==============
|
|
% Desciption: Lilypond package to make writing large orchestral scores easier.
|
|
% Documentation: http://wiki.kainhofer.com/lilypond/orchestrallily
|
|
% Version: 0.02, 2008-03-06
|
|
% Author: Reinhold Kainhofer, reinhold@kainhofer.com
|
|
% Copyright: (C) 2008 by Reinhold Kainhofer
|
|
% License: Dual-licensed under either:
|
|
% -) GPL v3.0, http://www.gnu.org/licenses/gpl.html
|
|
% -) Creative Commons BY-NC 3.0, http://creativecommons.org/licenses/by-nc/3.0/at/
|
|
%
|
|
% Version History:
|
|
% 0.01 (2008-03-02): Initial Version
|
|
% 0.02 (2008-03-06): Added basic MIDI support (*MidiInstrument and \setCreateMIDI)
|
|
% 0.03 (2008-07-xx): General staff/voice types, title pages, etc.
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
#(use-modules (ice-9 match))
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% GLOBAL OPTIONS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
% Use relative include pathes!
|
|
#(ly:set-option 'relative-includes #t)
|
|
|
|
\include "sceaux_clef-key.ily"
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% SCORE STRUCTURE AND AUTOMATIC GENERATION
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Helper functions
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
% Helper function to filter all non-null entries
|
|
#(define (not-null? x) (not (null? x)))
|
|
|
|
% Helper function to extract a given variable, built from [Piece][Instrument]Identifier
|
|
#(define (namedPieceInstrObject piece instr name)
|
|
(let* (
|
|
(fullname (string->symbol (string-append piece instr name)))
|
|
(instrname (string->symbol (string-append instr name)))
|
|
(piecename (string->symbol (string-append piece name)))
|
|
(fallback (string->symbol name))
|
|
)
|
|
(cond
|
|
((defined? fullname) (primitive-eval fullname))
|
|
((defined? instrname) (primitive-eval instrname))
|
|
((defined? piecename) (primitive-eval piecename))
|
|
((defined? fallback) (primitive-eval fallback))
|
|
(else '())
|
|
)
|
|
)
|
|
)
|
|
|
|
%% Print text as a justified paragraph, taken from the lilypond Notation Reference
|
|
#(define-markup-list-command (paragraph layout props args) (markup-list?)
|
|
(let ((indent (chain-assoc-get 'par-indent props 2)))
|
|
(interpret-markup-list layout props
|
|
(make-justified-lines-markup-list (cons (make-hspace-markup indent)
|
|
args)))))
|
|
|
|
conditionalBreak = #(define-music-function (parser location) ()
|
|
#{ \tag #'instrumental-score \pageBreak #}
|
|
)
|
|
|
|
#(define (oly:piece-title-markup title) (markup #:column (#:line (#:fontsize #'3 #:bold title))) )
|
|
|
|
#(define-markup-command (piece-title layout props title) (markup?)
|
|
(interpret-markup layout props (oly:piece-title-markup title))
|
|
)
|
|
|
|
#(define (oly:generate_object_name piece instr obj )
|
|
(if (and (string? piece) (string? instr) (string? obj))
|
|
(string-append piece instr obj)
|
|
#f
|
|
)
|
|
)
|
|
#(define (oly:generate_staff_name piece instr) (oly:generate_object_name piece instr "St"))
|
|
|
|
#(define (set-context-property context property value)
|
|
(set! (ly:music-property context property) value)
|
|
)
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Score structure and voice types
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
#(define oly:LiedScoreStructure '(
|
|
("SoloScore" "SimultaneousMusic" ("Singstimme"))
|
|
("Pfe" "PianoStaff" ("PfeI" "PfeII"))
|
|
;("PfeI" "ParallelVoicesStaff" ("OIa" "OIb"))
|
|
;("PfeII" "ParallelVoicesStaff" ("OIIa" "OIIb"))
|
|
("FullScore" "SimultaneousMusic" ("Singstimme" "Pfe"))
|
|
("VocalScore" "SimultaneousMusic" ("Singstimme" "Pfe"))
|
|
))
|
|
|
|
#(define oly:StringEnsembleScoreStructure '(
|
|
("FullScore" "StaffGroup" ("VI" "VII" "Va" "Vc" "Cb" "VcB"))
|
|
))
|
|
|
|
#(define oly:fullOrchestraScoreStructure '(
|
|
; Part-combined staves for full score
|
|
("Fl" "PartCombinedStaff" ("FlI" "FlII"))
|
|
("Ob" "PartCombinedStaff" ("ObI" "ObII"))
|
|
("Cl" "PartCombinedStaff" ("ClI" "ClII"))
|
|
("Fag" "PartCombinedStaff" ("FagI" "FagII"))
|
|
("Wd" "StaffGroup" ("Fl" "Ob" "Cl" "Fag" "CFag"))
|
|
|
|
("Cor" "PartCombinedStaff" ("CorI" "CorII"))
|
|
("Tbe" "PartCombinedStaff" ("TbeI" "TbeII"))
|
|
("Clni" "PartCombinedStaff" ("ClnoI" "ClnoII"))
|
|
("Trb" "PartCombinedStaff" ("TrbI" "TrbII"))
|
|
("Br" "StaffGroup" ("Cor" "Tbe" "Clni" "Trb" "Tba"))
|
|
|
|
; long score; no part-combined staves, but GrandStaves instead
|
|
("FlLong" "GrandStaff" ("FlI" "FlII"))
|
|
("ObLong" "GrandStaff" ("ObI" "ObII"))
|
|
("ClLong" "GrandStaff" ("ClI" "ClII"))
|
|
("FagLong" "GrandStaff" ("FagI" "FagII"))
|
|
("WdLong" "StaffGroup" ("FlLong" "ObLong" "ClLong" "FagLong" "CFag"))
|
|
|
|
("CorLong" "GrandStaff" ("CorI" "CorII"))
|
|
("TbeLong" "GrandStaff" ("TbeI" "TbeII"))
|
|
("ClniLong" "GrandStaff" ("ClnoI" "ClnoII" "ClnoIII"))
|
|
("TrbLong" "GrandStaff" ("TrbI" "TrbII" "TrbIII"))
|
|
("BrLong" "StaffGroup" ("CorLong" "TbeLong" "ClniLong" "TrbLong" "Tba"))
|
|
|
|
; Percussion
|
|
("Perc" "StaffGroup" ("Tim"))
|
|
|
|
; Strings, they are the same in long and short full score
|
|
("VV" "GrandStaff" ("VI" "VII"))
|
|
("Str" "StaffGroup" ("VV" "Va"))
|
|
("VceB" "StaffGroup" ("Vc" "Cb" "VcB"))
|
|
("FullStr" "StaffGroup" ("VV" "Va" "Vc" "Cb" "VcB"))
|
|
|
|
; Choral score
|
|
("Solo" "SimultaneousMusic" ("SSolo" "ASolo" "TSolo" "BSolo"))
|
|
("Ch" "ChoirStaff" ("S" "A" "T" "B"))
|
|
("ChoralScore" "SimultaneousMusic" ("Ch"))
|
|
("SoloScore" "SimultaneousMusic" ("Solo"))
|
|
("SoloChoirScore" "SimultaneousMusic" ("Solo" "Ch"))
|
|
|
|
; Organ score (inkl. Figured bass)
|
|
("BCFb" "FiguredBass" ())
|
|
("FiguredBass" "FiguredBass" ())
|
|
;("Organ" "SimultaneousMusic" ("BCFb" "O"))
|
|
("Continuo" "ParallelVoicesStaff" ("BCFb" "BC" "FiguredBass"))
|
|
("RealizedContinuo" "PianoStaff" ("BCRealization" "Continuo"))
|
|
|
|
("P" "PianoStaff" ("PI" "PII"))
|
|
("O" "PianoStaff" ("OI" "OII"))
|
|
("OI" "ParallelVoicesStaff" ("OIa" "OIb"))
|
|
("OII" "ParallelVoicesStaff" ("OIIa" "OIIb"))
|
|
|
|
;("Organ" "SimultaneousMusic" ("OGroup" "RealizedContinuo"))
|
|
;("BassGroup" "ParallelVoicesStaff" ("Organ" "O" "BC" "VceB"))
|
|
("BassGroup" "StaffGroup" ("O" "RealizedContinuo" "Vc" "Cb" "VcB"))
|
|
|
|
; Full Scores
|
|
("FullScore" "SimultaneousMusic" ("Wd" "Br" "Perc" "Str" "SoloChoirScore" "BassGroup"))
|
|
("LongScore" "SimultaneousMusic" ("WdLong" "BrLong" "Perc" "Str" "SoloChoirScore" "BassGroup"))
|
|
("OriginalScore" "SimultaneousMusic" ("BrLong" "WdLong" "Perc" "Str" "SoloChoirScore" "BassGroup"))
|
|
|
|
; Piano reduction
|
|
;("Piano" "SimultaneousMusic" ("Organ"))
|
|
("OrganScore" "SimultaneousMusic" ("SoloChoirScore" "O"))
|
|
("VocalScore" "SimultaneousMusic" ("SoloChoirScore" "P"))
|
|
("Particell" "SimultaneousMusic" ("ChoralScore" "BassGroup"))
|
|
|
|
; Full scores: Orchestral score and long score including organ
|
|
("ChStrQ" "SimultaneousMusic" ("Str" "Ch" "VceB"))
|
|
))
|
|
#(define oly:orchestral_score_structure oly:fullOrchestraScoreStructure)
|
|
|
|
#(define (oly:set_score_structure struct)
|
|
(if (list? struct)
|
|
(set! oly:orchestral_score_structure struct)
|
|
(ly:warning (_ "oly:set_score_structure needs an association list as argument!"))
|
|
)
|
|
)
|
|
|
|
#(define (oly:modify_score_structure entry)
|
|
(if (list? entry)
|
|
(set! oly:orchestral_score_structure (assoc-set! oly:orchestral_score_structure (car entry) (cdr entry)))
|
|
(ly:warning (_ "oly:modify_score_structure expects a list (\"key\" \"type\" '(children)) as argument!"))))
|
|
|
|
#(define (oly:remove_from_score_structure entry)
|
|
(if (list? entry)
|
|
(map oly:remove_from_score_structure entry)
|
|
(set! oly:orchestral_score_structure (assoc-remove! oly:orchestral_score_structure entry))))
|
|
|
|
orchestralScoreStructure = #(define-music-function (parser location structure) (list?)
|
|
(oly:set_score_structure structure)
|
|
(make-music 'Music 'void #t)
|
|
)
|
|
|
|
#(define oly:voice_types '())
|
|
|
|
#(define (oly:set_voice_types types)
|
|
(if (list? types)
|
|
(set! oly:voice_types types)
|
|
(ly:warning (_ "oly:set_voice_types needs an association list as argument!"))
|
|
)
|
|
)
|
|
|
|
orchestralVoiceTypes = #(define-music-function (parser location types) (list?)
|
|
(oly:set_voice_types types)
|
|
(make-music 'Music 'void #t)
|
|
)
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Automatic staff and group generation
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
% Retrieve all music definitions for the given
|
|
#(define (oly:get_music_object piece instrument)
|
|
(namedPieceInstrObject piece instrument "Music")
|
|
)
|
|
#(define (oly:get_music_objects piece instruments)
|
|
(filter not-null? (map (lambda (i) (oly:get_music_object piece i)) instruments))
|
|
)
|
|
|
|
% Given a property name and the extensions, either generate the pair to set
|
|
% the property or an empty list, if no pre-defined variable could be found
|
|
#(define (oly:generate_property_pair prop piece instr type)
|
|
(let* ((val (namedPieceInstrObject piece instr type)))
|
|
(if (not-null? val) (list 'assign prop val) '() )
|
|
)
|
|
)
|
|
|
|
#(define (oly:staff_type type)
|
|
(cond
|
|
((string? type) (string->symbol type))
|
|
((symbol? type) type)
|
|
(else 'Staff)
|
|
)
|
|
)
|
|
|
|
% extract the pitch from the music (can also be a raw pitch object!)
|
|
#(define (oly:extractPitch music)
|
|
(let* (
|
|
(elems (if (ly:music? music) (ly:music-property music 'elements)))
|
|
(note (if (pair? elems) (car elems)))
|
|
(mpitch (if (ly:music? note) (ly:music-property note 'pitch)))
|
|
(pitch (if (ly:pitch? music) music mpitch))
|
|
)
|
|
(if (and (not-null? music) (not (ly:pitch? pitch)))
|
|
(ly:warning "Unable to interpret as a pitch!")
|
|
)
|
|
pitch
|
|
)
|
|
|
|
)
|
|
#(define (oly:extractTranspositionPitch piece name)
|
|
(let* (
|
|
(trpFromPitch (oly:extractPitch (namedPieceInstrObject piece name "TransposeFrom")))
|
|
(trpToPitch (oly:extractPitch (namedPieceInstrObject piece name "TransposeTo")))
|
|
)
|
|
(if (ly:pitch? trpFromPitch)
|
|
(if (ly:pitch? trpToPitch)
|
|
; Both pitches
|
|
(ly:pitch-diff trpFromPitch trpToPitch)
|
|
(ly:pitch-diff trpFromPitch (ly:make-pitch 0 0 0))
|
|
)
|
|
(if (ly:pitch? trpToPitch)
|
|
(ly:pitch-diff (ly:make-pitch 0 0 0) trpToPitch)
|
|
#f
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
%%=====================================================================
|
|
%% Extract context modifications for given objects
|
|
%%---------------------------------------------------------------------
|
|
|
|
|
|
% TODO: join these property extractors to avoid code duplication
|
|
|
|
% Generate the properties for the lyrics for piece and instr.
|
|
% Also check whether we have a modifications object to fech mods from.
|
|
% return a (possibly empty) list of all assignments.
|
|
#(define (oly:lyrics_handler_properties piece name lyricsid)
|
|
(let* (
|
|
(mods (namedPieceInstrObject piece name (string-append lyricsid "Modifications")))
|
|
(mod-list (if (not-null? mods) (ly:get-context-mods mods) '()))
|
|
(mapping '(
|
|
;(instrumentName . "InstrumentName")
|
|
;(shortInstrumentName . "ShortInstrumentName")
|
|
;(midiInstrument . "MidiInstrument")
|
|
))
|
|
(assignments (map
|
|
(lambda (pr)
|
|
(oly:generate_property_pair (car pr) piece name (cdr pr))
|
|
)
|
|
mapping))
|
|
(olyprops (filter not-null? assignments))
|
|
(props (append mod-list olyprops))
|
|
)
|
|
props
|
|
)
|
|
)
|
|
|
|
% Generate the properties for the voice for piece and instr.
|
|
% Also check whether we have a modifications object to fech mods from.
|
|
% return a (possibly empty) list of all assignments.
|
|
#(define (oly:voice_handler_properties piece name)
|
|
(let* (
|
|
(mods (namedPieceInstrObject piece name "VoiceModifications"))
|
|
(mod-list (if (not-null? mods) (ly:get-context-mods mods) '()))
|
|
(mapping '(
|
|
;(instrumentName . "InstrumentName")
|
|
;(shortInstrumentName . "ShortInstrumentName")
|
|
;(midiInstrument . "MidiInstrument")
|
|
))
|
|
(assignments (map
|
|
(lambda (pr)
|
|
(oly:generate_property_pair (car pr) piece name (cdr pr))
|
|
)
|
|
mapping))
|
|
(olyprops (filter not-null? assignments))
|
|
(props (append mod-list olyprops))
|
|
)
|
|
props
|
|
)
|
|
)
|
|
|
|
% Generate the properties for the staff for piece and instr. Typically, these
|
|
% are the instrument name and the short instrument name (if defined).
|
|
% Also check whether we have a modifications object to fech mods from.
|
|
% return a (possibly empty) list of all assignments.
|
|
#(define (oly:staff_handler_properties piece instr)
|
|
(let* (
|
|
(mods (namedPieceInstrObject piece instr "StaffModifications"))
|
|
(mod-list (if (not-null? mods) (ly:get-context-mods mods) '()))
|
|
(mapping '(
|
|
(instrumentName . "InstrumentName")
|
|
(shortInstrumentName . "ShortInstrumentName")
|
|
(midiInstrument . "MidiInstrument")
|
|
))
|
|
(assignments (map
|
|
(lambda (pr)
|
|
(oly:generate_property_pair (car pr) piece instr (cdr pr))
|
|
)
|
|
mapping))
|
|
(olyprops (filter not-null? assignments))
|
|
(props (append mod-list olyprops))
|
|
)
|
|
props
|
|
)
|
|
)
|
|
|
|
%% Process the extracted object, e.g. wrap \clef around the
|
|
%% string for "type"=="Clef", etc.
|
|
% This allows a more fine-grained post-processing of the global vars
|
|
#(define (oly:processExtractedObject piece name type object)
|
|
(if (and (string=? type "Clef") (string? object))
|
|
(make-ancient-or-modern-clef object) ;; Use Nicolas Sceaux' old/modern clef notation
|
|
object))
|
|
|
|
|
|
|
|
%%=====================================================================
|
|
%% Extract contents for voices
|
|
%%---------------------------------------------------------------------
|
|
|
|
#(define (oly:musiccontent_for_voice parser piece name music additional)
|
|
(let* ((musiccontent additional))
|
|
|
|
; Append the settings, key and clef (if defined)
|
|
(map
|
|
(lambda (type)
|
|
(let* ((object (oly:processExtractedObject piece name type (namedPieceInstrObject piece name type))))
|
|
(if (ly:music? object)
|
|
(set! musiccontent (append musiccontent (list (ly:music-deep-copy object))))
|
|
(if (not-null? object) (ly:warning (_ "Wrong type (no ly:music) for ~S for instrument ~S in piece ~S") type name piece))
|
|
)
|
|
)
|
|
)
|
|
; TODO: Does the "Tempo" work here???
|
|
'("Settings" "Key" "Clef" "TimeSignature" "ExtraSettings";"Tempo"
|
|
)
|
|
)
|
|
|
|
(if (ly:music? music)
|
|
(begin
|
|
(set! musiccontent (make-sequential-music (append musiccontent (list music))))
|
|
;(ly:message "Generating staff for ~a" name)
|
|
(let* ((trpPitch (oly:extractTranspositionPitch piece name)))
|
|
(if (ly:pitch? trpPitch)
|
|
(set! musiccontent (ly:music-transpose musiccontent trpPitch))
|
|
)
|
|
)
|
|
musiccontent
|
|
)
|
|
; For empty music, return empty
|
|
'()
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
|
|
%%=====================================================================
|
|
%% create Lyrics
|
|
%%---------------------------------------------------------------------
|
|
|
|
|
|
#(define (oly:lyrics_create_single_context parser piece name voicename lyricsid)
|
|
; If we have lyrics, create a lyrics context containing LyricCombineMusic
|
|
; and add that as second element to the staff's elements list...
|
|
; Also add possibly configured LyricsModifications
|
|
(let* ((id (string-append "Lyrics" lyricsid))
|
|
(lyricsmods (oly:lyrics_handler_properties piece name id))
|
|
(lyrics (namedPieceInstrObject piece name id))
|
|
(ctx (if (ly:music? lyrics)
|
|
(context-spec-music (make-music 'LyricCombineMusic
|
|
'element lyrics
|
|
'associated-context voicename)
|
|
'Lyrics
|
|
(oly:generate_object_name piece name id))
|
|
'())))
|
|
(if (and (not-null? lyricsmods) (not-null? ctx))
|
|
(set! (ly:music-property ctx 'property-operations) lyricsmods)
|
|
)
|
|
ctx
|
|
)
|
|
)
|
|
|
|
#(define (oly:lyrics_create_contexts parser piece name voicename)
|
|
(filter not-null?
|
|
(map (lambda (str)
|
|
(oly:lyrics_create_single_context parser piece name voicename str))
|
|
(list "" "I" "II" "III" "IV" "V" "VI"))))
|
|
|
|
|
|
%%=====================================================================
|
|
%% Voice handling
|
|
%%---------------------------------------------------------------------
|
|
|
|
|
|
#(define (oly:voice_handler_internal parser piece name type music)
|
|
(if (ly:music? music)
|
|
(let* (
|
|
(voicename (oly:generate_object_name piece name "Voice" ))
|
|
(lyrics (oly:lyrics_create_contexts parser piece name voicename))
|
|
(additional (if (not-null? lyrics) (list dynamicUp) '()))
|
|
(musiccontent (oly:musiccontent_for_voice parser piece name music additional))
|
|
(voicetype (oly:staff_type type))
|
|
(voice (context-spec-music musiccontent voicetype voicename))
|
|
(voiceprops (oly:voice_handler_properties piece name))
|
|
)
|
|
(if (not-null? voiceprops)
|
|
(set! (ly:music-property voice 'property-operations) voiceprops)
|
|
)
|
|
(cons voice lyrics)
|
|
)
|
|
; For empty music, return empty
|
|
'()
|
|
)
|
|
)
|
|
|
|
#(define (oly:voice_handler parser piece name type)
|
|
(oly:voice_handler_internal parser piece name type (oly:get_music_object piece name)))
|
|
|
|
|
|
%%=====================================================================
|
|
%% Staff/Group handling
|
|
%%---------------------------------------------------------------------
|
|
|
|
|
|
#(define (oly:staff_handler_internal parser piece name type voices)
|
|
(if (not-null? voices)
|
|
(let* (
|
|
(staffname (oly:generate_staff_name piece name))
|
|
(stafftype (oly:staff_type type))
|
|
(staff (make-simultaneous-music voices))
|
|
(propops (oly:staff_handler_properties piece name))
|
|
)
|
|
(case stafftype
|
|
((SimultaneousMusic ParallelMusic) #f)
|
|
(else (set! staff (context-spec-music staff stafftype staffname)))
|
|
)
|
|
(if (not-null? propops)
|
|
(set! (ly:music-property staff 'property-operations) propops)
|
|
)
|
|
staff
|
|
)
|
|
; For empty music, return empty
|
|
'()
|
|
)
|
|
)
|
|
|
|
#(define (oly:staff_handler parser piece name type children)
|
|
(let* ((c (if (not-null? children) children (list name)))
|
|
(voices (apply append (map (lambda (v) (oly:create_voice parser piece v)) c)) )
|
|
)
|
|
(if (not-null? voices)
|
|
(oly:staff_handler_internal parser piece name type voices)
|
|
'()
|
|
)
|
|
)
|
|
)
|
|
|
|
#(define (oly:devnull_handler parser piece name type children)
|
|
(oly:voice_handler parser piece name type)
|
|
)
|
|
|
|
#(define (oly:parallel_voices_staff_handler parser piece name type children)
|
|
(let* (
|
|
(voices (map (lambda (i) (oly:create_voice parser piece i)) children))
|
|
; get the list of non-empty voices and flatten it!
|
|
(nonemptyvoices (apply append (filter not-null? voices)))
|
|
)
|
|
(if (not-null? nonemptyvoices)
|
|
(oly:staff_handler_internal parser piece name "Staff" nonemptyvoices)
|
|
'()
|
|
)
|
|
)
|
|
)
|
|
|
|
#(define (oly:remove-with-tag tag music)
|
|
(if (ly:music? music)
|
|
(music-filter
|
|
(lambda (m)
|
|
(let* ((tags (ly:music-property m 'tags))
|
|
(res (memq tag tags)))
|
|
(not res)))
|
|
music)
|
|
music))
|
|
|
|
% Remove all music tagged a not-part-combine
|
|
#(define (oly:remove-non-part-combine-events music)
|
|
(oly:remove-with-tag 'non-partcombine music))
|
|
|
|
#(define (oly:part_combined_staff_handler parser piece name type children)
|
|
(let* ((rawmusic (map (lambda (c) (oly:musiccontent_for_voice parser piece name (oly:get_music_object piece c) '())) children))
|
|
(filteredmusic (map (lambda (m) (oly:remove-non-part-combine-events m)) rawmusic))
|
|
(music (filter not-null? filteredmusic)))
|
|
(cond
|
|
((and (pair? music) (ly:music? (car music)) (not-null? (cdr music)) (ly:music? (cadr music)))
|
|
;(ly:message "Part-combine with two music expressions")
|
|
(oly:staff_handler_internal parser piece name "Staff" (list (make-part-combine-music parser music #f))))
|
|
((null? music)
|
|
;;(ly:warning "Part-combine without any music expressions")
|
|
'())
|
|
; exactly one is a music expression, simply use that by joining
|
|
((list? music)
|
|
;;(ly:message "Part-combine with only one music expressions")
|
|
(oly:staff_handler_internal parser piece name "Staff" (list (apply append music))))
|
|
(else
|
|
;(ly:message "make_part_combined_staff: ~S ~S ~a" piece instr instruments)
|
|
'() )
|
|
)
|
|
)
|
|
)
|
|
|
|
% Figured bass is a special case, as it can be voice- or staff-type. When
|
|
% given as a staff type, simply call the voice handler, instead
|
|
|
|
#(define (oly:figured_bass_staff_handler parser piece name type children)
|
|
(let* ((c (if (not-null? children) children (list name)))
|
|
(voice (oly:voice_handler parser piece (car c) type)))
|
|
(if (pair? voice) (car voice) ())
|
|
)
|
|
)
|
|
|
|
#(define (flatten lst)
|
|
(define (f remaining result)
|
|
(cond
|
|
((null? remaining) result)
|
|
((pair? (car remaining)) (f (cdr remaining) (f (car remaining) result)))
|
|
(else (f (cdr remaining) (cons (car remaining) result)))))
|
|
(reverse! (f lst '())))
|
|
|
|
#(define (oly:staff_group_handler parser piece name type children)
|
|
(let* (
|
|
(staves (flatten (map (lambda (i) (oly:create_staff_or_group parser piece i)) children)))
|
|
(nonemptystaves (filter not-null? staves))
|
|
)
|
|
(if (not-null? nonemptystaves)
|
|
(let* (
|
|
(musicexpr (if (= 1 (length nonemptystaves))
|
|
(car nonemptystaves)
|
|
(make-simultaneous-music nonemptystaves)))
|
|
(groupname (oly:generate_staff_name piece name))
|
|
(grouptype (oly:staff_type type))
|
|
(group musicexpr)
|
|
(propops (oly:staff_handler_properties piece name))
|
|
)
|
|
(case grouptype
|
|
((SimultaneousMusic ParallelMusic) #f)
|
|
(else (set! group (context-spec-music group grouptype groupname)))
|
|
)
|
|
(if (pair? propops)
|
|
(set! (ly:music-property group 'property-operations) propops))
|
|
group
|
|
)
|
|
; Return empty list if no staves are generated
|
|
'()
|
|
)
|
|
)
|
|
)
|
|
|
|
#(define (oly:create_voice parser piece name)
|
|
(let* ( (voice (namedPieceInstrObject piece name "Voice"))
|
|
(type (assoc-ref oly:voice_types name)) )
|
|
(if (not-null? voice)
|
|
; Explicit voice variable, use that
|
|
voice
|
|
|
|
(if (not type)
|
|
; No entry in structure found => simple voice
|
|
(oly:voice_handler parser piece name "Voice")
|
|
; Entry found in structure => use the handler for the given type
|
|
(let* (
|
|
(voicetype (car type))
|
|
(handler (assoc-ref oly:voice_handlers voicetype))
|
|
)
|
|
(if handler
|
|
((primitive-eval handler) parser piece name voicetype)
|
|
(begin
|
|
(ly:warning "No handler found for voice type ~a, using default voice handler" voicetype)
|
|
(oly:voice_handler parser piece name voicetype)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
#(define (oly:create_staff_or_group parser piece name)
|
|
(let* ( (staff (namedPieceInstrObject piece name "Staff"))
|
|
(type_from_structure (assoc-ref oly:orchestral_score_structure name)) )
|
|
;(if (not-null? staff)
|
|
; (ly:message "Found staff variable for instrument ~a in piece ~a" instr piece)
|
|
; (ly:message "Staff variable for instrument ~a in piece ~a NOT FOUND" instr piece)
|
|
;)
|
|
(if (not-null? staff)
|
|
; Explicit staff variable, use that
|
|
staff
|
|
|
|
(if (not (list? type_from_structure))
|
|
; No entry in structure found => simple staff
|
|
(oly:staff_handler parser piece name "Staff" '())
|
|
|
|
; Entry found in structure => use the handler for the given type
|
|
(let* ((type (car type_from_structure))
|
|
(handler (assoc-ref oly:staff_handlers type))
|
|
(children (cadr type_from_structure))
|
|
)
|
|
(if handler
|
|
((primitive-eval handler) parser piece name type children)
|
|
(begin
|
|
(ly:warning "No handler found for staff type ~a, using default staff handler" type)
|
|
(oly:staff_handler parser piece name type children)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
#(define (oly:dynamics_handler parser piece name type children)
|
|
(oly:voice_handler parser piece name type)
|
|
)
|
|
|
|
|
|
%%=====================================================================
|
|
%% Handler definitions
|
|
%%---------------------------------------------------------------------
|
|
|
|
#(define oly:staff_handlers
|
|
(list
|
|
; staff group types
|
|
'("GrandStaff" . oly:staff_group_handler )
|
|
'("PianoStaff" . oly:staff_group_handler )
|
|
'("ChoirStaff" . oly:staff_group_handler )
|
|
'("StaffGroup" . oly:staff_group_handler )
|
|
'("ParallelMusic" . oly:staff_group_handler )
|
|
'("SimultaneousMusic" . oly:staff_group_handler )
|
|
; staff types
|
|
'("Staff" . oly:staff_handler )
|
|
'("DrumStaff" . oly:staff_handler )
|
|
'("RhythmicStaff" . oly:staff_handler )
|
|
'("TabStaff" . oly:staff_handler )
|
|
'("GregorianTranscriptionStaff" . oly:staff_handler )
|
|
'("MensuralStaff" . oly:staff_handler )
|
|
'("VaticanaStaff" . oly:staff_handler )
|
|
'("ChordNames" . oly:staff_handler )
|
|
; staves with multiple voices
|
|
'("PartCombinedStaff" . oly:part_combined_staff_handler )
|
|
'("ParallelVoicesStaff" . oly:parallel_voices_staff_handler )
|
|
; special cases: Figured bass can be staff or voice type!
|
|
'("FiguredBass" . oly:figured_bass_staff_handler )
|
|
; Devnull is like a staff, only that it doesn't craete output
|
|
'("Devnull" . oly:devnull_handler )
|
|
'("Dynamics" . oly:dynamics_handler )
|
|
)
|
|
)
|
|
|
|
#(define oly:voice_handlers
|
|
(list
|
|
; voice types
|
|
'("Voice" . oly:voice_handler )
|
|
'("CueVoice" . oly:voice_handler )
|
|
'("DrumVoice" . oly:voice_handler )
|
|
'("FiguredBass" . oly:voice_handler )
|
|
'("ChordNames" . oly:voice_handler )
|
|
'("GregorianTranscriptionVoice" . oly:voice_handler )
|
|
'("NoteNames" . oly:voice_handler )
|
|
'("TabVoice" . oly:voice_handler )
|
|
'("VaticanaVoice" . oly:voice_handler )
|
|
)
|
|
)
|
|
|
|
|
|
#(define (oly:register_staff_type_handler type func)
|
|
; (ly:message "Registering staff handler ~a for type ~a" func type)
|
|
(set! oly:staff_handlers (assoc-set! oly:staff_handlers type func))
|
|
)
|
|
|
|
#(define (oly:register_voice_type_handler type func)
|
|
; (ly:message "Registering voice type handler ~a for type ~a" func type)
|
|
(set! oly:voice_handlers (assoc-set! oly:voice_handlers type func))
|
|
)
|
|
|
|
% handlers for deprecated API
|
|
#(oly:register_staff_type_handler 'StaffGroup 'oly:staff_group_handler)
|
|
#(oly:register_staff_type_handler 'GrandStaff 'oly:staff_group_handler)
|
|
#(oly:register_staff_type_handler 'PianoStaff 'oly:staff_group_handler)
|
|
#(oly:register_staff_type_handler 'ChoirStaff 'oly:staff_group_handler)
|
|
#(oly:register_staff_type_handler 'Staff 'oly:staff_handler )
|
|
#(oly:register_staff_type_handler 'ParallelMusic 'oly:staff_group_handler)
|
|
#(oly:register_staff_type_handler 'SimultaneousMusic 'oly:staff_group_handler)
|
|
#(oly:register_staff_type_handler #t 'oly:part_combined_staff_handler )
|
|
#(oly:register_staff_type_handler #f 'oly:parallel_voices_staff_handler )
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Automatic score generation
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
#(define oly:score_handler add-score)
|
|
#(define oly:music_handler add-music)
|
|
#(define oly:text_handler add-text)
|
|
|
|
|
|
% TODO: deprecate
|
|
setUseBook = #(define-music-function (parser location usebook) (boolean?)
|
|
(ly:warning "\\setUseBook has been deprecated! Books are now automatically handled without any hacks")
|
|
(make-music 'Music 'void #t)
|
|
)
|
|
|
|
|
|
% Two functions to handle midi-blocks: Either don't set one, or set an empty
|
|
% one so that MIDI is generated
|
|
#(define (oly:set_no_midi_block score) '())
|
|
#(define (oly:set_midi_block score)
|
|
(let* ((midiblock (if (defined? '$defaultmidi)
|
|
(ly:output-def-clone $defaultmidi)
|
|
(ly:make-output-def))))
|
|
(ly:output-def-set-variable! midiblock 'is-midi #t)
|
|
(ly:score-add-output-def! score midiblock)
|
|
)
|
|
)
|
|
|
|
% \setCreateMidi ##t/##f sets a flag to determine wheter MIDI output should
|
|
% be generated
|
|
#(define oly:apply_score_midi oly:set_no_midi_block)
|
|
setCreateMIDI = #(define-music-function (parser location createmidi) (boolean?)
|
|
(if createmidi
|
|
(set! oly:apply_score_midi oly:set_midi_block)
|
|
(set! oly:apply_score_midi oly:set_no_midi_block)
|
|
)
|
|
(make-music 'Music 'void #t)
|
|
)
|
|
|
|
|
|
% Two functions to handle layout-blocks: Either don't set one, or set an empty
|
|
% one so that a PDF is generated
|
|
#(define (oly:set_no_layout_block score) '())
|
|
#(define (oly:set_layout_block score)
|
|
(let* ((layoutblock (if (defined? '$defaultlayout)
|
|
(ly:output-def-clone $defaultlayout)
|
|
(ly:make-output-def))))
|
|
(ly:output-def-set-variable! layoutblock 'is-layout #t)
|
|
(ly:score-add-output-def! score layoutblock)
|
|
)
|
|
)
|
|
|
|
% \setCreatePDF ##t/##f sets a flag to determine wheter PDF output should
|
|
% be generated
|
|
#(define oly:apply_score_layout oly:set_no_layout_block)
|
|
setCreatePDF = #(define-music-function (parser location createlayout) (boolean?)
|
|
(if createlayout
|
|
(set! oly:apply_score_layout oly:set_layout_block)
|
|
(set! oly:apply_score_layout oly:set_no_layout_block)
|
|
)
|
|
(make-music 'Music 'void #t)
|
|
)
|
|
|
|
|
|
% Set the piece title in a new header block.
|
|
#(define (oly:set_piece_header score piecename)
|
|
(if (not-null? piecename)
|
|
(let* ((header (make-module)))
|
|
(module-define! header 'piece piecename)
|
|
(ly:score-set-header! score header)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
% post-filter functions. By default, no filtering is done. However,
|
|
% for the *NoCues* function, the cue notes should be killed
|
|
keepcuefilter = #(define-music-function (parser location music) (ly:music?)
|
|
((ly:music-function-extract removeWithTag) parser location 'non-cued music))
|
|
removecuefilter = #(define-music-function (parser location music) (ly:music?)
|
|
((ly:music-function-extract removeWithTag) parser location 'cued ((ly:music-function-extract killCues) parser location music)))
|
|
|
|
%% The page numbers are pages counts in the pdf file, not visible page number!
|
|
%% So we have to offset them if the first page is not page #1
|
|
%% unfortunately this means we have to store the first-page-number of the first
|
|
%% bookpart in a global variable, because in later layouts we don't have that
|
|
%% information available any more (first-page-number will be the first page
|
|
%% number of the currently processed bookpart!)
|
|
#(define oly:first-page-offset #f)
|
|
#(define (oly:create-toc-file layout pages)
|
|
(if (not oly:first-page-offset)
|
|
(set! oly:first-page-offset (1- (ly:output-def-lookup layout 'first-page-number))))
|
|
(let* ((label-table (ly:output-def-lookup layout 'label-page-table)))
|
|
(if (not (null? label-table))
|
|
(let* ((format-line (lambda (toc-item)
|
|
(let* ((label (car toc-item))
|
|
(text (caddr toc-item))
|
|
(label-page (and (list? label-table)
|
|
(assoc label label-table)))
|
|
(page (and label-page (cdr label-page))))
|
|
(if page
|
|
(format #f "~a, section, 1, {~a}, ~a" (- page oly:first-page-offset) text label)
|
|
;; label came from a different bookpart, so ignore it!
|
|
#f))))
|
|
(formatted-toc-items (map format-line (toc-items)))
|
|
(whole-string (string-join (filter (lambda (i) i) formatted-toc-items) ",\n"))
|
|
(output-name (ly:parser-output-name parser))
|
|
(outfilename (format "~a.toc" output-name))
|
|
(outfile (open-output-file outfilename)))
|
|
(if (output-port? outfile)
|
|
(display whole-string outfile)
|
|
(ly:warning (_ "Unable to open output file ~a for the TOC information") outfilename))
|
|
(close-output-port outfile)))))
|
|
|
|
|
|
#(define-public (oly:add-toc-item parser markup-symbol text)
|
|
(oly:music_handler parser (add-toc-item! markup-symbol text)))
|
|
|
|
|
|
#(define (oly:add-score parser score piecename)
|
|
(if (not-null? piecename)
|
|
(oly:add-toc-item parser 'tocItemMarkup piecename))
|
|
(oly:score_handler parser score)
|
|
)
|
|
% The helper function to build a score.
|
|
#(define (oly:createScoreHelper parser location piece children func)
|
|
(let* (
|
|
(staves (oly:staff_group_handler parser piece "" "SimultaneousMusic" children))
|
|
(music (if (not-null? staves)
|
|
((ly:music-function-extract func) parser location staves)
|
|
'()
|
|
))
|
|
(score '())
|
|
(piecename (namedPieceInstrObject piece (car children) "PieceName"))
|
|
(piecenametacet (namedPieceInstrObject piece (car children) "PieceNameTacet"))
|
|
(header '())
|
|
)
|
|
(if (null? music)
|
|
; No staves, print tacet
|
|
(begin
|
|
(if (not-null? piecenametacet) (set! piecename piecenametacet))
|
|
(if (not-null? piecename)
|
|
(oly:add-score parser (list (oly:piece-title-markup piecename)) piecename)
|
|
(ly:warning (_ "No music and no score title found for part ~a and instrument ~a") piece children)
|
|
)
|
|
)
|
|
; we have staves, apply the piecename to the score and add layout/midi blocks if needed
|
|
(begin
|
|
(set! score (scorify-music music parser))
|
|
(oly:set_piece_header score piecename)
|
|
(oly:apply_score_midi score)
|
|
(oly:apply_score_layout score)
|
|
; Schedule the score for typesetting
|
|
(oly:add-score parser score piecename)
|
|
)
|
|
)
|
|
)
|
|
; This is a void function, the score has been schedulled for typesetting already
|
|
(make-music 'Music 'void #t)
|
|
)
|
|
|
|
createVoice = #(define-music-function (parser location piece name) (string? string?)
|
|
(let* ((vc (oly:create_voice parser piece name)))
|
|
(make-music 'SimultaneousMusic
|
|
'elements vc)))
|
|
|
|
createStaff = #(define-music-function (parser location piece name) (string? string?)
|
|
(oly:create_staff_or_group parser piece name))
|
|
createStaffForContents = #(define-music-function (parser location piece name contents) (string? string? ly:music?)
|
|
(let* ((tstruct (assoc-ref oly:orchestral_score_structure name))
|
|
(type (if (list? tstruct) (car tstruct) "Staff")))
|
|
(oly:staff_handler_internal parser piece name type (list contents))))
|
|
|
|
|
|
createScore = #(define-music-function (parser location piece children) (string? list?)
|
|
(oly:createScoreHelper parser location piece children keepcuefilter)
|
|
)
|
|
createNoCuesScore = #(define-music-function (parser location piece children) (string? list?)
|
|
(oly:createScoreHelper parser location piece children removecuefilter)
|
|
)
|
|
|
|
createHeadline = #(define-music-function (parser location headline) (string?)
|
|
(oly:add-toc-item parser 'tocItemMarkup headline)
|
|
(oly:score_handler parser (list (oly:piece-title-markup headline)))
|
|
(make-music 'Music 'void #t)
|
|
)
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% CUE NOTES
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
newInstrument = #(define-music-function (parser location instr) (string?)
|
|
#{
|
|
\set Voice.instrumentCueName = #(string-join (list "+" instr))
|
|
#}
|
|
)
|
|
cueText = #(define-music-function (parser location instr) (string?)
|
|
#{
|
|
\set Voice.instrumentCueName = $instr
|
|
#}
|
|
)
|
|
cueMarkup = #(define-music-function (parser location instr) (markup?)
|
|
#{
|
|
\set Voice.instrumentCueName = $instr
|
|
#}
|
|
)
|
|
|
|
clearCueText = #(define-music-function (parser location) ()
|
|
#{
|
|
\unset Voice.instrumentCueName
|
|
#}
|
|
)
|
|
|
|
insertCueText = #(define-music-function (parser location instr) (string?)
|
|
(if (string-null? instr)
|
|
#{ \tag #'cued \clearCueText #}
|
|
#{ \tag #'cued \cueText #instr #}
|
|
))
|
|
|
|
% generate a cue music section with instrument names
|
|
% Parameters: \namedCueDuring NameOfQuote CueDirection CueInstrument OriginalInstrument music
|
|
% -) NameOfQuote CueDirection music are the parameters for \cueDuring
|
|
% -) CueInstrument and OriginalInstrument are the displayed instrument names
|
|
% typical call:
|
|
% \namedCueDuring #"vIQuote" #UP #"V.I" #"Sop." { R1*3 }
|
|
% This adds the notes from vIQuote (defined via \addQuote) to three measures, prints "V.I" at
|
|
% the beginning of the cue notes and "Sop." at the end
|
|
namedCueDuring = #(define-music-function (parser location cuevoice direction instrcue instr cuemusic) (string? number? string? string? ly:music?)
|
|
#{
|
|
\cueDuring #cuevoice #direction {
|
|
\insertCueText #instrcue
|
|
$cuemusic
|
|
\insertCueText #instr
|
|
}
|
|
#}
|
|
)
|
|
namedTransposedCueDuring = #(define-music-function (parser location cuevoice direction instrcue instr trans cuemusic) (string? number? string? string? ly:music? ly:music?)
|
|
#{
|
|
\transposedCueDuring #cuevoice #direction #trans {
|
|
\insertCueText #instrcue
|
|
#cuemusic
|
|
\insertCueText #instr
|
|
}
|
|
#}
|
|
)
|
|
|
|
% set the cue instrument name and clef
|
|
% setClefCue = #(define-music-function (parser location instr clef)
|
|
% (string? ly:music?)
|
|
% #{
|
|
% \once \override Staff.Clef #'font-size = #-3 \clef $clef
|
|
% \insertCueText $instr
|
|
% #} )
|
|
|
|
% generate a cue music section with instrument names and clef changes
|
|
% Parameters: \cleffedCueDuring NameOfQuote CueDirection CueInstrument CueClef OriginalInstrument OriginalClef music
|
|
% -) NameOfQuote CueDirection music are the parameters for \cueDuring
|
|
% -) CueInstrument and OriginalInstrument are the displayed instrument names
|
|
% -) CueClef and OriginalClef are the clefs for the the cue notes and the clef of the containing voice
|
|
% typical call:
|
|
% \cleffedCueDuring #"vIQuote" #UP #"V.I" #"treble" #"Basso" #"bass" { R1*3 }
|
|
% This adds the notes from vIQuote (defined via \addQuote) to three measures, prints "V.I" at
|
|
% the beginning of the cue notes and "Basso" at the end. The clef is changed to treble at the
|
|
% beginning of the cue notes and reset to bass at the end
|
|
cleffedCueDuring = #(define-music-function (parser location cuevoice direction instrcue clefcue instr clefinstr cuemusic)
|
|
(string? number? string? string? string? string? ly:music?)
|
|
#{
|
|
\namedCueDuringWithClef $cuevoice $direction $instrcue $clefcue $instr $cuemusic
|
|
#}
|
|
)
|
|
% generate a cue music section with instrument names and clef changes
|
|
% Parameters: \namedCueDuringClef NameOfQuote CueDirection CueInstrument CueClef OriginalInstrument music
|
|
% -) NameOfQuote CueDirection music are the parameters for \cueDuring
|
|
% -) CueInstrument and OriginalInstrument are the displayed instrument names
|
|
% -) CueClef is the clef for the the cue notes
|
|
% typical call:
|
|
% \namedCueDuringWithClef #"vIQuote" #UP #"V.I" #"treble" #"Basso" { R1*3 }
|
|
% This adds the notes from vIQuote (defined via \addQuote) to three measures, prints "V.I" at
|
|
% the beginning of the cue notes and "Basso" at the end. The clef is changed to treble at the
|
|
% beginning of the cue notes and reset to bass at the end
|
|
namedCueDuringWithClef = #(define-music-function (parser location cuevoice direction instrcue clefcue instr cuemusic)
|
|
(string? number? string? string? string? ly:music?)
|
|
#{
|
|
\cueDuringWithClef #cuevoice #direction #(extract-ancient-or-modern-clef clefcue) {
|
|
\insertCueText #instrcue
|
|
#cuemusic
|
|
\insertCueText #instr
|
|
}
|
|
#}
|
|
)
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% DYNAMICS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
dynamicsX = #(define-music-function (parser location offset) (number?)
|
|
#{
|
|
\once \override DynamicText #'X-offset = $offset
|
|
\once \override DynamicLineSpanner #'Y-offset = #0
|
|
#})
|
|
|
|
% Move the dynamic sign inside the staff to a fixed staff-relative position
|
|
% posY (where 0 means vertically starts at the middle staff line)
|
|
dynamicsAllInside = #(define-music-function (parser location offsetX posY)
|
|
(number? number?)
|
|
#{
|
|
% Invalid y-extent -> hidden from skyline calculation and collisions
|
|
% \once \override DynamicLineSpanner #'Y-extent = #(cons +0 -0.01)
|
|
\once \override DynamicLineSpanner #'Y-extent = $(lambda (grob)
|
|
(let* ((ext (ly:axis-group-interface::height grob))
|
|
(dir (ly:grob-property grob 'direction)))
|
|
(if (eq? dir UP)
|
|
(cons (- (cdr ext) 0.1) (cdr ext))
|
|
(cons (car ext) (+ (car ext) 0.1)))))
|
|
% move by X offset and to fixed Y-position (use Y-offset of parent!)
|
|
\once \override DynamicText #'X-offset = $offsetX
|
|
\once \override DynamicText #'Y-offset =
|
|
$(lambda (grob)
|
|
(let* ((head (ly:grob-parent grob Y))
|
|
(offset (ly:grob-property head 'Y-offset)))
|
|
(- posY offset (- 0.6))))
|
|
\once \override DynamicLineSpanner #'Y-offset = $posY
|
|
#})
|
|
|
|
dynamicsUpInside = #(define-music-function (parser location offsetX) (number?)
|
|
((ly:music-function-extract dynamicsAllInside) parser location offsetX 1.5)
|
|
)
|
|
|
|
dynamicsDownInside = #(define-music-function (parser location offsetX) (number?)
|
|
((ly:music-function-extract dynamicsAllInside) parser location offsetX -3.5)
|
|
)
|
|
|
|
hairpinOffset = #(define-music-function (parser location posY) (number?)
|
|
#{
|
|
\once \override DynamicLineSpanner #'Y-offset = $posY
|
|
\once \override DynamicLineSpanner #'Y-extent = #(cons +0 -0.01)
|
|
#})
|
|
|
|
#(define ((line-break-offset before after) grob)
|
|
(let* ((orig (ly:grob-original grob))
|
|
; All siblings if line-broken:
|
|
(siblings (if (ly:grob? orig) (ly:spanner-broken-into orig) '() )))
|
|
(if (>= (length siblings) 2)
|
|
; We have been line-broken
|
|
(if (eq? (car (last-pair siblings)) grob)
|
|
; Last sibling:
|
|
(ly:grob-set-property! grob 'Y-offset after)
|
|
; Others get the before value:
|
|
(ly:grob-set-property! grob 'Y-offset before)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
rf = #(make-dynamic-script "rf")
|
|
ffz = #(make-dynamic-script "ffz")
|
|
pf = #(make-dynamic-script "pf")
|
|
sempp = #(make-dynamic-script (markup #:line( #:with-dimensions '(0 . 0)
|
|
'(0 . 0) #:right-align #:normal-text #:italic "sempre" #:dynamic "pp")))
|
|
parenf = #(make-dynamic-script (markup #:line(#:normal-text #:italic #:fontsize 2 "(" #:dynamic "f" #:normal-text #:italic #:fontsize 2 ")")))
|
|
parenp = #(make-dynamic-script (markup #:line(#:normal-text #:italic #:fontsize 2 "(" #:dynamic "p" #:normal-text #:italic #:fontsize 2 ")")))
|
|
pdolce = #(make-dynamic-script (markup #:line(#:dynamic "p" #:with-dimensions '(0 . 0) '(0 . 0) #:normal-text #:italic "dolce")))
|
|
ppdolce = #(make-dynamic-script (markup #:line(#:dynamic "pp" #:with-dimensions '(0 . 0) '(0 . 0) #:normal-text #:italic "dolce")))
|
|
dolce = #(make-dynamic-script (markup #:line(#:normal-text #:italic "dolce")))
|
|
sfpdolce = #(make-dynamic-script (markup #:line(#:dynamic "sfp" #:with-dimensions '(0 . 0) '(0 . 0) #:normal-text #:italic "dolce" )))
|
|
bracketf = #(make-dynamic-script (markup #:line(#:concat(#:normal-text #:fontsize 3 "[" #:dynamic "f" #:hspace 0.1 #:normal-text #:fontsize 3 "]"))))
|
|
bracketmf = #(make-dynamic-script (markup #:line(#:concat(#:normal-text #:fontsize 3 "[" #:dynamic "mf" #:hspace 0.1 #:normal-text #:fontsize 3 "]"))))
|
|
bracketmp = #(make-dynamic-script (markup #:line(#:concat(#:normal-text #:fontsize 2 "[" #:hspace 0.2 #:dynamic "mp" #:normal-text #:fontsize 2 "]"))))
|
|
bracketp = #(make-dynamic-script (markup #:line(#:concat(#:normal-text #:fontsize 2 "[" #:hspace 0.2 #:dynamic "p" #:normal-text #:fontsize 2 "]"))))
|
|
|
|
whiteoutp = #(make-dynamic-script (markup #:whiteout #:pad-markup 0.5 #:dynamic "p"))
|
|
whiteoutf = #(make-dynamic-script (markup #:whiteout #:pad-markup 0.5 #:dynamic "f"))
|
|
whiteoutff = #(make-dynamic-script (markup #:whiteout #:pad-markup 0.5 #:dynamic "ff"))
|
|
|
|
sim = ^\markup{\italic "sim."}
|
|
|
|
%%% Thanks to "Gilles THIBAULT" <gilles.thibault@free.fr>, there is a way
|
|
% to remove also the fermata from R1-\fermataMarkup: By filtering the music
|
|
% and removing the corresponding events.
|
|
% Documented as an LSR snippet: http://lsr.dsi.unimi.it/LSR/Item?id=372
|
|
#(define (filterOneEventsMarkup event)
|
|
( let ( (eventname (ly:music-property event 'name)) )
|
|
(not
|
|
(or ;; add here event name you do NOT want
|
|
(eq? eventname 'MultiMeasureTextEvent)
|
|
(eq? eventname 'AbsoluteDynamicEvent)
|
|
(eq? eventname 'TextScriptEvent)
|
|
(eq? eventname 'ArticulationEvent)
|
|
(eq? eventname 'CrescendoEvent)
|
|
(eq? eventname 'DecrescendoEvent)
|
|
)
|
|
)
|
|
))
|
|
|
|
filterArticulations = #(define-music-function (parser location music) (ly:music?)
|
|
(music-filter filterOneEventsMarkup music)
|
|
)
|
|
|
|
|
|
|
|
%%% Add the same articulation to a longer sequence of notes:
|
|
#(define (make-script x)
|
|
(make-music 'ArticulationEvent
|
|
'articulation-type x))
|
|
|
|
#(define (add-articulation music art)
|
|
(map-some-music
|
|
(lambda (m)
|
|
(cond ((music-is-of-type? m 'event-chord)
|
|
(set! (ly:music-property m 'elements)
|
|
(append (ly:music-property m 'elements)
|
|
(list (make-script art))))
|
|
m)
|
|
((music-is-of-type? m 'note-event)
|
|
(set! (ly:music-property m 'articulations)
|
|
(append (ly:music-property m 'articulations)
|
|
(list (make-script art))))
|
|
m)
|
|
(else #f)))
|
|
music))
|
|
|
|
addArticulation = #(define-music-function (parser location type music)
|
|
(string? ly:music? )
|
|
(add-articulation music type))
|
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% Tempo markings
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
rit = \markup {\italic "rit."}
|
|
atempo = \markup {\italic "a tempo"}
|
|
pocorit = \markup {\italic "poco rit."}
|
|
ppmosso = \markup {\italic "poco più mosso"}
|
|
pizz = \markup {\italic "pizz."}
|
|
arco = \markup {\italic "arco"}
|
|
colarco = \markup {\italic "Col' arco"}
|
|
perd = \markup {\italic "perdend."}
|
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% REST COMBINATION
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
%% REST COMBINING, TAKEN FROM http://lsr.dsi.unimi.it/LSR/Item?id=336
|
|
%%
|
|
%% Usage:
|
|
%% \new Staff \with {
|
|
%% \override RestCollision #'positioning-done = #merge-rests-on-positioning
|
|
%% } << \somevoice \\ \othervoice >>
|
|
%% or (globally):
|
|
%% \layout {
|
|
%% \context {
|
|
%% \Staff
|
|
%% \override RestCollision #'positioning-done = #merge-rests-on-positioning
|
|
%% }
|
|
%% }
|
|
%%
|
|
%% Limitations:
|
|
%% - only handles two voices
|
|
%% - does not handle multi-measure/whole-measure rests
|
|
|
|
#(define (rest-score r)
|
|
(let ((score 0)
|
|
(yoff (ly:grob-property-data r 'Y-offset))
|
|
(sp (ly:grob-property-data r 'staff-position)))
|
|
(if (number? yoff)
|
|
(set! score (+ score 2))
|
|
(if (eq? yoff 'calculation-in-progress)
|
|
(set! score (- score 3))))
|
|
(and (number? sp)
|
|
(<= 0 2 sp)
|
|
(set! score (+ score 2))
|
|
(set! score (- score (abs (- 1 sp)))))
|
|
score))
|
|
|
|
#(define (merge-rests-on-positioning grob)
|
|
(let* ((can-merge #f)
|
|
(elts (ly:grob-object grob 'elements))
|
|
(num-elts (and (ly:grob-array? elts)
|
|
(ly:grob-array-length elts)))
|
|
(two-voice? (= num-elts 2)))
|
|
(if two-voice?
|
|
(let* ((v1-grob (ly:grob-array-ref elts 0))
|
|
(v2-grob (ly:grob-array-ref elts 1))
|
|
(v1-rest (ly:grob-object v1-grob 'rest))
|
|
(v2-rest (ly:grob-object v2-grob 'rest)))
|
|
(and
|
|
(ly:grob? v1-rest)
|
|
(ly:grob? v2-rest)
|
|
(let* ((v1-duration-log (ly:grob-property v1-rest 'duration-log))
|
|
(v2-duration-log (ly:grob-property v2-rest 'duration-log))
|
|
(v1-dot (ly:grob-object v1-rest 'dot))
|
|
(v2-dot (ly:grob-object v2-rest 'dot))
|
|
(v1-dot-count (and (ly:grob? v1-dot)
|
|
(ly:grob-property v1-dot 'dot-count -1)))
|
|
(v2-dot-count (and (ly:grob? v2-dot)
|
|
(ly:grob-property v2-dot 'dot-count -1))))
|
|
(set! can-merge
|
|
(and
|
|
(number? v1-duration-log)
|
|
(number? v2-duration-log)
|
|
(= v1-duration-log v2-duration-log)
|
|
(eq? v1-dot-count v2-dot-count)))
|
|
(if can-merge
|
|
;; keep the rest that looks best:
|
|
(let* ((keep-v1? (>= (rest-score v1-rest)
|
|
(rest-score v2-rest)))
|
|
(rest-to-keep (if keep-v1? v1-rest v2-rest))
|
|
(dot-to-kill (if keep-v1? v2-dot v1-dot)))
|
|
;; uncomment if you're curious of which rest was chosen:
|
|
;;(ly:grob-set-property! v1-rest 'color green)
|
|
;;(ly:grob-set-property! v2-rest 'color blue)
|
|
(ly:grob-suicide! (if keep-v1? v2-rest v1-rest))
|
|
(if (ly:grob? dot-to-kill)
|
|
(ly:grob-suicide! dot-to-kill))
|
|
(ly:grob-set-property! rest-to-keep 'direction 0)
|
|
(ly:rest::y-offset-callback rest-to-keep)))))))
|
|
(if can-merge
|
|
#t
|
|
(ly:rest-collision::calc-positioning-done grob))))
|
|
|
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% TABLE OF CONTENTS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
contentsTitle = "Inhalt / Contents"
|
|
|
|
\paper {
|
|
tocTitleMarkup = \markup \fill-line{
|
|
\null
|
|
\column {
|
|
\override #(cons 'line-width (* 7 cm))
|
|
\line{ \fill-line {\piece-title {\contentsTitle} \null }}
|
|
\hspace #1
|
|
}
|
|
\null
|
|
}
|
|
tocItemMarkup = \markup \fill-line {
|
|
\null
|
|
\column {
|
|
\override #(cons 'line-width (* 7 cm ))
|
|
\line { \fill-line{\fromproperty #'toc:text \fromproperty #'toc:page }}
|
|
}
|
|
\null
|
|
}
|
|
}
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% TITLE PAGE / HEADER
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
#(define-markup-command (when-property layout props symbol markp) (symbol? markup?)
|
|
(if (chain-assoc-get symbol props)
|
|
(interpret-markup layout props markp)
|
|
(ly:make-stencil '() '(1 . -1) '(1 . -1))))
|
|
|
|
#(define-markup-command (vspace layout props amount) (number?)
|
|
"This produces a invisible object taking vertical space."
|
|
(let ((amount (* amount 3.0)))
|
|
(if (> amount 0)
|
|
(ly:make-stencil "" (cons -1 1) (cons 0 amount))
|
|
(ly:make-stencil "" (cons -1 1) (cons amount amount)))))
|
|
|
|
|
|
|
|
titlePageMarkup = \markup \abs-fontsize #10 \when-property #'header:title \column {
|
|
\vspace #4
|
|
\fill-line { \fontsize #8 \fromproperty #'header:composer }
|
|
\vspace #1
|
|
\fill-line { \fontsize #8 \fromproperty #'header:poet }
|
|
\vspace #4
|
|
\fill-line { \fontsize #10 \bold \fromproperty #'header:titlepagetitle }
|
|
\vspace #1
|
|
\fontsize #2 \when-property #'header:titlepagesubtitle {
|
|
\fill-line { \fromproperty #'header:titlepagesubtitle }
|
|
\vspace #1
|
|
}
|
|
\fill-line { \postscript #"-20 0 moveto 40 0 rlineto stroke" }
|
|
\vspace #8
|
|
\fill-line { \fontsize #5 \fromproperty #'header:ensemble }
|
|
\vspace #0.02
|
|
\fill-line { \fontsize #2 \fromproperty #'header:instruments }
|
|
\vspace #9
|
|
\fill-line { \fontsize #5 \fromproperty #'header:date }
|
|
\vspace #1
|
|
\fill-line { \fontsize #5 \fromproperty #'header:scoretype }
|
|
\vspace #1
|
|
\when-property #'header:instrument {
|
|
\fill-line { \bold \fontsize #6 \rounded-box \fromproperty #'header:instrument }
|
|
}
|
|
\vspace #7
|
|
\fontsize #2 \when-property #'header:enteredby \override #'(baseline-skip . 3.75) \left-align\center-column {
|
|
\fill-line { "Herausgegeben von: / Edited by:"}
|
|
\vspace #0.
|
|
\fill-line { \fromproperty #'header:enteredby }
|
|
}
|
|
\fill-line {
|
|
\when-property #'header:arrangement \column {
|
|
\vspace #8
|
|
\fill-line { \fontsize #3 \fromproperty #'header:arrangement }
|
|
}
|
|
}
|
|
\vspace #6
|
|
\fill-line { \fromproperty #'header:copyright }
|
|
}
|
|
|
|
titleHeaderMarkup = \markup {
|
|
\override #'(baseline-skip . 3.5)
|
|
\column {
|
|
\fill-line {
|
|
\fromproperty #'header:logo
|
|
\override #'(baseline-skip . 4.5) \center-column {
|
|
\bold \abs-fontsize #18 \fromproperty #'header:title
|
|
\bold \abs-fontsize #12 \fromproperty #'header:subtitle
|
|
\abs-fontsize #11 \fromproperty #'header:subsubtitle
|
|
}
|
|
\bold \abs-fontsize #11 \when-property #'header:instrument \rounded-box \fromproperty #'header:instrument
|
|
}
|
|
\fill-line {
|
|
\with-dimensions #'( 0 . 0) #'( 0 . 1 ) \null
|
|
}
|
|
|
|
\fill-line {
|
|
\abs-fontsize #10 \fromproperty #'header:poet
|
|
\abs-fontsize #10 \fromproperty #'header:composer
|
|
}
|
|
\fill-line {
|
|
\abs-fontsize #10 \fromproperty #'header:meter
|
|
\abs-fontsize #10 \fromproperty #'header:arranger
|
|
}
|
|
}
|
|
}
|
|
date = #(strftime "%d-%m-%Y" (localtime (current-time)))
|
|
\header {
|
|
logo = \date
|
|
scorenumber = \markup \concat { \fromproperty #'header:scorenumberbase "-" \fromproperty #'header:instrumentnr }
|
|
pdftitle = \markup \line {\concat{\fromproperty #'header:shortcomposer ":"} \concat {\fromproperty #'header:title ","} \fromproperty #'header:instrument \fromproperty #'header:scoretype }
|
|
}
|
|
|
|
|
|
titleScoreMarkup = \markup \piece-title \fromproperty #'header:piece
|
|
|
|
\paper {
|
|
scoreTitleMarkup = \titleScoreMarkup
|
|
bookTitleMarkup = \titleHeaderMarkup
|
|
}
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%% headers and footers %%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
#(define (first-score-page layout props arg)
|
|
(let* ((label 'first-score-page)
|
|
(table (ly:output-def-lookup layout 'label-page-table))
|
|
(label-page (and (list? table) (assoc label table)))
|
|
(page-number (and label-page (cdr label-page)))
|
|
)
|
|
(if (eq? (chain-assoc-get 'page:page-number props -1) page-number)
|
|
(interpret-markup layout props arg)
|
|
empty-stencil)))
|
|
|
|
#(define no-header-table '(1))
|
|
addNoHeaderPage = #(define-music-function (parser location nr) (number?)
|
|
(set! no-header-table (cons nr no-header-table))
|
|
(make-music 'Music 'void #t))
|
|
setNoHeaderPages = #(define-music-function (parser location pages) (list?)
|
|
(set! no-header-table pages)
|
|
(make-music 'Music 'void #t))
|
|
|
|
#(define (is-header-page layout props arg)
|
|
(let* ((page-number (chain-assoc-get 'page:page-number props -1)))
|
|
(if (not (member page-number no-header-table))
|
|
(interpret-markup layout props arg)
|
|
empty-stencil)))
|
|
|
|
#(define no-footer-table '(1))
|
|
addNoFooterPage = #(define-music-function (parser location nr) (number?)
|
|
(set! no-footer-table (cons nr no-footer-table))
|
|
(make-music 'Music 'void #t))
|
|
setNoFooterPages = #(define-music-function (parser location pages) (list?)
|
|
(set! no-footer-table pages)
|
|
(make-music 'Music 'void #t))
|
|
|
|
#(define (is-footer-page layout props arg)
|
|
(let* ((page-number (chain-assoc-get 'page:page-number props -1)))
|
|
(if (not (member page-number no-footer-table))
|
|
(interpret-markup layout props arg)
|
|
empty-stencil)))
|
|
|
|
#(define copyright-pages-table '(1))
|
|
addCopyrightPage = #(define-music-function (parser location nr) (number?)
|
|
(set! copyright-pages-table (cons nr copyright-pages-table))
|
|
(make-music 'Music 'void #t))
|
|
setCopyrightPages = #(define-music-function (parser location pages) (list?)
|
|
(set! copyright-pages-table pages)
|
|
(make-music 'Music 'void #t))
|
|
|
|
#(define (is-copyright-page layout props arg)
|
|
(let* ((page-number (chain-assoc-get 'page:page-number props -1)))
|
|
(if (member page-number copyright-pages-table)
|
|
(interpret-markup layout props arg)
|
|
empty-stencil)))
|
|
|
|
|
|
|
|
\paper {
|
|
olyStdOddHeaderMarkup = \markup \fill-line {
|
|
%% force the header to take some space, otherwise the
|
|
%% page layout becomes a complete mess.
|
|
" "
|
|
\on-the-fly #is-header-page \fromproperty #'header:title
|
|
\on-the-fly #is-header-page \fromproperty #'page:page-number-string
|
|
}
|
|
olyStdEvenHeaderMarkup = \markup \fill-line {
|
|
\on-the-fly #is-header-page \fromproperty #'page:page-number-string
|
|
\on-the-fly #is-header-page \fromproperty #'header:composer
|
|
" "
|
|
}
|
|
olyInstrumentOddHeaderMarkup = \markup \fill-line {
|
|
" "
|
|
\on-the-fly #is-header-page \concat { \fromproperty #'header:instrument }
|
|
\on-the-fly #is-header-page \fromproperty #'page:page-number-string
|
|
}
|
|
olyInstrumentEvenHeaderMarkup = \markup \fill-line {
|
|
\on-the-fly #is-header-page \fromproperty #'page:page-number-string
|
|
\on-the-fly #is-header-page \concat { \fromproperty #'header:composer ": " \fromproperty #'header:title }
|
|
" "
|
|
}
|
|
oddHeaderMarkup = \olyStdOddHeaderMarkup
|
|
evenHeaderMarkup = \olyStdEvenHeaderMarkup
|
|
|
|
olyStdOddFooterMarkup = \markup {
|
|
\column {
|
|
\fill-line {
|
|
%% publisher header field only on title page.
|
|
\on-the-fly #first-page \fromproperty #'header:publisher
|
|
}
|
|
\fill-line {
|
|
%% copyright on the first real score page
|
|
\on-the-fly #is-copyright-page \fromproperty #'header:copyright
|
|
\on-the-fly #is-copyright-page \null
|
|
}
|
|
\fill-line {
|
|
%% All other pages get the number of the edition centered
|
|
\on-the-fly #is-footer-page \fromproperty #'header:scorenumber
|
|
}
|
|
}
|
|
}
|
|
olyInstrumentOddFooterMarkup = \markup {
|
|
\column {
|
|
\fill-line {
|
|
%% copyright on the first real score page
|
|
\on-the-fly #is-copyright-page \fromproperty #'header:copyright
|
|
\on-the-fly #is-copyright-page \null
|
|
}
|
|
\fill-line {
|
|
%% All other pages get the number of the edition centered
|
|
\on-the-fly #is-footer-page \fromproperty #'header:scorenumber
|
|
}
|
|
}
|
|
}
|
|
oddFooterMarkup = \olyStdOddFooterMarkup
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
% Interpret the given markup with the header fields added to the props.
|
|
% This way, one can re-use the same functions (using fromproperty
|
|
% #'header:field) in the header block and as top-level markup.
|
|
%
|
|
% This function is originally copied from mark-up-title (file scm/titling.scm),
|
|
% which is lilypond's internal function to handle the title markups. I needed
|
|
% to replace the scopes and manually add the $defaultheader (which is internally
|
|
% done in paper-book.cc before calling mark-up-title. Also, I don't extract the
|
|
% markup from the header block, but use the given markup.
|
|
%
|
|
% I'm not sure if I really need the page properties in props, too... But I
|
|
% suppose it does not hurt, either.
|
|
#(define-markup-command (markupWithHeader layout props markup) (markup?)
|
|
"Interpret the given markup with the header fields added to the props.
|
|
This way, one can re-use the same functions (using fromproperty
|
|
#'header:field) in the header block and as top-level markup."
|
|
(let* (
|
|
; TODO: If we are inside a score, add the score's local header block, too!
|
|
; Currently, I only use the global header block, stored in $defaultheader
|
|
(scopes (list $defaultheader))
|
|
(alists (map ly:module->alist scopes))
|
|
|
|
(prefixed-alist
|
|
(map (lambda (alist)
|
|
(map (lambda (entry)
|
|
(cons
|
|
(string->symbol (string-append "header:" (symbol->string (car entry))))
|
|
(cdr entry)))
|
|
alist))
|
|
alists))
|
|
(props (append prefixed-alist
|
|
props
|
|
(layout-extract-page-properties layout)))
|
|
)
|
|
(interpret-markup layout props markup)
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% Equally spacing multiple columns (e.g. for translations)
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
% Credits: Nicolas Sceaux on the lilypond-user mailinglist
|
|
#(define-markup-command (columns layout props args) (markup-list?)
|
|
(let ((line-width (/ (chain-assoc-get 'line-width props
|
|
(ly:output-def-lookup layout 'line-width))
|
|
(max (length args) 1))))
|
|
(interpret-markup layout props
|
|
(make-line-markup (map (lambda (line)
|
|
(markup #:pad-to-box `(0 . ,line-width) '(0 . 0)
|
|
#:override `(line-width . ,line-width)
|
|
line))
|
|
args)))))
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% SCORE (HEADER / LAYOUT) SETTINGS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
startSlashedGraceMusic = {
|
|
\override Flag #'stroke-style = #"grace"
|
|
}
|
|
|
|
stopSlashedGraceMusic = {
|
|
\revert Flag #'stroke-style
|
|
}
|
|
|
|
slashedGrace =
|
|
#(def-grace-function startSlashedGraceMusic stopSlashedGraceMusic
|
|
(_i "Create slashed graces (slashes through stems, but no slur)from the following music expression"))
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% SCORE (HEADER / LAYOUT) SETTINGS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\paper {
|
|
footnote-separator-markup = \markup { \fill-line { \override #`(span-factor . 1/4) { \draw-hline } \null }}
|
|
|
|
left-margin = 2\cm
|
|
right-margin = 1.5\cm
|
|
line-width = 17.5\cm
|
|
% bottom-margin = 1.5\cm
|
|
top-margin = 0.7\cm
|
|
ragged-right = ##f
|
|
ragged-last = ##f
|
|
ragged-bottom = ##f
|
|
ragged-last-bottom = ##f
|
|
}
|
|
\layout {
|
|
\context {
|
|
\ChoirStaff
|
|
% If only one non-empty staff in a system exists, still print the backet
|
|
\override SystemStartBracket #'collapse-height = #1
|
|
\consists "Instrument_name_engraver"
|
|
\consists "Keep_alive_together_engraver"
|
|
}
|
|
\context {
|
|
\StaffGroup
|
|
% If only one non-empty staff in a system exists, still print the backet
|
|
\override SystemStartBracket #'collapse-height = #1
|
|
\consists "Instrument_name_engraver"
|
|
}
|
|
\context {
|
|
\GrandStaff
|
|
\override SystemStartBracket #'collapse-height = #1
|
|
\consists "Instrument_name_engraver"
|
|
}
|
|
\context {
|
|
\FiguredBass
|
|
\override VerticalAxisGroup #'padding = #0
|
|
}
|
|
\context {
|
|
\Score
|
|
% Force multi-measure rests to be written as one span
|
|
\override MultiMeasureRest #'expand-limit = #3
|
|
skipBars = ##t
|
|
autoBeaming = ##f
|
|
\override CombineTextScript #'avoid-slur = #'outside
|
|
\override DynamicTextSpanner #'style = #'none
|
|
\override InstrumentSwitch #'font-size = #-1
|
|
|
|
% Rest collision
|
|
\override RestCollision #'positioning-done = #merge-rests-on-positioning
|
|
% Auto-Accidentals: Use modern-cautionary style...
|
|
extraNatural = ##f
|
|
% Accidental rules (the rule giving the most accidentals wins!)
|
|
% -) Reset accidentals at each barline -> accs not in key sig will always be printed
|
|
% -) Same octave accidentals are remembered for two measures -> cancellation
|
|
% -) other octave accidentals are remembered for next measure -> cancellation
|
|
autoAccidentals = #`(Staff ,(make-accidental-rule 'same-octave 0)
|
|
,(make-accidental-rule 'any-octave 0)
|
|
,(make-accidental-rule 'any-octave 1)
|
|
,(make-accidental-rule 'same-octave 2))
|
|
% No auto-cautionaries, we always use autoAccidentals!
|
|
% autoCautionaries = #`(Staff ,(make-accidental-rule 'any-octave 0)
|
|
% ,(make-accidental-rule 'same-octave 1))
|
|
printKeyCancellation = ##t
|
|
quotedEventTypes = #'(StreamEvent)
|
|
quotedCueEventTypes = #'(
|
|
rhythmic-event
|
|
tie-event
|
|
beam-event
|
|
tuplet-span-event
|
|
tremolo-event
|
|
glissando-event
|
|
harmonic-event
|
|
repeat-tie-event
|
|
articulation-event
|
|
slur-event
|
|
trill-span-event
|
|
tremolo-span-event
|
|
)
|
|
implicitBassFigures = #'(0 100)
|
|
}
|
|
\context {
|
|
\Staff
|
|
\RemoveEmptyStaves
|
|
}
|
|
}
|
|
|
|
|
|
ts = #(make-music 'TextScriptEvent 'text "t.s." 'direction UP )
|
|
tt = #(make-music 'TextScriptEvent 'text "Tutti" 'direction UP )
|
|
solo = #(make-music 'TextScriptEvent 'text "Solo" 'direction UP )
|
|
tutti = #(make-music 'TextScriptEvent 'text "Tutti" 'direction UP )
|
|
bracketts = #(make-music 'TextScriptEvent 'text "[t.s.]" 'direction UP )
|
|
brackettt = #(make-music 'TextScriptEvent 'text "[Tutti]" 'direction UP )
|
|
bracketsolo = #(make-music 'TextScriptEvent 'text "[Solo]" 'direction UP )
|
|
|
|
sottovoce = #(make-music 'TextScriptEvent 'text "sotto voce" 'direction UP )
|
|
|
|
dashedSlur = -\tweak #'dash-definition #'((0 1 0.4 0.75))(
|
|
dashedTie = -\tweak #'dash-definition #'((0 1 0.4 0.75))~
|
|
|
|
divisi = #(define-music-function (parser location vc1 vc2) (ly:music? ly:music?)
|
|
#{
|
|
<< { \voiceOne $vc1 \oneVoice} \context Voice = "divisi2" { \voiceTwo $vc2 } >>
|
|
#}
|
|
)
|
|
|
|
#(define twoVoice divisi)
|
|
|
|
#(define-public (bracket-stencils grob)
|
|
(let ((lp (grob-interpret-markup grob (markup #:fontsize 3.5 #:translate (cons -0.3 -0.5) "[")))
|
|
(rp (grob-interpret-markup grob (markup #:fontsize 3.5 #:translate (cons -0.3 -0.5) "]"))))
|
|
(list lp rp)))
|
|
|
|
bracketify = #(define-music-function (parser loc arg) (ly:music?)
|
|
(_i "Tag @var{arg} to be parenthesized.")
|
|
#{
|
|
\once \override ParenthesesItem #'stencils = #bracket-stencils
|
|
\parenthesize $arg
|
|
#})
|
|
|
|
|
|
|
|
#(define-markup-command (hat layout props arg) (markup?)
|
|
"Draw a hat above the given string @var{arg}."
|
|
(interpret-markup layout props (markup #:combine #:raise 1.5 "^" arg)))
|
|
|
|
|
|
|
|
smallFlageolet =
|
|
#(let ((m (make-music 'ArticulationEvent
|
|
'articulation-type "flageolet")))
|
|
(ly:music-set-property! m 'tweaks
|
|
(acons 'font-size -2
|
|
(ly:music-property m 'tweaks)))
|
|
m)
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% LICENSE TEXTS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
LicenseCCBYPlain = \markup {Creative Commons BY \with-url #"http://creativecommons.org/licenses/by/3.0/at/" {\translate #'(0 . -0.7) \epsfile #Y #3 #"orchestrallily/cc-by.eps" }}
|
|
LicenseCCBY = \markup {Lizensiert unter / Licensed under: Creative Commons BY \with-url #"http://creativecommons.org/licenses/by/3.0/at/" {\translate #'(0 . -0.7) \epsfile #Y #3 #"orchestrallily/cc-by.eps" }}
|
|
LicenseCCBYNC = \markup {Lizensiert unter / Licensed under: Creative Commons BY-NC \with-url #"http://creativecommons.org/licenses/by-nc/3.0/at/" {\translate #'(0 . -0.7) \epsfile #Y #3 #"orchestrallily/cc-by-nc.eps" }}
|
|
LicenseNoRestrictions = \markup{\line {Die Ausgabe darf kopiert und ohne Einschränkungen aufgeführt werden. / May be copied and performed without restriction.}}
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% VARIOUS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
startUnremovableSection = \set Staff.keepAliveInterfaces =
|
|
#'(rhythmic-grob-interface
|
|
rest-interface
|
|
lyric-interface
|
|
percent-repeat-item-interface
|
|
percent-repeat-interface
|
|
stanza-number-interface)
|
|
|
|
endUnremovableSection = \unset Staff.keepAliveInterfaces
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% EDITORIAL ANNOTATIONS
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
#(define-public (editorial-bracket-stencil stil padding widen)
|
|
"Add brackets for editorial annoations around STIL, producing a new stencil."
|
|
(let* ((axis Y)
|
|
(other-axis (lambda (a) (remainder (+ a 1) 2)))
|
|
(ext (interval-widen (ly:stencil-extent stil axis) widen))
|
|
(thick 0.15)
|
|
(protrusion 0.3)
|
|
(lb (ly:bracket axis ext thick protrusion))
|
|
(rb (ly:bracket axis ext thick (- protrusion))))
|
|
(set! stil (ly:stencil-combine-at-edge stil (other-axis axis) 1 rb padding))
|
|
(set! stil
|
|
(ly:stencil-combine-at-edge lb (other-axis axis) 1 stil padding))
|
|
stil))
|
|
|
|
editorialHairpin = \once \override Hairpin #'stencil = #(lambda (grob) (editorial-bracket-stencil (ly:hairpin::print grob) 0.2 0.55))
|
|
editorialDynamic = \once \override DynamicText #'stencil = #(lambda (grob) (editorial-bracket-stencil (ly:text-interface::print grob) 0.2 0.55))
|
|
editorialMarkup = \once \override TextScript #'stencil = #(lambda (grob) (editorial-bracket-stencil (ly:text-interface::print grob) 0.2 0.55))
|
|
|
|
% videStart = \mark \markup { \hspace #1 \musicglyph #"scripts.coda" \with-dimensions #'(0 . 0) #'(0 . 0) \left-align { vi-} }
|
|
videStart = \mark \markup \halign #-2.3 \concat { \hspace #4.5 \musicglyph #"scripts.coda" \left-align { vi- } }
|
|
% videEnd = \notemode {
|
|
% \once \override Score.RehearsalMark #'break-visibility = #begin-of-line-invisible
|
|
% \mark \markup \concat{ \with-dimensions #'(0 . 0) #'(0 . 0) \right-align { -de } \hspace #1 \musicglyph #"scripts.coda" }
|
|
%}
|
|
videEnd = \notemode {
|
|
\once \override Score.RehearsalMark #'break-visibility = #begin-of-line-invisible
|
|
\mark \markup \concat{ \right-align { -de } \hspace #1.5 \musicglyph #"scripts.coda" \hspace #4.2 }
|
|
}
|
|
|
|
|
|
|
|
\layout {
|
|
\context {\Staff
|
|
soloText = #"I"
|
|
soloIIText = #"II"
|
|
aDueText = #"a2"
|
|
}
|
|
}
|
|
|
|
\paper {
|
|
% annotate-spacing = ##t
|
|
ragged-bottom = ##f
|
|
ragged-last = ##f
|
|
ragged-last-bottom = ##f
|
|
|
|
top-markup-spacing #'minimum-distance = #5
|
|
% top-markup-spacing #'basic-distance = #4
|
|
% top-markup-spacing #'padding = #2
|
|
top-markup-spacing #'stretchability = #15
|
|
|
|
top-system-spacing #'minimum-distance = #0
|
|
% top-system-spacing #'basic-distance = #3
|
|
top-system-spacing #'padding = #2
|
|
top-system-spacing #'stretchability = #13
|
|
|
|
markup-system-spacing #'minimum-distance = #5
|
|
% markup-system-spacing #'basic-distance = #4
|
|
markup-system-spacing #'padding = #3
|
|
markup-system-spacing #'stretchability = #25
|
|
|
|
system-system-spacing #'minimum-distance = #0
|
|
% system-system-spacing #'basic-distance = #5
|
|
system-system-spacing #'padding = #2
|
|
system-system-spacing #'stretchability = #15
|
|
|
|
last-bottom-spacing #'basic-distance = #3
|
|
% last-bottom-spacing #'basic-distance = #7
|
|
last-bottom-spacing #'padding = #4
|
|
last-bottom-spacing #'stretchability = #14
|
|
|
|
% score-markup-spacing #'basic-distance = #5
|
|
% score-markup-spacing #'stretchability = #15
|
|
|
|
% markup-markup-spacing #'basic-distance = #5
|
|
% markup-markup-spacing #'stretchability = #30
|
|
}
|
|
|
|
\layout {
|
|
\context { \PianoStaff
|
|
\override StaffGrouper #'staff-staff-spacing #'stretchability = #1.5
|
|
}
|
|
\context { \StaffGroup
|
|
\override StaffGrouper #'staff-staff-spacing #'stretchability = #2.5
|
|
\override SystemStartBracket #'collapse-height = #1
|
|
}
|
|
\context { \GrandStaff
|
|
\override StaffGrouper #'staff-staff-spacing #'stretchability = #3
|
|
\override StaffGrouper #'staffgroup-staff-spacing #'stretchability = #3
|
|
}
|
|
\context { \ChoirStaff
|
|
\override StaffGrouper #'staff-staff-spacing #'stretchability = #1
|
|
}
|
|
\context { \Staff
|
|
\override StaffGrouper #'staff-staff-spacing #'stretchability = #4.9
|
|
}
|
|
\context { \Score
|
|
\override StaffGrouper #'staff-staff-spacing #'stretchability = #5
|
|
}
|
|
}
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%% WORKAROUNDS!
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
% _ does not work as a direction modifier in figured bass
|
|
tsdown = #(make-music 'TextScriptEvent 'text "t.s." 'direction DOWN )
|