--- /dev/null
+\version "2.15.6"
+
+\header{
+ texidoc="
+Braces can be used to show organ keyboard changes.
+"
+}
+
+\score {
+ <<
+ \new PianoStaff <<
+ { << { d''2~\brace d''~ d'' } \\ { s1 <a d' f'>2\brace a' } >> }
+ \new Dynamics { s1-\markup \bold \upright "G.O." }
+ { f8\brace
+ \once \override Brace #'minimum-brace-height = #1
+ \once \override Brace #'positions = #'(-5.5 . 0)
+ <a' c' e'>\brace-\markup \bold "Pos." a' a' a'2\brace f'\brace f' }
+ >>
+ \new Staff { \clef F R1 d2\brace d }
+ >>
+ \layout {
+ ragged-right = ##t
+ \context {
+ \Score
+ \consists Span_brace_engraver
+ connectBraces = ##t
+ }
+ }
+}
#include "arpeggio.hh"
+#include "all-font-metrics.hh"
#include "bezier.hh"
#include "font-interface.hh"
#include "grob.hh"
return mol.smobbed_copy ();
}
+MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_brace, 1);
+SCM
+Arpeggio::brew_chord_brace (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Interval heads = robust_scm2interval (me->get_property ("positions"),
+ Interval ())
+ * Staff_symbol_referencer::staff_space (me);
+ int minimum_brace_height = robust_scm2int (
+ me->get_property ("minimum-brace-height"), 1);
+ Font_metric *fm = Font_interface::get_default_font (me);
+
+ int
+ lo = 0;
+ int hi = max ((int) fm->count () - 1, 2);
+
+ /* do a binary search for each Y, not very efficient, but passable? */
+ Box b;
+ do
+ {
+ int cmp = (lo + hi) / 2;
+ b = fm->get_indexed_char_dimensions (cmp);
+ if (b[Y_AXIS].is_empty () || b[Y_AXIS].length () > heads.length ()+1)
+ hi = cmp;
+ else
+ lo = cmp;
+ }
+ while (hi - lo > 1);
+
+ if (lo < minimum_brace_height)
+ lo = minimum_brace_height;
+
+ Stencil mol (unsmob_metrics (me->get_property ("font"))
+ ->find_by_name ("brace" + to_string (lo)));
+ mol.translate_axis ((heads[RIGHT] + heads[LEFT]) / 2, Y_AXIS);
+
+ return mol.smobbed_copy ();
+}
+
MAKE_SCHEME_CALLBACK (Arpeggio, brew_chord_slur, 1);
SCM
Arpeggio::brew_chord_slur (SCM smob)
/* properties */
"arpeggio-direction "
+ "minimum-brace-height "
"positions "
"script-priority " // TODO: make around-note-interface
"stems "
--- /dev/null
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2011 Bertrand Bordage
+ Mike Solomon
+
+ 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 "engraver.hh"
+
+#include "pointer-group-interface.hh"
+#include "arpeggio.hh"
+#include "stem.hh"
+#include "rhythmic-head.hh"
+#include "side-position-interface.hh"
+#include "stream-event.hh"
+#include "note-column.hh"
+#include "item.hh"
+
+#include "translator.icc"
+
+class Brace_engraver : public Engraver
+{
+public:
+ TRANSLATOR_DECLARATIONS (Brace_engraver);
+
+ void acknowledge_stem (Grob_info);
+ void acknowledge_rhythmic_head (Grob_info);
+protected:
+ void process_music ();
+ void stop_translation_timestep ();
+ DECLARE_TRANSLATOR_LISTENER (brace);
+
+private:
+ Item *brace_;
+ Stream_event *brace_event_;
+};
+
+Brace_engraver::Brace_engraver ()
+{
+ brace_ = 0;
+ brace_event_ = 0;
+}
+
+IMPLEMENT_TRANSLATOR_LISTENER (Brace_engraver, brace);
+void Brace_engraver::listen_brace (Stream_event *ev)
+{
+ ASSIGN_EVENT_ONCE (brace_event_, ev);
+}
+
+void
+Brace_engraver::acknowledge_stem (Grob_info info)
+{
+ if (brace_)
+ {
+ if (!brace_->get_parent (Y_AXIS))
+ brace_->set_parent (info.grob (), Y_AXIS);
+
+ Pointer_group_interface::add_grob (brace_,
+ ly_symbol2scm ("stems"),
+ info.grob ());
+ }
+}
+void
+Brace_engraver::acknowledge_rhythmic_head (Grob_info info)
+{
+ if (brace_)
+
+ /*
+ We can't catch local key items (accidentals) from Voice context,
+ see Local_key_engraver
+ */
+ Side_position_interface::add_support (brace_, info.grob ());
+}
+
+void
+Brace_engraver::process_music ()
+{
+ if (brace_event_)
+ brace_ = make_item ("Brace", brace_event_->self_scm ());
+}
+
+void
+Brace_engraver::stop_translation_timestep ()
+{
+ brace_ = 0;
+ brace_event_ = 0;
+}
+
+ADD_ACKNOWLEDGER (Brace_engraver, stem);
+ADD_ACKNOWLEDGER (Brace_engraver, rhythmic_head);
+
+ADD_TRANSLATOR (Brace_engraver,
+ /* doc */
+ "Generate a Brace symbol.",
+
+ /* create */
+ "Brace",
+
+ /* read */
+ "",
+
+ /* write */
+ ""
+ );
+
DECLARE_SCHEME_CALLBACK (print, (SCM));
DECLARE_SCHEME_CALLBACK (calc_positions, (SCM));
DECLARE_SCHEME_CALLBACK (brew_chord_bracket, (SCM));
+ DECLARE_SCHEME_CALLBACK (brew_chord_brace, (SCM));
DECLARE_SCHEME_CALLBACK (brew_chord_slur, (SCM));
DECLARE_SCHEME_CALLBACK (width, (SCM));
DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM));
--- /dev/null
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2011 Bertrand Bordage
+ Mike Solomon
+
+ 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 "engraver.hh"
+#include "arpeggio.hh"
+#include "pointer-group-interface.hh"
+#include "side-position-interface.hh"
+#include "staff-symbol-referencer.hh"
+#include "item.hh"
+
+/**
+ Make braces that span multiple staves. Catch braces, and span a
+ Span_brace over them if we find more than two braces.
+*/
+class Span_brace_engraver : public Engraver
+{
+public:
+ TRANSLATOR_DECLARATIONS (Span_brace_engraver);
+ DECLARE_ACKNOWLEDGER (brace);
+
+protected:
+ void process_acknowledged ();
+ void stop_translation_timestep ();
+
+private:
+ Item *span_brace_;
+ vector<Grob*> braces_;
+};
+
+Span_brace_engraver::Span_brace_engraver ()
+{
+ span_brace_ = 0;
+}
+
+void
+Span_brace_engraver::acknowledge_brace (Grob_info info)
+{
+ if (info.origin_contexts (this).size ()) // huh? what's this test for?
+ braces_.push_back (info.grob ());
+}
+
+void
+Span_brace_engraver::process_acknowledged ()
+{
+ /*
+ connectBraces is slightly brusque; we should really read a grob
+ property of the caught non-span braces. That way, we can have
+
+ both non-connected and connected braces in one pianostaff.
+
+ */
+ if (!span_brace_ && braces_.size () > 1
+ && to_boolean (get_property ("connectBraces")))
+ {
+ span_brace_ = make_item ("Brace", SCM_EOL);
+ span_brace_->set_property ("cross-staff", SCM_BOOL_T);
+ }
+}
+
+void
+Span_brace_engraver::stop_translation_timestep ()
+{
+ if (span_brace_)
+ {
+ /*
+ we do this very late, to make sure we also catch `extra'
+ side-pos support like accidentals.
+ */
+ for (vsize j = 0; j < braces_.size (); j++)
+ {
+ extract_grob_set (braces_[j], "stems", stems);
+ for (vsize i = 0; i < stems.size (); i++)
+ Pointer_group_interface::add_grob (span_brace_, ly_symbol2scm ("stems"),
+ stems[i]);
+
+ extract_grob_set (braces_[j], "side-support-elements", sses);
+ for (vsize i = 0; i < sses.size (); i++)
+ Pointer_group_interface::add_grob (span_brace_, ly_symbol2scm ("side-support-elements"),
+ sses[i]);
+
+ /*
+ we can't kill the children, since we don't want to the
+ previous note to bump into the span brace; so we make
+ it transparent. */
+ braces_[j]->set_property ("transparent", SCM_BOOL_T);
+ }
+
+
+ span_brace_->set_parent (braces_[0]->get_parent (Y_AXIS), Y_AXIS);
+ span_brace_ = 0;
+ }
+ braces_.clear ();
+}
+
+#include "translator.icc"
+
+ADD_ACKNOWLEDGER (Span_brace_engraver, brace);
+ADD_TRANSLATOR (Span_brace_engraver,
+ /* doc */
+ "Make braces that span multiple staves.",
+
+ /* create */
+ "Brace ",
+
+ /* read */
+ "connectBraces ",
+
+ /* write */
+ ""
+ );
\consists "Pitched_trill_engraver"
\consists "Output_property_engraver"
\consists "Arpeggio_engraver"
+ \consists "Brace_engraver"
\consists "Multi_measure_rest_engraver"
\consists "Text_spanner_engraver"
\consists "Trill_spanner_engraver"
\description "A voice on a percussion staff."
\remove "Arpeggio_engraver"
+ \remove "Brace_engraver"
\consists "Grob_pq_engraver"
\remove "Note_head_line_engraver"
\consists "Instrument_name_engraver"
\consists "Span_bar_engraver"
\consists "Span_arpeggio_engraver"
+ \consists "Span_brace_engraver"
\consists "System_start_delimiter_engraver"
\consists "Vertical_align_engraver"
systemStartDelimiter = #'SystemStartBrace
\consists "Instrument_name_engraver"
\consists "Span_bar_engraver"
\consists "Span_arpeggio_engraver"
+ \consists "Span_brace_engraver"
\consists "Output_property_engraver"
systemStartDelimiter = #'SystemStartBracket
%% explicitly set instrument, so it is not inherited from the parent
\override TimeSignature #'stencil = ##f
%% no arpeggios
\override Arpeggio #'stencil = ##f
+ \override Brace #'stencil = ##f
%% we ignore collision warnings that may occur due to
%% stem overlapping, because we have no stems ;-)
\override NoteColumn #'ignore-collision = ##t
% cross-staff brackets are desired.
arpeggio = #(make-music 'ArpeggioEvent)
+brace = #(make-music 'BraceEvent)
+
arpeggioArrowUp = {
\revert Arpeggio #'stencil
\revert Arpeggio #'X-extent
(completionBusy ,boolean? "Whether a completion-note head is playing.")
(connectArpeggios ,boolean? "If set, connect arpeggios across
piano staff.")
+ (connectBraces ,boolean? "If set, connect braces across
+staves.")
(countPercentRepeats ,boolean? "If set, produce counters for
percent repeats.")
(createKeyOnClefChange ,boolean? "Print a key signature whenever
arpeggio-event breathing-event extender-event span-event
rhythmic-event dynamic-event break-event label-event percent-event
key-change-event string-number-event stroke-finger-event tie-event
- part-combine-event part-combine-force-event
+ part-combine-event part-combine-force-event brace-event
beam-forbid-event script-event tempo-change-event
tremolo-event bend-after-event fingering-event glissando-event
harmonic-event hyphen-event laissez-vibrer-event mark-event
"Any kind of loudness sign."
'())
+(ly:add-interface
+ 'brace-interface
+ "A brace."
+ '())
+
(ly:add-interface
'dynamic-line-spanner-interface
"Dynamic line spanner."
appropriate callback for the @code{springs-and-rods} property. If
added to a @code{Tie}, this sets the minimum distance between
noteheads.")
+ (minimum-brace-height ,integer? "Specifies a minimum height for
+a brace. The unit is an increment in fetaBraces.")
(minimum-length-fraction ,number? "Minimum length of ledger line
as fraction of note head size.")
(minimum-space ,ly:dimension? "Minimum distance that the victim
font-interface
text-interface))))))
+ (Brace
+ . (
+ (direction . ,LEFT)
+ (font-encoding . fetaBraces)
+ (minimum-brace-height . 95)
+ (padding . 0.5)
+ (positions . ,ly:arpeggio::calc-positions)
+ (script-priority . 0)
+ (side-axis . ,X)
+ (staff-position . 0.0)
+ (stencil . ,ly:arpeggio::brew-chord-brace)
+ (X-extent . (-1 . 0))
+ (X-offset . ,ly:side-position-interface::x-aligned-side)
+ (Y-offset . ,ly:staff-symbol-referencer::callback)
+ (meta . ((class . Item)
+ (interfaces . (arpeggio-interface
+ brace-interface
+ font-interface
+ side-position-interface
+ staff-symbol-referencer-interface))))))
+
(ChordName
. (
(after-line-breaking . ,ly:chord-name::after-line-breaking)
`(
(,ly:arpeggio::print . ,ly:arpeggio::pure-height)
(,ly:arpeggio::brew-chord-bracket . ,ly:arpeggio::pure-height)
+ (,ly:arpeggio::brew-chord-brace . ,ly:arpeggio::pure-height)
(,ly:arpeggio::brew-chord-slur . ,ly:arpeggio::pure-height)
(,ly:hairpin::print . ,ly:hairpin::pure-height)
(,ly:stem-tremolo::print . ,ly:stem-tremolo::pure-height)
'BeamEvent
'BeamForbidEvent
'BendAfterEvent
+ 'BraceEvent
'CrescendoEvent
'DecrescendoEvent
'EpisemaEvent
(format #f "\\rightHandFinger #~a" (ly:music-property event 'digit)))
(define-span-event-display-method BeamEvent (event parser) #f "[" "]")
+(define-post-event-display-method BraceEvent (event parser) #t "\\brace")
(define-span-event-display-method SlurEvent (event parser) #f "(" ")")
(define-span-event-display-method CrescendoEvent (event parser) #f "\\<" "\\!")
(define-span-event-display-method DecrescendoEvent (event parser) #f "\\>" "\\!")
(types . (general-music event breathing-event))
))
+ (BraceEvent
+ . ((description . "Make a brace for this chord.
+
+Syntax: @var{chord}@code{-\\brace}")
+ (types . (general-music brace-event event))
+ ))
+
(ClusterNoteEvent
. ((description . "A note that is part of a cluster.")
;; not a note-event, to ensure that Note_heads_engraver doesn't eat it.
ly:accidental-interface::print
ly:arpeggio::print
ly:arpeggio::brew-chord-bracket
+ ly:arpeggio::brew-chord-brace
ly:bar-line::print
ly:breathing-sign::offset-callback
ly:clef::print