* lily/horizontal-bracket-engraver.cc: new file.
* input/regression/note-group-bracket.ly: new file. Support
horizontal note brackets for music analysis.
* lily/stem.cc (flag): new flag-style: no-flag.
* input/test/stem-cross-staff.ly: new file
2002-10-05 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ * lily/horizontal-bracket.cc: new file.
+
+ * lily/horizontal-bracket-engraver.cc: new file.
+
+ * input/regression/note-group-bracket.ly: new file. Support
+ horizontal note brackets for music analysis.
+
+ * lily/stem.cc (flag): new flag-style: no-flag.
+
+ * input/test/stem-cross-staff.ly: new file
+
* lily/include/midi-stream.hh: use stdio.h iso. iostream.h
* lily/parser.yy: remove \dynamicscript.
f'4 g'4 a'4 \sostenutoUp
@end lilypond
+@node Cross staff stems
+@subsection Cross staff stems
+@cindex Cross staff stems
+@cindex Stems, cross staff
+Unfortunately, there is no support for putting chords across staves.
+You can get this result by increasing the length of the stem in the
+lower stave so it reaches the stem in the upper stave, or vice versa.
+
+@lilypond
+
+sUp = \translator Staff = "up"
+sDown = \translator Staff = "down"
+
+stemExtend = \property Voice.Stem \set #'length = #22
+stemNormal = \property Voice.Slur \revert #'length
+
+
+ < { \stemDown \sDown s4. a, } \\
+ { \stemDown \sUp f4. \stemExtend f }> |
+
+ \stemNormal
+
+ [...]
+@end lilypond
-@c . {Arpeggio}
@node Arpeggio
@subsection Arpeggio
@cindex Arpeggio
Both loudness controls are combined to produce the final MIDI volume.
-
-
@menu
* MIDI block::
* MIDI instrument names::
PACKAGE_NAME=LilyPond
MAJOR_VERSION=1
MINOR_VERSION=7
-PATCH_LEVEL=1
+PATCH_LEVEL=2
MY_PATCH_LEVEL=
# Use the above to send patches: MY_PATCH_LEVEL is always empty for a
--- /dev/null
+
+\header {
+
+ texidoc = "Note grouping events are used to indicate where
+brackets for analysis start and end."
+
+}
+
+
+
+\score {
+ \notes
+ {
+
+ c4-\groupOpen-\groupOpen-\groupOpen
+ c4-\groupClose
+ c4-\groupOpen
+ c4-\groupClose-\groupClose
+ c4-\groupOpen
+ c4-\groupClose-\groupClose
+ }
+
+ \paper {
+ \translator {
+ \StaffContext \consists "Horizontal_bracket_engraver"
+ }
+
+ linewidth = -1.0
+ }
+}
--- /dev/null
+\header {
+ texidoc = "Cross staff stems
+
+Unfortunately, there is no support for putting chords across staves.
+You can get this result by increasing the length of the stem in the
+lower stave so it reaches the stem in the upper stave, or vice versa.
+
+@cindex Cross staff stems
+@cindex Stems, cross staff
+
+"
+}
+
+stemExtend = \once \property Voice.Stem \override #'length = #22
+
+%% following reqs 1.7.1 or better.
+noFlag = \once \property Voice.Stem \override #'flag-style = #'no-flag
+
+
+\score { \notes
+ \context PianoStaff
+ < \context Staff = up {
+ \stemDown
+ \stemExtend
+ f'4
+ \stemExtend
+ \noFlag
+ f'8 }
+ \context Staff = down {
+ \clef bass
+ a4 a8 }
+ >
+
+ \paper { linewidth = -1.0 }
+}
String style;
if (gh_symbol_p (scm_style))
{
- style = ly_scm2string (scm_symbol_to_string (scm_style));
+ style = ly_symbol2string (scm_style);
}
else
{
if (gh_symbol_p (scm_note_head_style))
{
String note_head_style =
- ly_scm2string (scm_symbol_to_string (scm_note_head_style));
+ ly_symbol2string (scm_note_head_style);
}
else
{
if (gh_symbol_p (scm_accidentals_style))
{
accidentals_style =
- ly_scm2string (scm_symbol_to_string (scm_accidentals_style));
+ ly_symbol2string (scm_accidentals_style);
}
else
{
String style;
if (gh_symbol_p (scm_style))
{
- style = ly_scm2string (scm_symbol_to_string (scm_style));
+ style = ly_symbol2string (scm_style);
}
else
{
if (iface == SCM_BOOL_F)
{
String msg = to_string ("Unknown interface `%s'",
- ly_scm2string (scm_symbol_to_string (gh_car(ifs))).to_str0 ());
+ ly_symbol2string (gh_car(ifs)).to_str0 ());
programming_error (msg);
continue;
}
--- /dev/null
+/*
+ horizontal-bracket-engraver.cc -- implement
+ Horizontal_bracket_engraver
+
+source file of the GNU LilyPond music typesetter
+
+(c) 2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ */
+
+#include "engraver.hh"
+#include "side-position-interface.hh"
+#include "note-column.hh"
+#include "group-interface.hh"
+
+class Horizontal_bracket_engraver : public Engraver
+{
+public:
+ TRANSLATOR_DECLARATIONS(Horizontal_bracket_engraver);
+ Link_array<Spanner> bracket_stack_;
+ Link_array<Music> events_;
+ int pop_count_;
+ int push_count_;
+
+ virtual bool try_music(Music*);
+ virtual void start_translation_timestep ();
+ virtual void stop_translation_timestep ();
+ virtual void process_music ();
+ virtual void acknowledge_grob (Grob_info);
+};
+
+ENTER_DESCRIPTION(Horizontal_bracket_engraver,
+ "Create horizontal brackets over notes for musical analysis purposes.",
+ "HorizontalBracket",
+ "note-grouping-event",
+ "note-column-interface",
+ "",
+ "");
+
+Horizontal_bracket_engraver::Horizontal_bracket_engraver()
+{
+ pop_count_ = 0;
+ push_count_ = 0;
+}
+
+void
+Horizontal_bracket_engraver::start_translation_timestep()
+{
+ pop_count_ = 0;
+ push_count_ = 0;
+}
+
+bool
+Horizontal_bracket_engraver::try_music (Music *m)
+{
+ if (m->is_mus_type ("note-grouping-event"))
+ {
+ Direction d = to_dir (m->get_mus_property ("span-direction"));
+
+ if (d == STOP)
+ {
+ pop_count_ ++;
+ if (pop_count_ > bracket_stack_.size())
+ m->origin()->warning (_("Don't have that many brackets."));
+ }
+ else
+ {
+ push_count_++;
+ events_.push (m);
+ }
+
+ if (pop_count_ && push_count_)
+ m->origin()->warning (_("Conflicting note group events."));
+
+ return true;
+ }
+ return false;
+}
+
+void
+Horizontal_bracket_engraver::acknowledge_grob (Grob_info gi)
+{
+ if (Note_column::has_interface (gi.grob_))
+ {
+ for (int i = 0; i < bracket_stack_.size(); i++)
+ {
+ Side_position_interface::add_support (bracket_stack_[i], gi.grob_);
+ Pointer_group_interface::add_grob (bracket_stack_[i],
+ ly_symbol2scm ("columns"), gi.grob_);
+ add_bound_item (bracket_stack_[i],
+ gi.grob_);
+ }
+ }
+}
+
+void
+Horizontal_bracket_engraver::process_music ()
+{
+ for (int k = 0; k < push_count_; k++)
+ {
+ Spanner * sp = new Spanner (get_property ("HorizontalBracket"));
+
+ announce_grob (sp, events_[k]->self_scm());
+ for (int i = 0; i < bracket_stack_.size(); i++)
+ {
+ /*
+ sp is the smallest, it should be added to the bigger brackets.
+ */
+ Side_position_interface::add_support (bracket_stack_[i], sp);
+ }
+ bracket_stack_.push (sp);
+ }
+}
+
+
+void
+Horizontal_bracket_engraver::stop_translation_timestep ()
+{
+ for (int i = pop_count_; i--;)
+ {
+ if (bracket_stack_.size())
+ typeset_grob (bracket_stack_.pop());
+ }
+}
+
+
--- /dev/null
+/*
+horizontal-bracket.cc -- implement
+
+source file of the GNU LilyPond music typesetter
+
+(c) 2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ */
+
+#include "side-position-interface.hh"
+#include "lookup.hh"
+#include "group-interface.hh"
+#include "directional-element-interface.hh"
+#include "paper-def.hh"
+
+struct Horizontal_bracket
+{
+ DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM));
+ static bool has_interface (Grob*);
+};
+
+
+/*
+ TODO:
+
+ This doesn't look very elegant: should support winged edges.
+
+ Support texts on the brackets?
+
+*/
+
+MAKE_SCHEME_CALLBACK(Horizontal_bracket, brew_molecule, 1);
+
+SCM
+Horizontal_bracket::brew_molecule (SCM smob)
+{
+ Grob * me = unsmob_grob (smob);
+ Spanner *sp = dynamic_cast<Spanner*> (me);
+ Link_array<Grob> gs = Pointer_group_interface__extract_grobs (me,(Grob*)0, "columns");
+
+ if (!gs.size())
+ {
+ me->suicide();
+ return SCM_EOL;
+ }
+ Grob * cx = common_refpoint_of_array (gs, me, X_AXIS);
+ cx = cx->common_refpoint (sp->get_bound (LEFT), X_AXIS);
+ cx = cx->common_refpoint (sp->get_bound (RIGHT),X_AXIS);
+
+ Interval ext = gs.top()->extent (cx, X_AXIS);
+ ext.unite (gs[0]->extent (cx, X_AXIS));
+
+ Direction d = Directional_element_interface::get (me);
+ Real t = me->get_paper()->get_var ("linethickness");
+
+ SCM lthick = me->get_grob_property ("thickness");
+ if (gh_number_p (lthick))
+ t *= gh_scm2double (lthick);
+
+ Molecule b = Lookup::bracket (X_AXIS, ext, t, - d* 1.0);
+
+ b.translate_axis ( - sp->get_bound (LEFT)->relative_coordinate (cx, X_AXIS), X_AXIS);
+
+ return b.smobbed_copy();
+}
+
+ADD_INTERFACE (Horizontal_bracket,"horizontal-bracket-interface",
+ "A horizontal bracket encompassing notes.",
+ "thickness columns direction");
+
String style;
if (gh_symbol_p (scm_style))
{
- style = ly_scm2string (scm_symbol_to_string (scm_style));
+ style = ly_symbol2string (scm_style);
}
else
{
return scm_list_n (ly_symbol2scm ("quote"), s, SCM_UNDEFINED);
}
-
-
String
ly_symbol2string (SCM s)
{
return String ((Byte*)SCM_STRING_CHARS (s), (int) SCM_STRING_LENGTH (s));
}
-
String
gulp_file_to_string (String fn)
{
else if (verbose_global_b)
progress_indication ("[" + s);
-
int n;
char * str = gulp_file (s, &n);
String result (str);
SCM scm_style = me->get_grob_property ("style");
String style;
if ((gh_symbol_p (scm_style)) && (scm_style != SCM_EOL))
- style = ly_scm2string (scm_symbol_to_string (scm_style));
+ style = ly_symbol2string (scm_style);
else {
me->warning (_ ("porrectus style undefined; using mensural"));
style = "mensural";
--hwn.
*/
-
SCM width_scm = me->get_grob_property ("width");
if (gh_number_p (width_scm))
{
/* TODO: maybe property stroke-style should take different values,
e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
'() or "grace"). */
- String flag_style, staffline_offs;
+ String flag_style;
+
SCM flag_style_scm = me->get_grob_property ("flag-style");
if (gh_symbol_p (flag_style_scm))
{
- flag_style = ly_scm2string (scm_symbol_to_string (flag_style_scm));
+ flag_style = ly_symbol2string (flag_style_scm);
}
- else
+
+ if (flag_style == "no-flag")
{
- flag_style = "";
+ return Molecule ();
}
+
bool adjust = to_boolean (me->get_grob_property ("adjust-if-on-staffline"));
+ String staffline_offs;
if (String::compare (flag_style, "mensural") == 0)
/* Mensural notation: For notes on staff lines, use different
flags than for notes between staff lines. The idea is that
{
staffline_offs = "";
}
+
char dir = (get_direction (me) == UP) ? 'u' : 'd';
String font_char =
flag_style + to_string (dir) + staffline_offs + to_string (duration_log (me));
/*
TODO: make the stem start a direction ?
*/
-
-
-
if (to_boolean (me->get_grob_property ("avoid-note-head")))
{
Grob * lh = last_head (me);
\version "1.5.68"
-cr = \spanrequest \start "crescendo"
-decr = \spanrequest \start "decrescendo"
-rc = \spanrequest \stop "crescendo"
-rced = \spanrequest \stop "decrescendo"
+
+#(define (make-span-request type spandir)
+ (let* ((m (make-music-by-name type)))
+ (ly-set-mus-property! m 'span-direction spandir)
+ m
+ ))
+
+groupOpen = #(make-span-request 'NoteGroupingEvent START)
+groupClose = #(make-span-request 'NoteGroupingEvent STOP)
+
+
+cr = #(make-span-request 'CrescendoEvent START)
+rc = #(make-span-request 'CrescendoEvent STOP)
+decr = #(make-span-request 'DecrescendoEvent START)
+rced = #(make-span-request 'DecrescendoEvent STOP)
cresc = \notes {
\commandspanrequest \start "crescendo"
(meta . ((interfaces . (hairpin-interface self-alignment-interface dynamic-interface spanner-interface))))
))
+ (HorizontalBracket
+ . (
+ (thickness . 1.0)
+ (molecule-callback . ,Horizontal_bracket::brew_molecule)
+ (Y-offset-callbacks . (,Side_position_interface::aligned_side))
+ (padding . 0.2)
+ (direction . -1)
+ (meta . ((interfaces . (horizontal-bracket-interface spanner-interface))))
+ ))
(InstrumentName
. (
(breakable . #t)
slur dir) -> attachment to determine the attachment (see above). If
procedure returns #t, attachment is used. Otherwise, the next
procedure is tried.")
-(grob-property-description 'flag-style symbol? "a string determining what style of glyph is typeset.")
+(grob-property-description
+ 'flag-style symbol?
+ "a string determining what style of glyph is typeset on a Stem.
+ Additionally, @code{no-flag} switches off the flag.")
(grob-property-description 'stroke-style string? "set to \"grace\" to turn stroke through flag on.")
(grob-property-description 'flag-width-function procedure? "Procedure that computes the width of a half-beam (a non-connecting beam.).")
(grob-property-description 'flexa-width number? "width of a flexa shape in a ligature grob.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(define X 0)
-(define Y 1)
-(define LEFT -1)
-(define RIGHT 1)
-(define UP 1)
-(define DOWN -1)
-(define CENTER 0)
+(define-public X 0)
+(define-public Y 1)
+(define-public START -1)
+(define-public STOP 1)
+(define-public LEFT -1)
+(define-public RIGHT 1)
+(define-public UP 1)
+(define-public DOWN -1)
+(define-public CENTER 0)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; lily specific variables.
(iterator-ctor . ,Grace_iterator::constructor)
(types . (grace-music music-wrapper-music general-music))
))
+ (NoteGroupingEvent
+ . (
+ (description . "Start or stop grouping brackets.")
+ (internal-class-name . "Event")
+ (types . (general-music event note-grouping-event))
+ ))
(HyphenEvent
. (
(description . "")