diff options
author | Reinhold Kainhofer <reinhold@kainhofer.com> | 2010-09-28 15:03:20 +0200 |
---|---|---|
committer | Reinhold Kainhofer <reinhold@kainhofer.com> | 2010-12-29 02:06:34 +0100 |
commit | 29640aafbf7ad7b2191813c4c16d282f15a127fd (patch) | |
tree | f27e2558c456b46a6f367d97e98880cb99d3979d | |
parent | 9551796a06445e9570d5481a73aff11f1d259568 (diff) |
Clef support for cue notes
-) Added \cueDuringWithClef, which allows to specify a clef for
the cue notes. At the end of the cue section, the clef is
automatically reset to the containing voice's clef.
-) Cue clefs are implemented as CueClef and CueEndClef grobs,
created by a dedicated Cue_clef_engraver, which reads
some cueClef* context properties.
-) After a line break, a cue clef does NOT override the global clef
of the containing voice, but prints (in smaller size) after
the containing clef.
-rw-r--r-- | Documentation/changes.tely | 28 | ||||
-rw-r--r-- | input/regression/cue-clef-begin-of-score.ly | 20 | ||||
-rw-r--r-- | input/regression/cue-clef-new-line.ly | 30 | ||||
-rw-r--r-- | input/regression/cue-clef-octavation.ly | 26 | ||||
-rw-r--r-- | input/regression/cue-clef.ly | 25 | ||||
-rw-r--r-- | lily/cue-clef-engraver.cc | 241 | ||||
-rw-r--r-- | lily/pitch-scheme.cc | 4 | ||||
-rw-r--r-- | ly/engraver-init.ly | 2 | ||||
-rw-r--r-- | ly/music-functions-init.ly | 25 | ||||
-rw-r--r-- | scm/define-context-properties.scm | 11 | ||||
-rw-r--r-- | scm/define-grobs.scm | 81 | ||||
-rw-r--r-- | scm/define-music-properties.scm | 1 | ||||
-rw-r--r-- | scm/music-functions.scm | 10 | ||||
-rw-r--r-- | scm/parser-clef.scm | 59 |
14 files changed, 553 insertions, 10 deletions
diff --git a/Documentation/changes.tely b/Documentation/changes.tely index ddc6c575ce..29882e3eaf 100644 --- a/Documentation/changes.tely +++ b/Documentation/changes.tely @@ -67,6 +67,34 @@ which scares away people. @end ignore @item +By using @code{\cueDuringWithClef}, cue notes can now also have their own +clef, which is correctly reset at the end of the cue notes. At the begin +of each line, the standard clef is still displayed, but the cue clef is +shown after the time/key signature in smaller size. +@lilypond +vI = \relative c'' { \clef "treble" \repeat unfold 40 g4 } +\addQuote vIQuote { \vI } + +Solo = \relative c { + \clef "bass" + \cueDuringWithClef #"vIQuote" #DOWN #"treble" { R1 } | + c4 \cueDuringWithClef #"vIQuote" #DOWN #"treble" { + r4 r2 | + r4 + } c4 c2 | + \cueDuringWithClef #"vIQuote" #DOWN "soprano" { R1*2 \break R1 } | + c1 +} + +\score { + << + \new Staff \new Voice \Solo + >> +} +@end lilypond + + +@item Note names can be selected with a new @code{@bs{}language "italiano"} command, which can be used in safe mode. The old diff --git a/input/regression/cue-clef-begin-of-score.ly b/input/regression/cue-clef-begin-of-score.ly new file mode 100644 index 0000000000..9c3d69538b --- /dev/null +++ b/input/regression/cue-clef-begin-of-score.ly @@ -0,0 +1,20 @@ +\version "2.13.45" + +\header { + texidoc = "Clefs for cue notes at the start of a score should print the +standard clef plus a small cue clef after the time/key signature." +} + +vI = \relative c'' { \clef "treble" \repeat unfold 40 g4 } +\addQuote vIQuote { \vI } + +Solo = \relative c'' { + \clef "bass" + \cueDuringWithClef #"vIQuote" #DOWN #"treble" { r2 } d,,4 d4 | +} + +\score { + << + \new Staff \new Voice \Solo + >> +} diff --git a/input/regression/cue-clef-new-line.ly b/input/regression/cue-clef-new-line.ly new file mode 100644 index 0000000000..56f2e9311b --- /dev/null +++ b/input/regression/cue-clef-new-line.ly @@ -0,0 +1,30 @@ +\version "2.13.45" + +\header { + texidoc = "Clefs for cue notes and line breaks. If the cue notes start in a +new line, the cue clef should not be printed at the end of the previous line. +Similarly, an end clef for cue notes ending at a line break should only be +printed at the end of the line. + +Cue notes going over a line break should print the standard clef on the new +line plus an additional cue clef after the time/key signature." +} + +vI = \relative c'' { \clef "treble" \repeat unfold 40 g4 } +\addQuote vIQuote { \vI } + +Solo = \relative c { + \clef "bass" + c1 | \break + \cueDuringWithClef #"vIQuote" #UP #"tenor" { R1 } | \break + c1 | + \cueDuringWithClef #"vIQuote" #UP #"tenor" { R1 | \break + R1 } | + c1 +} + +\score { + << + \new Staff \new Voice \Solo + >> +} diff --git a/input/regression/cue-clef-octavation.ly b/input/regression/cue-clef-octavation.ly new file mode 100644 index 0000000000..cbe101024c --- /dev/null +++ b/input/regression/cue-clef-octavation.ly @@ -0,0 +1,26 @@ +\version "2.13.45" + +\header { + texidoc = "Octavation for clefs for cue notes." +} + +vI = \relative c'' { \clef "treble" \repeat unfold 40 g4 } +\addQuote vIQuote { \vI } + +Solo = \relative c' { + \clef "treble_8" c1 | + \cueDuringWithClef #"vIQuote" #UP #"bass^8" { R1 } | + c1 | \break + c c + \clef "bass^8" c1 | + \cueDuringWithClef #"vIQuote" #UP #"treble_8" { R1 R1 } | + c + \cueDuringWithClef #"vIQuote" #UP #"treble_8" { R1 \break R } | + c +} + +\score { + << + \new Staff \new Voice \Solo + >> +} diff --git a/input/regression/cue-clef.ly b/input/regression/cue-clef.ly new file mode 100644 index 0000000000..c29759ca2d --- /dev/null +++ b/input/regression/cue-clef.ly @@ -0,0 +1,25 @@ +\version "2.13.45" + +\header { + texidoc = "Clefs for cue notes: Print a cue clef at the begin of the cue +notes and a cancelling clef after the cue notes." +} + +vI = \relative c'' { \clef "treble" \repeat unfold 16 g4 } +\addQuote vIQuote { \vI } + +Solo = \relative c { + \clef "bass" + c4 \cueDuringWithClef #"vIQuote" #DOWN #"treble" { + r4 r2 | + r4 + } c4 c2 | + \cueDuringWithClef #"vIQuote" #DOWN "soprano" { R1*2 } | + c1 +} + +\score { + << + \new Staff \new Voice \Solo + >> +} diff --git a/lily/cue-clef-engraver.cc b/lily/cue-clef-engraver.cc new file mode 100644 index 0000000000..be4ddf44f7 --- /dev/null +++ b/lily/cue-clef-engraver.cc @@ -0,0 +1,241 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 1997--2010 Han-Wen Nienhuys <hanwen@xs4all.nl> + Mats Bengtsson <matsb@s3.kth.se> + Copyright (C) 2010 Reinhold Kainhofer <reinhold@kainhofer.com> + + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <cctype> +using namespace std; + +#include "item.hh" +#include "context.hh" +#include "bar-line.hh" +#include "staff-symbol-referencer.hh" +#include "engraver.hh" +#include "direction.hh" +#include "side-position-interface.hh" +#include "warn.hh" +#include "international.hh" + +#include "translator.icc" + +class Cue_clef_engraver : public Engraver +{ +public: + TRANSLATOR_DECLARATIONS (Cue_clef_engraver); + +protected: + void stop_translation_timestep (); + void process_music (); + DECLARE_ACKNOWLEDGER (bar_line); + + virtual void derived_mark () const; +private: + Item *clef_; + Item *octavate_; + + SCM prev_glyph_; + SCM prev_cpos_; + SCM prev_octavation_; + void create_clef (); + void create_end_clef (); + void set_glyph (); + void inspect_clef_properties (); + void create_octavate_eight (SCM oct); +}; + +void +Cue_clef_engraver::derived_mark () const +{ + scm_gc_mark (prev_octavation_); + scm_gc_mark (prev_cpos_); + scm_gc_mark (prev_glyph_); +} + +Cue_clef_engraver::Cue_clef_engraver () +{ + clef_ = 0; + octavate_ = 0; + + prev_octavation_ = prev_cpos_ = prev_glyph_ = SCM_EOL; +} + +void +Cue_clef_engraver::set_glyph () +{ + SCM glyph_sym = ly_symbol2scm ("glyph"); + SCM basic = ly_symbol2scm ("CueClef"); + execute_pushpop_property (context (), basic, glyph_sym, SCM_UNDEFINED); + execute_pushpop_property (context (), basic, glyph_sym, get_property ("cueClefGlyph")); + + basic = ly_symbol2scm ("CueEndClef"); + execute_pushpop_property (context (), basic, glyph_sym, SCM_UNDEFINED); + execute_pushpop_property (context (), basic, glyph_sym, get_property ("clefGlyph")); +} + +/** + Generate a clef at the start of a measure. (when you see a Bar, + ie. a breakpoint) +*/ +void +Cue_clef_engraver::acknowledge_bar_line (Grob_info info) +{ + Item *item = info.item (); + if (item && scm_is_string (get_property ("cueClefGlyph"))) + create_clef (); +} + +void +Cue_clef_engraver::create_octavate_eight (SCM oct) +{ + if (scm_is_number (oct) && scm_to_int (oct)) + { + Item *g = make_item ("OctavateEight", SCM_EOL); + + int abs_oct = scm_to_int (oct); + int dir = sign (abs_oct); + abs_oct = abs (abs_oct) + 1; + + SCM txt = scm_number_to_string (scm_from_int (abs_oct), + scm_from_int (10)); + + g->set_property ("text", + scm_list_n (ly_lily_module_constant ("vcenter-markup"), + txt, SCM_UNDEFINED)); + Side_position_interface::add_support (g, clef_); + + g->set_parent (clef_, Y_AXIS); + g->set_parent (clef_, X_AXIS); + g->set_property ("direction", scm_from_int (dir)); + + // Inherit the break-visibility from the clef! + SCM vis = clef_->get_property ("break-visibility"); + if (vis && g) + g->set_property ("break-visibility", vis); + + octavate_ = g; + } +} + +void +Cue_clef_engraver::create_clef () +{ + if (!clef_) + { + Item *c = make_item ("CueClef", SCM_EOL); + + clef_ = c; + SCM cpos = get_property ("cueClefPosition"); + if (scm_is_number (cpos)) + clef_->set_property ("staff-position", cpos); + + create_octavate_eight (get_property ("cueClefOctavation")); + } +} + +void +Cue_clef_engraver::create_end_clef () +{ + if (!clef_) + { + clef_ = make_item ("CueEndClef", SCM_EOL); + SCM cpos = get_property ("clefPosition"); + if (scm_is_number (cpos)) + clef_->set_property ("staff-position", cpos); + + create_octavate_eight (get_property ("clefOctavation")); + } +} + +void +Cue_clef_engraver::process_music () +{ + inspect_clef_properties (); +} + +void +Cue_clef_engraver::inspect_clef_properties () +{ + SCM glyph = get_property ("cueClefGlyph"); + SCM clefpos = get_property ("cueClefPosition"); + SCM octavation = get_property ("cueClefOctavation"); + + if (scm_equal_p (glyph, prev_glyph_) == SCM_BOOL_F + || scm_equal_p (clefpos, prev_cpos_) == SCM_BOOL_F + || scm_equal_p (octavation, prev_octavation_) == SCM_BOOL_F + || to_boolean (force_clef)) + { + set_glyph (); + if (scm_is_string (glyph)) + { + create_clef (); + if (clef_) + clef_->set_property ("non-default", SCM_BOOL_T); + } + else + create_end_clef (); + + prev_cpos_ = clefpos; + prev_glyph_ = glyph; + prev_octavation_ = octavation; + } + +} + +void +Cue_clef_engraver::stop_translation_timestep () +{ + if (clef_) + { + SCM vis = 0; + if (to_boolean (clef_->get_property ("non-default"))) + vis = get_property ("explicitCueClefVisibility"); + + if (vis) + { + clef_->set_property ("break-visibility", vis); + if (octavate_) + octavate_->set_property ("break-visibility", vis); + } + + clef_ = 0; + octavate_ = 0; + } +} + +ADD_ACKNOWLEDGER (Cue_clef_engraver, bar_line); +ADD_TRANSLATOR (Cue_clef_engraver, + /* doc */ + "Determine and set reference point for pitches in cued voices.", + + /* create */ + "CueClef " + "CueEndClef " + "OctavateEight ", + + /* read */ + "cueClefGlyph " + "cueClefOctavation " + "cueClefPosition " + "explicitCueClefVisibility " + "middleCCuePosition " + "clefOctavation ", + + /* write */ + "" + ); diff --git a/lily/pitch-scheme.cc b/lily/pitch-scheme.cc index be499050c1..58e31a3b93 100644 --- a/lily/pitch-scheme.cc +++ b/lily/pitch-scheme.cc @@ -168,6 +168,10 @@ LY_DEFINE (ly_set_middle_C_x, "ly:set-middle-C!", Context *c = unsmob_context (context); int clef_pos = robust_scm2int (c->get_property ("middleCClefPosition"), 0); int offset = robust_scm2int (c->get_property ("middleCOffset"), 0); + /* middleCCuePosition overrides the clef! */ + SCM cue_pos = c->get_property ("middleCCuePosition"); + if (scm_is_number (cue_pos)) + clef_pos = robust_scm2int (cue_pos, 0); c->set_property (ly_symbol2scm ("middleCPosition"), scm_from_int (clef_pos + offset)); return SCM_UNDEFINED; diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index d102d7c5d4..f5c4eab9b2 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -75,6 +75,7 @@ \consists "Figured_bass_engraver" \consists "Figured_bass_position_engraver" \consists "Script_row_engraver" + \consists "Cue_clef_engraver" localKeySignature = #'() createSpacing = ##t @@ -553,6 +554,7 @@ automatically when an output definition (a @code{\score} or automaticBars = ##t explicitClefVisibility = #all-visible + explicitCueClefVisibility = #end-of-line-invisible explicitKeySignatureVisibility = #all-visible implicitTimeSignatureVisibility = #end-of-line-invisible diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly index 9d66ee72ed..b591344ed5 100644 --- a/ly/music-functions-init.ly +++ b/ly/music-functions-init.ly @@ -214,6 +214,15 @@ clef = (_i "Set the current clef to @var{type}.") (make-clef-set type)) +cueClef = +#(define-music-function (parser location type) (string?) + (_i "Set the current cue clef to @var{type}.") + (make-cue-clef-set type)) +cueClefUnset = +#(define-music-function (parser location) () + (_i "Unset the current cue clef.") + (make-cue-clef-unset)) + cueDuring = #(define-music-function (parser location what dir main-music) (string? ly:dir? ly:music?) @@ -224,8 +233,20 @@ in a CueVoice oriented by @var{dir}.") 'quoted-context-type 'Voice 'quoted-context-id "cue" 'quoted-music-name what - 'quoted-voice-direction dir - 'origin location)) + 'quoted-voice-direction dir)) + +cueDuringWithClef = +#(define-music-function + (parser location what dir clef main-music) (string? ly:dir? string? ly:music?) + (_i "Insert contents of quote @var{what} corresponding to @var{main-music}, +in a CueVoice oriented by @var{dir}.") + (make-music 'QuoteMusic + 'element main-music + 'quoted-context-type 'Voice + 'quoted-context-id "cue" + 'quoted-music-name what + 'quoted-music-clef clef + 'quoted-voice-direction dir)) diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index d4cfe13766..795701ac74 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -174,6 +174,12 @@ crescendi. Available values are @samp{hairpin} and @samp{text}. If unset, a hairpin crescendo is used.") (crescendoText ,markup? "The text to print at start of non-hairpin crescendo, i.e., @samp{cresc.}.") + (cueClefGlyph ,string? "Name of the symbol within the music font.") + (cueClefOctavation ,integer? "Add this much extra octavation. +Values of 7 and -7 are common.") + (cueClefPosition ,number? "Where should the center of the clef +symbol go, measured in half staff spaces from the center of the +staff.") (currentBarNumber ,integer? "Contains the current barnumber. This property is incremented at every bar line.") @@ -210,6 +216,8 @@ values.") (explicitClefVisibility ,vector? "@samp{break-visibility} function for clef changes.") + (explicitCueClefVisibility ,vector? "@samp{break-visibility} +function for cue clef changes.") (explicitKeySignatureVisibility ,vector? "@samp{break-visibility} function for explicit key changes. @samp{\\override} of the @code{break-visibility} property will set the visibility for normal @@ -330,6 +338,9 @@ markup. Called with four arguments: text, duration, count and context.") (middleCClefPosition ,number? "The position of the middle C, as determined only by the clef. This can be calculated by looking at @code{clefPosition} and @code{clefGlyph}.") + (middleCCuePosition ,number? "The position of the middle C, +as determined only by the clef of the cue notes. This can be calculated by +looking at @code{cueClefPosition} and @code{cueClefGlyph}.") (middleCOffset ,number? "The offset of middle C from the position given by @code{middleCClefPosition} This is used for ottava brackets.") diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index d47633d48d..95df5c37d1 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -102,7 +102,9 @@ (break-visibility . ,begin-of-line-visible) (non-musical . #t) (space-alist . ( + (cue-end-clef . (extra-space . 0.5)) (clef . (extra-space . 0.5)) + (cue-clef . (extra-space . 0.5)) (key-signature . (extra-space . 0.0)) (staff-bar . (extra-space . 0.0)) (time-signature . (extra-space . 0.0)) @@ -415,9 +417,11 @@ (break-align-orders . ;; end of line #(( left-edge + cue-end-clef ambitus breathing-sign clef + cue-clef staff-bar key-cancellation key-signature @@ -427,9 +431,11 @@ ;; unbroken ( left-edge + cue-end-clef ambitus breathing-sign clef + cue-clef staff-bar key-cancellation key-signature @@ -446,6 +452,7 @@ key-signature staff-bar time-signature + cue-clef custos))) (non-musical . #t) (positioning-done . ,ly:break-alignment-interface::calc-positioning-done) @@ -467,6 +474,8 @@ (time-signature . (minimum-space . 1.5)) (staff-bar . (minimum-space . 1.5)) (clef . (minimum-space . 2.0)) + (cue-clef . (minimum-space . 2.0)) + (cue-end-clef . (minimum-space . 2.0)) (first-note . (fixed-space . 1.0)) ;huh? (right-edge . (extra-space . 0.1)))) (stencil . ,ly:text-interface::print) @@ -499,7 +508,7 @@ (break-visibility . ,begin-of-line-visible) (glyph-name . ,ly:clef::calc-glyph-name) (non-musical . #t) - (space-alist . ((ambitus . (extra-space . 2.0)) + (space-alist . ((cue-clef . (extra-space . 2.0)) (staff-bar . (extra-space . 0.7)) (key-cancellation . (minimum-space . 3.5)) (key-signature . (minimum-space . 3.5)) @@ -556,6 +565,61 @@ text-interface text-script-interface)))))) + (CueClef + . ( + (avoid-slur . inside) + (break-align-anchor . ,ly:break-aligned-interface::calc-extent-aligned-anchor) + (break-align-symbol . cue-clef) + (break-visibility . ,begin-of-line-visible) + (font-size . -3) + (glyph-name . ,ly:clef::calc-glyph-name) + (non-musical . #t) + (full-size-change . #t) + (space-alist . ((staff-bar . (minimum-space . 2.7)) + (key-cancellation . (minimum-space . 3.5)) + (key-signature . (minimum-space . 3.5)) + (time-signature . (minimum-space . 4.2)) + (custos . (minimum-space . 0.0)) + (first-note . (minimum-fixed-space . 3.0)) + (next-note . (extra-space . 0.5)) + (right-edge . (extra-space . 0.5)))) + (stencil . ,ly:clef::print) + (extra-spacing-height . (-0.5 . 0.5)) + (Y-offset . ,ly:staff-symbol-referencer::callback) + (meta . ((class . Item) + (interfaces . (break-aligned-interface + clef-interface + font-interface + staff-symbol-referencer-interface)))))) + + (CueEndClef + . ( + (avoid-slur . inside) + (break-align-anchor . ,ly:break-aligned-interface::calc-extent-aligned-anchor) + (break-align-symbol . cue-end-clef) + (break-visibility . ,begin-of-line-invisible) + (font-size . -3) + (glyph-name . ,ly:clef::calc-glyph-name) + (non-musical . #t) + (full-size-change . #t) + (space-alist . ((clef . (extra-space . 0.7)) + (cue-clef . (extra-space . 0.7)) + (staff-bar . (extra-space . 0.7)) + (key-cancellation . (minimum-space . 3.5)) + (key-signature . (minimum-space . 3.5)) + (time-signature . (minimum-space . 4.2)) + (first-note . (minimum-fixed-space . 5.0)) + (next-note . (extra-space . 0.5)) + (right-edge . (extra-space . 0.5)))) + (stencil . ,ly:clef::print) + (extra-spacing-height . (-0.5 . 0.5)) + (Y-offset . ,ly:staff-symbol-referencer::callback) + (meta . ((class . Item) + (interfaces . (break-aligned-interface + clef-interface + font-interface + staff-symbol-referencer-interface)))))) + (Custos . ( (break-align-symbol . custos) @@ -940,6 +1004,7 @@ (time-signature . (extra-space . 1.25)) (staff-bar . (extra-space . 0.6)) (key-signature . (extra-space . 0.5)) + (cue-clef . (extra-space . 0.5)) (right-edge . (extra-space . 0.5)) (first-note . (fixed-space . 2.5)))) (stencil . ,ly:key-signature-interface::print) @@ -962,6 +1027,7 @@ (space-alist . ( (time-signature . (extra-space . 1.15)) (staff-bar . (extra-space . 1.1)) + (cue-clef . (extra-space . 0.5)) (right-edge . (extra-space . 0.5)) (first-note . (fixed-space . 2.5)))) (stencil . ,ly:key-signature-interface::print) @@ -1014,16 +1080,18 @@ (break-visibility . ,center-invisible) (non-musical . #t) (space-alist . ( - (custos . (extra-space . 0.0)) (ambitus . (extra-space . 2.0)) - (time-signature . (extra-space . 1.0)) - (staff-bar . (extra-space . 0.0)) (breathing-sign . (minimum-space . 0.0)) + (cue-end-clef . (extra-space . 0.8)) (clef . (extra-space . 0.8)) + (cue-clef . (extra-space . 0.8)) + (staff-bar . (extra-space . 0.0)) + (key-cancellation . (extra-space . 0.0)) + (key-signature . (extra-space . 0.8)) + (time-signature . (extra-space . 1.0)) + (custos . (extra-space . 0.0)) (first-note . (fixed-space . 2.0)) (right-edge . (extra-space . 0.0)) - (key-signature . (extra-space . 0.8)) - (key-cancellation . (extra-space . 0.0)) )) (X-extent . (0 . 0)) (meta . ((class . Item) @@ -2087,6 +2155,7 @@ (extra-spacing-height . (-1.0 . 1.0)) (non-musical . #t) (space-alist . ( + (cue-clef . (extra-space . 1.5)) (first-note . (fixed-space . 2.0)) (right-edge . (extra-space . 0.5)) (staff-bar . (minimum-space . 2.0)))) diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index 23faf5644a..577b9d2925 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -148,6 +148,7 @@ e.g., @code{cue}.") direct quotes to, e.g., @code{Voice}.") (quoted-events ,vector? "A vector of with @code{moment} and @code{event-list} entries.") + (quoted-music-clef ,string? "The clef of the voice to quote.") (quoted-music-name ,string? "The name of the voice to quote.") (quoted-transposition ,ly:pitch? "The pitch used for the quote, overriding @code{\\transposition}.") diff --git a/scm/music-functions.scm b/scm/music-functions.scm index 688900411f..1f8b593318 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -782,6 +782,7 @@ Syntax: (if (vector? (ly:music-property quote-music 'quoted-events)) (let* ((dir (ly:music-property quote-music 'quoted-voice-direction)) + (clef (ly:music-property quote-music 'quoted-music-clef)) (main-voice (if (eq? 1 dir) 1 0)) (cue-voice (if (eq? 1 dir) 0 1)) (main-music (ly:music-property quote-music 'element)) @@ -793,14 +794,19 @@ Syntax: ;; to have opposite stems. (begin (set! return-value - ;; cannot context-spec Quote-music, since context ;; for the quotes is determined in the iterator. (make-sequential-music (list + (if (null? clef) + (make-music 'Music) + (make-cue-clef-set clef)) (context-spec-music (make-voice-props-set cue-voice) 'CueVoice "cue") quote-music - (context-spec-music (make-voice-props-revert) 'CueVoice "cue")))) + (context-spec-music (make-voice-props-revert) 'CueVoice "cue") + (if (null? clef) + (make-music 'Music) + (make-cue-clef-unset))))) (set! main-music (make-sequential-music (list diff --git a/scm/parser-clef.scm b/scm/parser-clef.scm index 757a1876de..f6e0fb9b0b 100644 --- a/scm/parser-clef.scm +++ b/scm/parser-clef.scm @@ -143,6 +143,65 @@ (sort (map car supported-clefs) string<?))) (make-music 'Music))))) +(define-public (make-cue-clef-set clef-name) + "Generate the clef setting commands for a cue clef with name CLEF-NAME." + (define (make-prop-set props) + (let ((m (make-music 'PropertySet))) + (map (lambda (x) (set! (ly:music-property m (car x)) (cdr x))) props) + m)) + (let ((e '()) + (c0 0) + (oct 0) + (match (string-match "^(.*)([_^])([1-9][0-9]*)$" clef-name))) + (if match + (begin + (set! clef-name (match:substring match 1)) + (set! oct + (* (if (equal? (match:substring match 2) "^") -1 1) + (- (string->number (match:substring match 3)) 1))))) + (set! e (assoc-get clef-name supported-clefs)) + (if e + (let* ((musics (map make-prop-set + `(((symbol . cueClefGlyph) (value . ,(car e))) + ((symbol . middleCCuePosition) + (value . ,(+ oct + (cadr e) + (assoc-get (car e) c0-pitch-alist)))) + ((symbol . cueClefPosition) (value . ,(cadr e))) + ((symbol . cueClefOctavation) (value . ,(- oct)))))) + (recalc-mid-C (make-music 'ApplyContext)) + (seq (make-music 'SequentialMusic + 'elements (append musics (list recalc-mid-C)))) + (csp (make-music 'ContextSpeccedMusic))) + (set! (ly:music-property recalc-mid-C 'procedure) ly:set-middle-C!) + (context-spec-music seq 'Staff)) + (begin + (ly:warning (_ "unknown clef type `~a'") clef-name) + (ly:warning (_ "supported clefs: ~a") + (string-join + (sort (map car supported-clefs) string<?))) + (make-music 'Music))))) + + +(define-public (make-cue-clef-unset) + "Reset the clef settings for a cue clef." + (define (make-prop-unset props) + (let ((m (make-music 'PropertyUnset))) + (set! (ly:music-property m (car props)) (cdr props)) + m)) + (let* ((musics (map make-prop-unset + `((symbol . cueClefGlyph) + (symbol . middleCCuePosition) + (symbol . cueClefPosition) + (symbol . cueClefOctavation)))) + (recalc-mid-C (make-music 'ApplyContext)) + (seq (make-music 'SequentialMusic + 'elements (append musics (list recalc-mid-C)))) + (csp (make-music 'ContextSpeccedMusic))) + (set! (ly:music-property recalc-mid-C 'procedure) ly:set-middle-C!) + (context-spec-music seq 'Staff))) + + ;; a function to add new clefs at runtime (define-public (add-new-clef clef-name clef-glyph clef-position octavation c0-position) "Append the entries for a clef symbol to supported clefs and c0-pitch-alist" |