+2005-05-06 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+ * Documentation/topdocs/NEWS.tely (Top): document new feature.
+
+ * Documentation/user/basic-notation.itely (Staff symbol): document
+ start/stop staff. Reference to ossia.ly
+
+ * input/test/ossia.ly: new example using stop and startStaff.
+
+ * lily/timing-engraver.cc: remove Timing_engraver::initialize(),
+ in other words, don't create "|" barline at start of the score.
+ (start_translation_timestep): don't set whichBar for start of score.
+
+ * input/regression/staff-halfway.ly: use new functionality.
+
+ * lily/staff-symbol-engraver.cc (try_music): take StaffSpanEvents,
+ start and stop staff based on events.
+
+ * scm/define-music-types.scm (music-descriptions): add StaffSpanEvent
+
+ * ly/declarations-init.ly (startStaff, stopStaff): new identifiers.
+
2005-05-05 Han-Wen Nienhuys <hanwen@xs4all.nl>
* Documentation/user/programming-interface.itely (How markups work
@itemize @bullet
+@item
+Staves may be stopped and started halfway a line, e.g.
+
+@lilypond[relative=2,fragment,verbatim]
+b4 b \stopStaff b \startStaff b
+@end lilypond
+
+@noindent
+This feature has been sponsored by Hans Forbrich.
+
@item
Grid lines, vertical lines synchronized with notes, can be drawn across
staves, by adding suitable engravers.
system, these lines are drawn using a separate layout object called
staff symbol.
+The staff symbol may be tuned in the number, thickness and distannce
+of lines, using properties. This is demonstrated in the example files
+@inputfileref{input/@/test,staff@/-lines@/.ly},
+@inputfileref{input/@/test,staff@/-size@/.ly}.
+
+In addition, staves may be started and stopped at will. This is done
+with @code{\startStaff} and @code{\stopStaff}.
+
+@lilypond[verbatim,relative=2,fragment]
+b4 b
+\override Staff.StaffSymbol #'line-count = 2
+\stopStaff \startStaff
+b b
+\revert Staff.StaffSymbol #'line-count
+\stopStaff \startStaff
+b b
+@end lilypond
+
+In combination with Frenched staves, this may be used to typeset ossia
+sections. An example is in @inputfileref{input/@/test@/,ossia.ly},
+shown here
+
+@cindex ossia
+
+@lilypondfile{ossia.ly}
@cindex staff lines, setting number of
@cindex staff lines, setting thickness of
@seealso
-Program reference: @internalsref{StaffSymbol}.
+Program reference: @internalsref{StaffSymbol}, @internalsref{StaffSpanEvent}.
Examples: @inputfileref{input/@/test,staff@/-lines@/.ly},
+@inputfileref{input/@/test@/,ossia.ly},
@inputfileref{input/@/test,staff@/-size@/.ly}.
-@refbugs
-
-If a staff is ended halfway a piece, the staff symbol may not end
-exactly on the bar line.
-
@node Key signature
@subsection Key signature
+\header {
+ texidoc = "Staves can be started and stopped at command. "
+}
-\header { texidoc = " Staves starting and ending halfway include clefs
- and bar lines. " }
+\version "2.5.23"
-\version "2.4.0"
+\paper {
+ raggedright = ##t
+}
-\score {
- \new StaffGroup \relative c'' <<
- \new Staff { c4 c c c \bar "||" c c c c }
- { \skip 4 \new Staff { c c c } }
- >>
- \layout {}
- }
+\relative c'' {
+ b b \stopStaff b b \startStaff
+ \clef bass
+ c,, c
+}
-\header { texidoc = "A temporary ossia in an instrumental part may
- be printed using a separate, short staff. A simpler solution is
- also given: instantiate a full staff, and let
- @code{RemoveEmptyStaffContext} take out the unused parts.
-" }
-\version "2.4.0"
+\header { texidoc = "Ossia fragments can be done with starting and
+stopping staves. " }
-\score {
- \relative c''
- \new StaffGroup \with {
- \remove "System_start_delimiter_engraver"
- \override SpanBar #'glyph = #":"
- } <<
+\version "2.5.23"
+\paper { raggedright = ##t }
- %% solution 1
- { c1 c1
- <<
- { c1 c1 }
- \new Staff \with {
- \remove "Time_signature_engraver"
- fontSize = #-2
- \override StaffSymbol #'staff-space = #(magstep -2)
- } {
- c,4^"ossia" es f fis g1
- }
- >>
- c1 \break c c }
+<<
+ \new Staff \with
+ {
+ \remove "Time_signature_engraver"
+ fontSize = #-2
+ \override StaffSymbol #'staff-space = #(magstep -2)
+ firstClef = ##f
+ }
+ \relative c'' {
+ \stopStaff
+ \skip 2
- %% solution 2
- \new Staff \with {
- fontSize = #-2
- \override StaffSymbol #'staff-space = #(magstep -2)
-
- } { R1*2 c,4^"ossia" es f fis g1 R1 * 3 }
- >>
-
+ \startStaff
+ \clef treble
+ bes8[^"ossia" g bes g]
+ \stopStaff
- \layout {
- raggedright= ##t
- \context {\RemoveEmptyStaffContext}
- \context {
- \Score
- \remove System_start_delimiter_engraver
- }
- }
-}
+ s2
+ \startStaff
+ f8 d g4
+ }
+ \new Staff \relative
+ {
+ \time 2/4
+ c4 c g' g a a g2
+ }
+
+>>
SCM octavation = get_property ("clefOctavation");
SCM force_clef = get_property ("forceClef");
- if (clefpos == SCM_EOL
- || 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))
+ if (clefpos == SCM_EOL
+ || 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 ();
- create_clef ();
+ if (prev_cpos_ != SCM_BOOL_F || to_boolean (get_property ("firstClef")))
+ create_clef ();
- clef_->set_property ("non-default", SCM_BOOL_T);
+ if (clef_)
+ clef_->set_property ("non-default", SCM_BOOL_T);
prev_cpos_ = clefpos;
prev_glyph_ = glyph;
#include "spanner.hh"
#include "engraver.hh"
+/*
+ TODO: should sync with Staff_symbol_engraver.
+*/
class Ledger_line_engraver : public Engraver
{
Spanner *span_;
(c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
*/
-#include "score.hh"
-#include "paper-column.hh"
-#include "output-def.hh"
-#include "side-position-interface.hh"
-#include "engraver.hh"
-#include "moment.hh"
-
-/**
- Manage the staff symbol.
-*/
-class Staff_symbol_engraver : public Engraver
-{
-public:
- TRANSLATOR_DECLARATIONS (Staff_symbol_engraver);
-
-protected:
- Spanner *span_;
-
- virtual ~Staff_symbol_engraver ();
- virtual void acknowledge_grob (Grob_info);
- virtual void finalize ();
- virtual void process_music ();
-};
+#include "staff-symbol-engraver.hh"
+#include "spanner.hh"
Staff_symbol_engraver::~Staff_symbol_engraver ()
{
Staff_symbol_engraver::Staff_symbol_engraver ()
{
+ first_start_ = true;
span_ = 0;
+ span_events_[LEFT] = 0;
+ span_events_[RIGHT] = 0;
}
-void
-Staff_symbol_engraver::process_music ()
+bool
+Staff_symbol_engraver::try_music (Music *music)
{
- if (!span_)
+ Direction d = to_dir (music->get_property ("span-direction"));
+ if (d)
{
- span_ = make_spanner ("StaffSymbol", SCM_EOL);
-
- span_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));
+ span_events_[d] = music;
+ return true;
}
+
+ return false;
}
void
-Staff_symbol_engraver::finalize ()
+Staff_symbol_engraver::process_music ()
{
- if (span_)
+ if (span_events_[STOP])
{
- span_->set_bound (RIGHT, unsmob_grob (get_property ("currentCommandColumn")));
+ finished_span_ = span_;
+ span_ = 0;
}
- span_ = 0;
+
+ if (span_events_[START])
+ start_spanner ();
}
+
void
-Staff_symbol_engraver::acknowledge_grob (Grob_info s)
+Staff_symbol_engraver::initialize ()
{
- s.grob_->set_property ("staff-symbol", span_->self_scm ());
+ start_spanner ();
}
-ADD_TRANSLATOR (Staff_symbol_engraver,
- /* descr */ "Create the constellation of five (default) "
- "staff lines.",
- /* creats*/ "StaffSymbol",
- /* accepts */ "",
- /* acks */ "grob-interface",
- /* reads */ "",
- /* write */ "");
-
-/****************************************************************/
+void
+Staff_symbol_engraver::start_spanner ()
+{
+ if (!span_)
+ {
+ span_ = make_spanner ("StaffSymbol", SCM_EOL);
+ }
+}
-class Tab_staff_symbol_engraver : public Staff_symbol_engraver
+void
+Staff_symbol_engraver::stop_spanner ()
{
-public:
- TRANSLATOR_DECLARATIONS (Tab_staff_symbol_engraver);
-protected:
- virtual void process_music ();
-};
+ if (finished_span_ && !finished_span_->get_bound (RIGHT))
+ {
+ finished_span_->set_bound (RIGHT, unsmob_grob (get_property ("currentCommandColumn")));
+ }
+ finished_span_ = 0;
+}
void
-Tab_staff_symbol_engraver::process_music ()
+Staff_symbol_engraver::stop_translation_timestep ()
{
- bool init = !span_;
- Staff_symbol_engraver::process_music ();
- if (init)
+ if ((span_events_[START] || first_start_)
+ && span_
+ && !span_->get_bound (LEFT))
{
- int k = scm_ilength (get_property ("stringTunings"));
- if (k >= 0)
- span_->set_property ("line-count", scm_int2num (k));
+ span_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));
+ first_start_ = false;
}
+
+ span_events_[START] = 0;
+ span_events_[STOP] = 0;
+ stop_spanner ();
}
-Tab_staff_symbol_engraver::Tab_staff_symbol_engraver ()
+void
+Staff_symbol_engraver::finalize ()
+{
+ finished_span_ = span_;
+ span_ = 0;
+ stop_spanner ();
+}
+
+void
+Staff_symbol_engraver::acknowledge_grob (Grob_info s)
{
+
+ /*
+ Perhaps should try to take SeparationItem as bound of the staff
+ symbol?
+ */
+ if (span_)
+ s.grob_->set_property ("staff-symbol", span_->self_scm ());
}
-ADD_TRANSLATOR (Tab_staff_symbol_engraver,
- /* descr */ "Create a staff-symbol, but look at stringTunings for the number of lines."
+ADD_TRANSLATOR (Staff_symbol_engraver,
+ /* descr */ "Create the constellation of five (default) "
"staff lines.",
/* creats*/ "StaffSymbol",
- /* accepts */ "",
+ /* accepts */ "staff-span-event",
/* acks */ "grob-interface",
- /* reads */ "stringTunings",
+ /* reads */ "",
/* write */ "");
#include "all-font-metrics.hh"
#include "staff-symbol-referencer.hh"
#include "lookup.hh"
+#include "item.hh"
Stencil
System_start_delimiter::staff_bracket (Grob *me, Real height)
SCM
System_start_delimiter::after_line_breaking (SCM smob)
{
- Grob *me = unsmob_grob (smob);
+ Spanner *me = dynamic_cast<Spanner *> (unsmob_grob (smob));
+
SCM gl = me->get_property ("glyph");
if (ly_c_equal_p (gl, scm_makfrom0str ("bar-line")))
{
int count = 0;
+ Paper_column *left_column = me->get_bound (LEFT)->get_column ();
/*
Get all coordinates, to trigger Hara kiri.
Grob *common = common_refpoint_of_list (elts, me, Y_AXIS);
for (SCM s = elts; scm_is_pair (s); s = scm_cdr (s))
{
- Interval v = unsmob_grob (scm_car (s))->extent (common, Y_AXIS);
-
+ Spanner *staff = dynamic_cast<Spanner*> (unsmob_grob (scm_car (s)));
+ if (!staff ||
+ staff->get_bound (LEFT)->get_column () != left_column)
+ continue;
+
+ Interval v = staff->extent (common, Y_AXIS);
+
if (!v.is_empty ())
count++;
}
#include "engraver.hh"
#include "grob.hh"
-/**
- Do time bookkeeping
-*/
+
+
class Timing_engraver : public Timing_translator, public Engraver
{
protected:
- /* Needed to know whether we're advancing in grace notes, or not. */
+ /* Need to know whether we're advancing in grace notes, or not. */
Moment last_moment_;
virtual void start_translation_timestep ();
- virtual void initialize ();
virtual void process_music ();
virtual void stop_translation_timestep ();
TRANSLATOR_DECLARATIONS (Timing_engraver);
};
+ADD_TRANSLATOR (Timing_engraver,
+ /* descr */ " Responsible for synchronizing timing information from staves. "
+ "Normally in @code{Score}. In order to create polyrhythmic music, "
+ "this engraver should be removed from @code{Score} and placed in "
+ "@code{Staff}. "
+ "\n\nThis engraver adds the alias @code{Timing} to its containing context.",
+ /* creats*/ "",
+ /* accepts */ "",
+ /* acks */ "",
+ /* reads */ "automaticBars whichBar barAlways defaultBarType "
+ "skipBars timing measureLength measurePosition currentBarNumber",
+ /* write */ "");
+
+
Timing_engraver::Timing_engraver ()
{
last_moment_.main_part_ = Rational (-1);
}
-void
-Timing_engraver::initialize ()
-{
- Timing_translator::initialize ();
-
- SCM which = get_property ("whichBar");
- Moment now = now_mom ();
-
- /* Set the first bar of the score? */
- if (!scm_is_string (which))
- which = (now.main_part_ || now.main_part_ == last_moment_.main_part_)
- ? SCM_EOL : scm_makfrom0str ("|");
-
- context ()->set_property ("whichBar", which);
-}
-
void
Timing_engraver::process_music ()
{
{
SCM always = get_property ("barAlways");
- if (start_of_measure || (to_boolean (always)))
+ if ((start_of_measure && last_moment_.main_part_ >= Moment (0))
+ || to_boolean (always))
{
/* should this work, or be junked? See input/bugs/no-bars.ly */
which = get_property ("defaultBarType");
context ()->set_property ("whichBar", SCM_EOL);
last_moment_ = now_mom ();
}
-
-ADD_TRANSLATOR (Timing_engraver,
- /* descr */ " Responsible for synchronizing timing information from staves. "
- "Normally in @code{Score}. In order to create polyrhythmic music, "
- "this engraver should be removed from @code{Score} and placed in "
- "@code{Staff}. "
- "\n\nThis engraver adds the alias @code{Timing} to its containing context.",
- /* creats*/ "",
- /* accepts */ "",
- /* acks */ "",
- /* reads */ "automaticBars whichBar barAlways defaultBarType skipBars timing measureLength measurePosition currentBarNumber",
- /* write */ "");
noBreak = #(make-event-chord (list (make-penalty-music 10001 0)))
pageBreak = #(make-event-chord (list (make-penalty-music -10001 -10001)))
noPageBreak = #(make-event-chord (list (make-penalty-music 0 10001)))
+stopStaff = #(make-event-chord (list (make-span-event 'StaffSpanEvent STOP)))
+startStaff = #(make-event-chord (list (make-span-event 'StaffSpanEvent START)))
%
clefGlyph = #"clefs.G"
clefPosition = #-2
middleCPosition = #-6
+ firstClef = ##t
defaultBarType = #"|"
barNumberVisibility = #default-bar-number-visibility
slurDown = \override Slur #'direction = #-1
slurNeutral = \revert Slur #'direction
-% There's also dash, but setting dash period/length should be fixed.
+%% There's also dash, but setting dash period/length should be fixed.
slurDashed = {
- \override Slur #'dash-period = #0.75
- \override Slur #'dash-fraction = #0.4
+ \override Slur #'dash-period = #0.75
+ \override Slur #'dash-fraction = #0.4
}
slurDotted = {
- \override Slur #'dash-period = #0.75
- \override Slur #'dash-fraction = #0.1
+ \override Slur #'dash-period = #0.75
+ \override Slur #'dash-fraction = #0.1
}
slurSolid = {
- \revert Slur #'dash-period
- \revert Slur #'dash-fraction
+ \revert Slur #'dash-period
+ \revert Slur #'dash-fraction
}
tieSolid = \revert Tie #'dashed
setEasyHeads = \sequential {
- \override NoteHead #'print-function = #Note_head::brew_ez_stencil
- \override NoteHead #'Y-extent-callback = #'()
- \override NoteHead #'X-extent-callback = #'()
+ \override NoteHead #'print-function = #Note_head::brew_ez_stencil
+ \override NoteHead #'Y-extent-callback = #'()
+ \override NoteHead #'X-extent-callback = #'()
}
aikenHeads = \set shapeNoteStyles = ##(do re mi fa #f la ti)
tiny =
- \set fontSize = #-2
+\set fontSize = #-2
small =
- \set fontSize = #-1
+\set fontSize = #-1
normalsize = {
- \set fontSize = #0
+ \set fontSize = #0
}
-% End the incipit and print a ``normal line start''.
+%% End the incipit and print a ``normal line start''.
endincipit = \context Staff {
- \partial 16 s16 % Hack to handle e.g. \bar ".|" \endincipit
- \once \override Staff.Clef #'full-size-change = ##t
- \once \override Staff.Clef #'non-default = ##t
- \bar ""
+ \partial 16 s16 % Hack to handle e.g. \bar ".|" \endincipit
+ \once \override Staff.Clef #'full-size-change = ##t
+ \once \override Staff.Clef #'non-default = ##t
+ \bar ""
}
autoBeamOff = \set autoBeaming = ##f
determines where fingerings are put relative to the chord being
fingered.")
+ (firstClef ,boolean? "If true, create a new clef when starting a
+staff.")
(forceClef ,boolean? "Show clef symbol, even if it has not
changed. Only active for the first clef after the property is set, not
for the full staff.")
(internal-class-name . "Event")
(types . (general-music extender-event event))
))
+
+
+ (EventChord
+ . (
+ (description . "Internally used to group a set of events.")
+ (internal-class-name . "Music")
+ (iterator-ctor . ,Event_chord_iterator::constructor)
+ (length-callback . ,Music_sequence::maximum_length_callback)
+ (to-relative-callback . ,Music_sequence::event_chord_relative_callback)
+ (types . (general-music event-chord simultaneous-music))
+ ))
+
(FingerEvent
. (
(description . "Specify what finger to use for this note.")
(types . (general-music event rhythmic-event multi-measure-rest-event))
))
+ (MultiMeasureRestMusicGroup
+ . (
+ (description . "Like sequential-music, but specifically intended
+to group start-mmrest, skip, stop-mmrest sequence.
+
+Syntax @code{R2.*5} for 5 measures in 3/4 time.")
+ (internal-class-name . "Music")
+ (length-callback . ,Music_sequence::cumulative_length_callback)
+ (start-callback . ,Music_sequence::first_start_callback)
+ (iterator-ctor . ,Sequential_music_iterator::constructor)
+ (types . (general-music sequential-music))
+ ))
+
(MultiMeasureTextEvent
. (
(description . "Texts on mm rests.
(types . (general-music event note-event rhythmic-event melodic-event))
))
+ (OutputPropertySetMusic
+ . (
+ (description . "Set grob properties in objects
+individually.
+
+Syntax @code{\\outputproperty @var{predicate} @var{prop}
+= @var{val}}.")
+
+ (internal-class-name . "Music")
+ (iterator-ctor . ,Output_property_music_iterator::constructor)
+ (types . (general-music layout-instruction))
+ ))
+
(OverrideProperty
. (
(description . "Extend the definition of a graphical object.
(iterator-ctor . ,Sequential_music_iterator::constructor)
(types . (general-music sequential-music))
))
-
- (MultiMeasureRestMusicGroup
- . (
- (description . "Like sequential-music, but specifically intended
-to group start-mmrest, skip, stop-mmrest sequence.
-
-Syntax @code{R2.*5} for 5 measures in 3/4 time.")
- (internal-class-name . "Music")
- (length-callback . ,Music_sequence::cumulative_length_callback)
- (start-callback . ,Music_sequence::first_start_callback)
- (iterator-ctor . ,Sequential_music_iterator::constructor)
- (types . (general-music sequential-music))
- ))
(SoloOneEvent
. (
(internal-class-name . "Event")
(types . (general-music span-event slur-event))
))
-
+
+ (StaffSpanEvent
+ . ((description . "Start or stop a staff symbol.")
+ (internal-class-name . "Event")
+ (types . (general-music event span-event staff-span-event))
+ ))
+
(StartPlayingEvent
. (
(description . "Used internally to signal beginning of notes.")
(types . (general-music event start-playing-event))
))
- (OutputPropertySetMusic
- . (
- (description . "Set grob properties in objects
-individually.
-
-Syntax @code{\\outputproperty @var{predicate} @var{prop}
-= @var{val}}.")
-
- (internal-class-name . "Music")
- (iterator-ctor . ,Output_property_music_iterator::constructor)
- (types . (general-music layout-instruction))
- ))
-
(TextSpanEvent
. (
(description . "Start a text spanner like 8va.....|")
(internal-class-name . "Music_wrapper")
(types . (music-wrapper-music general-music relative-octave-music))
))
-
- (EventChord
- . (
- (description . "Internally used to group a set of events.")
- (internal-class-name . "Music")
- (iterator-ctor . ,Event_chord_iterator::constructor)
- (length-callback . ,Music_sequence::maximum_length_callback)
- (to-relative-callback . ,Music_sequence::event_chord_relative_callback)
- (types . (general-music event-chord simultaneous-music))
- ))
-
(ScriptEvent
. (
(description . "Add an articulation mark to a note. ")