@mudelafile{tie.ly}
+When tieing chords, the outer slurs point outwards, the inner slurs
+point away from the center of the staff. Override with
+@code{tieVerticalDirection}.
+
+@mudelafile{tie-chord.ly}
+
When tieing notes with accidentals across a bar boundary, the accidental
must not be drawn on the note in the new bar. Instead, the next note of
the same pitch in this bar should always show the accidental (even if
@top
-@unnumbered LilyPond -- The GNU Project Music Typesetter
+@unnumberedsec LilyPond -- The GNU Project Music Typesetter
@html
@c something breaks on 3.12 f
+@unnumberedsec What is LilyPond?
+
LilyPond is a music typesetter. It produces beautiful sheet music using
a high level description file as input. It excels at typesetting
classical music, but you can also print pop-songs. With LilyPond we
hope to make music publication software available to anyone on the
internet.
-The program also has limited MIDI functionality: you can write MIDI
-files with lilypond, and we have a simple MIDI to lilypond conversion
-tool, @file{midi2ly}.
-
-LilyPond is free software. It is licensed under GNU General Public
-License, and it is part of the @uref{http://www.gnu.org/,GNU Project}.
+@unnumberedsec Why should I use it?
+The input to LilyPond is plain text. So you can use your favorite text
+editor to edit it, you can put it in mail or embed it in an article like
+this:
@quotation
-@mudela[fragment]
+@mudela[fragment,verbatim]
\relative c'' { \key es; r8 [c16 b] [c8 g] [as c16 b] [c8 d] | g,4 }
@end mudela
@end quotation
-
+The output looks very good: the font and the layout algorithms were
+inspired by engraved music, so you can expect that same clear and
+elegant look from your LilyPond output. And if you don't like the
+looks, you can tweak almost everything.
+
+The program also has limited MIDI functionality: you can write MIDI
+files with lilypond, and we have a simple MIDI to lilypond conversion
+tool, @file{midi2ly}.
+
+LilyPond is free software. It is licensed under GNU General Public
+License, so you can use, modify and redistribute the program almost no
+restrictions. LilyPond is part of the @uref{http://www.gnu.org/,GNU
+Project}.
The version numbers are in Linux-kernel style: even unnumbered versions
are `stable'. The webpages for the stable version reside at GNU, here:
--- /dev/null
+t = \notes \relative c' { <c e g> ~ <c e g> }
+
+ \score {
+\notes \context Voice {
+ \t
+ \transpose g' \t
+ \property Voice.tieVerticalDirection = #-1
+ \t
+
+ }
+}
Bar::do_pre_processing ()
{
SCM g = get_elt_property ("glyph");
- SCM breakdir = gh_int2scm (break_status_dir ());
-
+ Direction bsd = break_status_dir ();
if (gh_string_p (g))
{
- g = scm_eval (gh_list (ly_symbol2scm ("break-barline"),
- g,
- breakdir,
- SCM_UNDEFINED));
+ if (bsd)
+ {
+ SCM breakdir = gh_int2scm (bsd);
+ g = scm_eval (gh_list (ly_symbol2scm ("break-barline"),
+ g,
+ breakdir,
+ SCM_UNDEFINED));
+ }
}
else
{
g = SCM_UNDEFINED;
}
-#if 0
- if (remove_elt_property ("at-line-start") == SCM_BOOL_T // UGR.
- && (break_status_dir () == RIGHT) && (type_str_ == ""))
- {
- type_str_ = "|";
- }
-#endif
-
if (!gh_string_p (g))
{
set_elt_property ("transparent", SCM_BOOL_T);
#include "paper-score.hh"
#include "dimension-cache.hh"
#include "side-position-interface.hh"
+#include "warn.hh"
void
Clef_item::do_pre_processing()
s = "clefs-" + s;
set_elt_property ("glyph", ly_str02scm (s.ch_C()));
}
+ else
+ {
+ set_elt_property ("transparent", SCM_BOOL_T);
+ }
if (style == "transparent") // UGH. JUNKME
{
pscore_l_->typeset_element (g);
+ spi.add_support (this);
g->set_elt_property ("text", ly_str02scm ( "8"));
g->set_elt_property ("style", gh_str02scm ("italic"));
g->set_parent (this, Y_AXIS);
- g->set_parent (this, X_AXIS);
+ g->set_parent (this, X_AXIS);
+
+ g->set_elt_property ("self-alignment-X", gh_int2scm (0));
+ g->dim_cache_[X_AXIS]->off_callbacks_.push (Side_position_interface::aligned_on_self);
+ g->dim_cache_[X_AXIS]->off_callbacks_.push (Side_position_interface::centered_on_parent);
+
g->set_elt_property ("direction", octave_dir);
add_dependency (g); // just to be sure.
}
}
+Group_interface
+group (Score_element*s,String n)
+{
+ Group_interface gi (s,n);
+ return gi;
+}
+
Group_interface
group (Score_element*s)
{
};
Group_interface group (Score_element*);
+Group_interface group (Score_element*, String);
/*
template<class T>
--- /dev/null
+/*
+ request-iterator.hh -- declare Request_iterator
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ */
+
+#ifndef REQUEST_ITERATOR_HH
+#define REQUEST_ITERATOR_HH
+
+#include "music-iterator.hh"
+
+class Request_iterator : public Music_iterator
+{
+public:
+ Request_iterator ();
+protected:
+ virtual void do_process_and_next (Moment );
+};
+
+#endif /* REQUEST_ITERATOR_HH */
+
public:
Side_position_interface (Score_element const*);
static Real side_position (Dimension_cache const *);
- static Real self_alignment (Dimension_cache const *);
+ static Real aligned_on_self (Dimension_cache const *);
static Real aligned_side (Dimension_cache const *);
static Real quantised_position (Dimension_cache const*);
+ static Real centered_on_parent (Dimension_cache const*);
void set_axis (Axis);
void set_quantised (Axis);
Axis get_axis () const;
{
public:
VIRTUAL_COPY_CONS (Score_element);
- void add_tie (Score_element*);
+ void add_tie (Tie*);
Tie_column ();
protected:
virtual void do_post_processing ();
#ifndef CTIE_ENGRAVER_HH
#define CTIE_ENGRAVER_HH
-
-#include "pqueue.hh"
-#include "engraver.hh"
-
-struct CHead_melodic_tuple {
- Melodic_req *req_l_ ;
- Note_head *head_l_;
- Moment end_;
- CHead_melodic_tuple ();
- CHead_melodic_tuple (Note_head*, Melodic_req*, Moment);
- static int pitch_compare (CHead_melodic_tuple const &, CHead_melodic_tuple const &);
- static int time_compare (CHead_melodic_tuple const &, CHead_melodic_tuple const &);
-};
-
-inline int compare (CHead_melodic_tuple const &a, CHead_melodic_tuple const &b)
-{
- return CHead_melodic_tuple::time_compare (a,b);
-}
-
-
-/**
- Manufacture ties. Acknowledge noteheads, and put them into a
- priority queue. If we have a Tie_req, connect the notes that finish
- just at this time, and note that start at this time.
-
- TODO: should share code with Beam_engraver, Extender_engraver?
- */
-class Tie_engraver : public Engraver
-{
- PQueue<CHead_melodic_tuple> past_notes_pq_;
- Tie_req *req_l_;
- Array<CHead_melodic_tuple> now_heads_;
- Array<CHead_melodic_tuple> stopped_heads_;
- Link_array<Tie> tie_p_arr_;
-
- void set_melisma (bool);
-protected:
- virtual void do_post_move_processing ();
- virtual void do_pre_move_processing ();
- virtual void acknowledge_element (Score_element_info);
- virtual bool do_try_music (Music*);
- virtual void do_process_requests ();
- virtual void process_acknowledged ();
-
-public:
- VIRTUAL_COPY_CONS(Translator);
- Tie_engraver();
-};
-
#endif /* CTIE_ENGRAVER_HH */
VIRTUAL_COPY_CONS(Score_element);
Note_head* head (Direction) const;
+ Real position_f () const;
+
+ virtual Direction get_default_dir() const;
protected:
virtual Molecule* do_brew_molecule_p () const;
virtual void do_add_processing ();
virtual void do_post_processing ();
- virtual Direction get_default_dir() const;
virtual Array<Rod> get_rods () const;
#include "lyric-combine-music-iterator.hh"
#include "auto-change-music.hh"
#include "auto-change-iterator.hh"
+#include "request.hh"
+#include "request-iterator.hh"
void
Music_iterator::do_print() const
else
p = new Unfolded_repeat_iterator;
}
+ else if (Request const * r = dynamic_cast<Request const* > (m))
+ {
+ p = new Request_iterator ;
+ }
else
assert (0);
-
p->music_l_ = m;
return p;
}
Request_chord_iterator::Request_chord_iterator ()
{
last_b_ = false;
- // cursor_ = elt_l ()->music_p_list_p_->head_;
cursor_ = 0;
}
--- /dev/null
+/*
+ request-iterator.cc -- implement
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ */
+#include "request-iterator.hh"
+#include "music.hh"
+
+Request_iterator::Request_iterator()
+{
+}
+
+
+void
+Request_iterator::do_process_and_next (Moment m)
+{
+ if (first_b_)
+ {
+ bool g= try_music (music_l_);
+ if (!g)
+ music_l_->warning (_f ("Junking request: `%s'", classname(music_l_)));
+
+ first_b_ = false;
+ }
+ Music_iterator::do_process_and_next (m);
+}
if (get_elt_property ("self-alignment-X") != SCM_UNDEFINED
&& !dim_cache_[X_AXIS]->off_callback_l_)
{
- dim_cache_[X_AXIS]->off_callbacks_.push (Side_position_interface::self_alignment);
+ dim_cache_[X_AXIS]->off_callbacks_.push (Side_position_interface::aligned_on_self);
}
if (get_elt_property ("self-alignment-Y") != SCM_UNDEFINED
&& !dim_cache_[X_AXIS]->off_callback_l_)
{
- dim_cache_[Y_AXIS]->set_offset_callback (Side_position_interface::self_alignment);
+ dim_cache_[Y_AXIS]->set_offset_callback (Side_position_interface::aligned_on_self);
}
#endif
return DOWN;
}
-/**
- Callback that does the aligning.
+/*
+ Callback that does the aligning. Puts the element next to the support
*/
+
Real
Side_position_interface::side_position (Dimension_cache const * c)
{
- Score_element * me = dynamic_cast<Score_element*> (c->element_l ());
+ Score_element * me = (c->element_l ());
Interval dim;
Axis axis = c->axis ();
return total_off;
}
+/*
+ callback that centers the element on itself
+ */
Real
-Side_position_interface::self_alignment (Dimension_cache const *c)
+Side_position_interface::aligned_on_self (Dimension_cache const *c)
{
String s ("self-alignment-");
Axis ax = c->axis ();
s += (ax == X_AXIS) ? "X" : "Y";
- Score_element *elm = dynamic_cast<Score_element*> (c->element_l ());
+ Score_element *elm = c->element_l ();
SCM align (elm->get_elt_property (s));
if (isdir_b (align))
{
return 0.0;
}
-
Real
directed_round (Real f, Direction d)
{
return ceil (f);
}
+/*
+ Callback that quantises in staff-spaces, rounding in the direction
+ of the elements "direction" elt property. */
Real
Side_position_interface::quantised_position (Dimension_cache const *c)
{
- Score_element * me = dynamic_cast<Score_element*> (c->element_l ());
+ Score_element * me = (c->element_l ());
Side_position_interface s(me);
Direction d = s.get_direction ();
Staff_symbol_referencer_interface si (me);
return 0.0;
}
+/*
+ Position next to support, taking into account my own dimensions and padding.
+ */
Real
Side_position_interface::aligned_side (Dimension_cache const *c)
{
- Score_element * me = dynamic_cast<Score_element*> (c->element_l ());
+ Score_element * me = (c->element_l ());
Side_position_interface s(me);
Direction d = s.get_direction ();
Axis ax = c->axis ();
return o;
}
+/*
+ Position centered on parent.
+ */
+Real
+Side_position_interface::centered_on_parent (Dimension_cache const *c)
+{
+
+ Score_element *me = c->element_l ();
+ Axis a = c->axis ();
+ Score_element *him = me->parent_l (a);
+
+ return him->extent (a).center ();
+}
+
+
void
Side_position_interface::add_staff_support ()
{
#include "tie-column.hh"
#include "group-interface.hh"
+#include "tie.hh"
+#include "directional-element-interface.hh"
+#include "note-head.hh"
Tie_column::Tie_column ()
{
set_elt_property ("ties", SCM_EOL);
+ set_empty (X_AXIS);
+ set_empty (Y_AXIS);
+ set_elt_property ("transparent", SCM_BOOL_T);
}
void
-Tie_column::add_tie (Score_element *s)
+Tie_column::add_tie (Tie *s)
{
- group (s).add_element (s);
+ Group_interface g (this, "ties");
+ if (!g.count ())
+ {
+ set_bounds (LEFT, s->head (LEFT));
+ set_bounds (RIGHT, s->head (RIGHT));
+ }
+
+ group (this, "ties").add_element (s);
s->add_dependency (this);
}
+
+int
+tie_compare (Tie* const & s1,
+ Tie* const & s2)
+{
+ return sign (s1->position_f () - s2->position_f());
+}
+
+/*
+ See [Ross p. 138].
+
+
+ In normal chord cases, the outer ties point outwards, and the
+ direction of the rest is determined by their staff position.
+
+ Ross forgets about the tie that is *on* the middle staff line. We
+ assume it goes UP. (TODO: make this settable) */
void
Tie_column::set_directions ()
{
- Link_array<Score_element> s =
- Group_interface__extract_elements (this, (Score_element*)0, "ties");
+ Link_array<Tie> s =
+ Group_interface__extract_elements (this, (Tie*)0, "ties");
+
+
+ Direction d = directional_element (this).get ();
+
+ if (d)
+ {
+ for (int i = s.size (); i--;)
+ directional_element (s[i]).set (d);
+ return;
+ }
+
+ if (s.size () == 1)
+ {
+ directional_element (s[0]).set (s[0]->get_default_dir ());
+ return;
+ }
+
+ s.sort (tie_compare);
+ directional_element (s[0]).set (DOWN);
+ s.del (0);
+ directional_element (s.pop ()).set (UP);
+
+ for (int i=s.size(); i--; )
+ {
+ Real p = s[i]->position_f ();
+ Direction d = (Direction) sign (p);
+ if (!d)
+ d = UP;
+
+ directional_element (s[i]).set (d);
+ }
+
}
void
#include "musical-request.hh"
#include "tie.hh"
#include "translator-group.hh"
+#include "tie-column.hh"
+#include "pqueue.hh"
+#include "engraver.hh"
+
+struct CHead_melodic_tuple {
+ Melodic_req *req_l_ ;
+ Note_head *head_l_;
+ Moment end_;
+ CHead_melodic_tuple ();
+ CHead_melodic_tuple (Note_head*, Melodic_req*, Moment);
+ static int pitch_compare (CHead_melodic_tuple const &, CHead_melodic_tuple const &);
+ static int time_compare (CHead_melodic_tuple const &, CHead_melodic_tuple const &);
+};
+
+inline int compare (CHead_melodic_tuple const &a, CHead_melodic_tuple const &b)
+{
+ return CHead_melodic_tuple::time_compare (a,b);
+}
+
+
+/**
+ Manufacture ties. Acknowledge noteheads, and put them into a
+ priority queue. If we have a Tie_req, connect the notes that finish
+ just at this time, and note that start at this time.
+
+ TODO: should share code with Beam_engraver, Extender_engraver?
+ */
+class Tie_engraver : public Engraver
+{
+ PQueue<CHead_melodic_tuple> past_notes_pq_;
+ Tie_req *req_l_;
+ Array<CHead_melodic_tuple> now_heads_;
+ Array<CHead_melodic_tuple> stopped_heads_;
+ Link_array<Tie> tie_p_arr_;
+
+ Tie_column * tie_column_p_;
+
+ void set_melisma (bool);
+
+protected:
+ virtual void do_post_move_processing ();
+ virtual void do_pre_move_processing ();
+ virtual void acknowledge_element (Score_element_info);
+ virtual bool do_try_music (Music*);
+ virtual void do_process_requests ();
+ virtual void process_acknowledged ();
+
+public:
+ VIRTUAL_COPY_CONS(Translator);
+ Tie_engraver();
+};
+
+
Tie_engraver::Tie_engraver()
{
req_l_ = 0;
+ tie_column_p_ = 0;
}
{
req_l_->warning (_ ("No ties were created!"));
}
-
+ else if (tie_p_arr_.size () > 1 && !tie_column_p_)
+ {
+ tie_column_p_ = new Tie_column;
+ for (int i = tie_p_arr_.size (); i--; )
+ tie_column_p_->add_tie (tie_p_arr_ [i]);
+ announce_element (Score_element_info (tie_column_p_, 0));
+ }
}
}
typeset_element (tie_p_arr_[i]);
}
tie_p_arr_.clear ();
+ if (tie_column_p_)
+ {
+ typeset_element (tie_column_p_);
+ tie_column_p_ =0;
+ }
}
void
return dynamic_cast<Note_head*> (unsmob_element (c));
}
+Real
+Tie::position_f () const
+{
+ return head (LEFT)
+ ? staff_symbol_referencer (head (LEFT)).position_f ()
+ : staff_symbol_referencer (head (RIGHT)).position_f () ;
+}
+
/*
ugh: direction of the Tie is more complicated. See [Ross] p136 and further
} while (flip(&d) != LEFT);
index_set_cell (get_elt_property ("heads"), LEFT, new_head_drul[LEFT]->self_scm_ );
- index_set_cell (get_elt_property ("heads"), RIGHT, new_head_drul[LEFT]->self_scm_ );
-
+ index_set_cell (get_elt_property ("heads"), RIGHT, new_head_drul[RIGHT]->self_scm_ );
}
void
*/
- Real ypos = head (LEFT)
- ? staff_symbol_referencer (head (LEFT)).position_f ()
- : staff_symbol_referencer (head (RIGHT)).position_f () ;
+ Real ypos = position_f ();
Real y_f = half_staff_space * ypos;
int ypos_i = int (ypos);
return c;
}
-
Array<Offset>
Tie::get_encompass_offset_arr () const
{
(list 'tieVerticalDirection dir? 'direction)
(list 'verticalDirection dir? 'direction)
)))
+(define generic-tie-column-properties
+ (cons "Tie_column" (list
+ (list 'tieVerticalDirection dir? 'direction)
+ (list 'verticalDirection dir? 'direction)
+ )))
(define generic-note-column-properties
generic-stem-properties
generic-breathing-sign-properties
generic-tie-properties
+ generic-tie-column-properties
generic-tuplet-spanner-properties
generic-rest-properties
generic-slur-properties