2 porrectus-engraver.cc -- implement Porrectus_engraver
4 Copyright (C) 2001 Juergen Reuter
6 written for the GNU LilyPond music typesetter
10 * FIXME: Currently, when creating a porrectus item, it takes the
11 * moment of the second note. Actually, it should take the moment of
14 * TODO: Introduce "\~" as alternative syntax for "\porrectus"?
16 * TODO: Hufnagel support.
18 * TODO: Fine-tuning of porrectus shape. In particular, the mensural
19 * non-solid shape could either be slightly bigger in height, or the
20 * extrem points could be slightly vertically shifted apart.
22 * TODO: For white mensural (i.e. #'style=#'mensural, #'solid=##f)
23 * porrectus grobs, it is possible to automatically determine all
24 * porrectus specific properties (add-stem, stem-direction) solely
25 * from the duration of the contributing notes and time-signature.
26 * Introduce a boolean grob property called auto-config, so that, if
27 * turned on, lily automatically sets the remaining properties
30 * TODO: The following issues are not (and should not be) handled by
31 * this engraver: (1) accidentals placement, (2) avoiding line
32 * breaking inbetween porrectus, (3) spacing. For example, currently
33 * only the accidental for the second note (cp. the above FIXME) is
34 * printed. These issues should be resolved by some sort of ligature
35 * context that encloses use of this engraver, using syntax like:
36 * \ligature { e \porrectus c }.
38 * TODO: Do not allow a series of adjacent porrectus requests, as in:
39 * e \porrectus d \porrectus c.
42 #include "staff-symbol-referencer.hh"
43 #include "porrectus.hh"
44 #include "musical-request.hh"
45 #include "command-request.hh"
46 #include "rhythmic-head.hh"
48 #include "engraver.hh"
51 // TODO: PHead_melodic_tuple is duplicated code from tie-engraver.cc.
52 // Maybe put this into public class?
53 struct PHead_melodic_tuple {
57 PHead_melodic_tuple ();
58 PHead_melodic_tuple (Grob*, Melodic_req*, Moment);
59 static int pitch_compare (PHead_melodic_tuple const &,
60 PHead_melodic_tuple const &);
61 static int time_compare (PHead_melodic_tuple const &,
62 PHead_melodic_tuple const &);
65 inline int compare (PHead_melodic_tuple const &a, PHead_melodic_tuple const &b)
67 return PHead_melodic_tuple::time_compare (a,b);
70 class Porrectus_engraver : public Engraver {
72 Porrectus_engraver ();
73 VIRTUAL_COPY_CONS (Translator);
76 virtual bool try_music (Music *req_l);
77 virtual void create_grobs ();
78 virtual void stop_translation_timestep ();
79 virtual void start_translation_timestep ();
80 virtual void acknowledge_grob (Grob_info);
83 PQueue<PHead_melodic_tuple> past_notes_pq_;
84 Porrectus_req *porrectus_req_l_;
85 Array<PHead_melodic_tuple> left_heads_;
86 Array<PHead_melodic_tuple> right_heads_;
87 Link_array<Grob> porrectus_p_arr_;
90 Porrectus_engraver::Porrectus_engraver ()
96 Porrectus_engraver::try_music (Music *m)
98 if (Porrectus_req *req_l_ = dynamic_cast <Porrectus_req *> (m))
100 porrectus_req_l_ = req_l_;
108 Porrectus_engraver::acknowledge_grob (Grob_info info_l_)
110 if (Rhythmic_head::has_interface (info_l_.elem_l_))
112 Note_req *note_req_l_ = dynamic_cast <Note_req *> (info_l_.req_l_);
115 left_heads_.push (PHead_melodic_tuple (info_l_.elem_l_, note_req_l_,
117 note_req_l_->length_mom ()));
122 Porrectus_engraver::create_grobs ()
124 if (porrectus_req_l_)
126 left_heads_.sort (PHead_melodic_tuple::pitch_compare);
127 right_heads_.sort (PHead_melodic_tuple::pitch_compare);
129 SCM head_list = SCM_EOL;
131 int i = left_heads_.size () - 1;
132 int j = right_heads_.size () - 1;
134 while ((i >= 0) && (j >= 0))
137 gh_cons (gh_cons (right_heads_[j].head_l_->self_scm (),
138 left_heads_[i].head_l_->self_scm ()),
141 past_notes_pq_. insert (left_heads_[i]);
143 right_heads_.del (j);
148 for (SCM s = head_list; gh_pair_p (s); s = gh_cdr (s))
150 SCM caar = gh_caar (s);
151 SCM cdar = gh_cdar (s);
153 Item *left_head = dynamic_cast<Item*> (unsmob_grob (caar));
154 Item *right_head = dynamic_cast<Item*> (unsmob_grob (cdar));
155 left_head->set_grob_property("transparent", gh_bool2scm(true));
156 right_head->set_grob_property("transparent", gh_bool2scm(true));
158 Grob *porrectus_p_ = new Item (get_property ("Porrectus"));
159 Porrectus::set_left_head(porrectus_p_, caar);
160 Porrectus::set_right_head(porrectus_p_, cdar);
161 porrectus_p_arr_.push (porrectus_p_);
162 announce_grob (porrectus_p_, 0);
168 Porrectus_engraver::stop_translation_timestep ()
170 for (int i = 0; i < left_heads_.size (); i++)
172 past_notes_pq_.insert (left_heads_[i]);
174 left_heads_.clear ();
176 for (int i = 0; i < porrectus_p_arr_.size (); i++)
178 typeset_grob (porrectus_p_arr_[i]);
180 porrectus_p_arr_.clear ();
184 Porrectus_engraver::start_translation_timestep ()
186 porrectus_req_l_ = 0;
187 Moment now = now_mom ();
188 while (past_notes_pq_.size () && past_notes_pq_.front ().end_ < now)
189 past_notes_pq_.delmin ();
191 right_heads_.clear ();
192 while (past_notes_pq_.size () &&
193 (past_notes_pq_.front ().end_ == now))
194 right_heads_.push (past_notes_pq_.get ());
197 ADD_THIS_TRANSLATOR (Porrectus_engraver);
199 // TODO: PHead_melodic_tuple is duplicated code from tie-engraver.cc.
200 // Maybe put this into public class?
202 PHead_melodic_tuple::PHead_melodic_tuple ()
209 PHead_melodic_tuple::PHead_melodic_tuple (Grob *h, Melodic_req*m, Moment mom)
217 signed compare, should use pitch<?
220 PHead_melodic_tuple::pitch_compare (PHead_melodic_tuple const&h1,
221 PHead_melodic_tuple const &h2)
223 SCM p1 = h1.req_l_->get_mus_property ("pitch");
224 SCM p2 = h2.req_l_->get_mus_property ("pitch");
226 int result = Pitch::compare (*unsmob_pitch (p1),
232 PHead_melodic_tuple::time_compare (PHead_melodic_tuple const&h1,
233 PHead_melodic_tuple const &h2)
235 int result = Moment::compare(h1.end_, h2.end_);