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 * FIXME: Turn off typesetting of stems, flags, dots, etc.
16 * TODO: Hufnagel support.
18 * TODO: Fine-tuning of vaticana-style porrectus shape; in particular,
19 * ensure solidity if solid is set to #t and thickness is very small.
21 * TODO: For white mensural (i.e. #'style=#'mensural, #'solid=##f)
22 * porrectus grobs, it is possible to automatically determine all
23 * porrectus specific properties (add-stem, stem-direction) solely
24 * from the duration of the contributing notes and time-signature.
25 * Introduce a boolean grob property called auto-config, so that, if
26 * turned on, lily automatically sets the properties add-stem and
27 * stem-direction properly.
29 * TODO: The following issues are currently not handled by this
30 * engraver: (1) accidentals placement, (2) avoiding line breaking
31 * inbetween porrectus, (3) spacing. (Han-Wen says: for (2), look at
32 * beam engraver.) For example, currently only the accidental for the
33 * second note (cp. the above FIXME) is printed. These issues should
34 * be resolved by some sort of ligature context that encloses use of
35 * this engraver, using syntax like: \ligature { e \~ c }.
37 * TODO: Do not allow a series of adjacent porrectus requests, as in:
40 * TODO: Junk duplicate (or rather triple) implementation of
41 * create_ledger_line in porrectus.cc, custos.cc and note-head.cc. */
43 #include "staff-symbol-referencer.hh"
44 #include "porrectus.hh"
45 #include "musical-request.hh"
46 #include "command-request.hh"
47 #include "rhythmic-head.hh"
49 #include "engraver.hh"
52 // TODO: PHead_melodic_tuple is duplicated code from tie-engraver.cc.
53 // Maybe put this into public class?
54 struct PHead_melodic_tuple {
58 PHead_melodic_tuple ();
59 PHead_melodic_tuple (Grob*, Melodic_req*, Moment);
60 static int pitch_compare (PHead_melodic_tuple const &,
61 PHead_melodic_tuple const &);
62 static int time_compare (PHead_melodic_tuple const &,
63 PHead_melodic_tuple const &);
66 inline int compare (PHead_melodic_tuple const &a, PHead_melodic_tuple const &b)
68 return PHead_melodic_tuple::time_compare (a,b);
71 class Porrectus_engraver : public Engraver {
73 Porrectus_engraver ();
74 VIRTUAL_COPY_CONS (Translator);
77 virtual bool try_music (Music *req_l);
78 virtual void create_grobs ();
79 virtual void stop_translation_timestep ();
80 virtual void start_translation_timestep ();
81 virtual void acknowledge_grob (Grob_info);
84 PQueue<PHead_melodic_tuple> past_notes_pq_;
85 Porrectus_req *porrectus_req_l_;
86 Array<PHead_melodic_tuple> left_heads_;
87 Array<PHead_melodic_tuple> right_heads_;
88 Link_array<Grob> porrectus_p_arr_;
91 Porrectus_engraver::Porrectus_engraver ()
97 Porrectus_engraver::try_music (Music *m)
99 if (Porrectus_req *req_l_ = dynamic_cast <Porrectus_req *> (m))
101 porrectus_req_l_ = req_l_;
109 Porrectus_engraver::acknowledge_grob (Grob_info info_l_)
111 if (Rhythmic_head::has_interface (info_l_.elem_l_))
113 Note_req *note_req_l_ = dynamic_cast <Note_req *> (info_l_.req_l_);
116 right_heads_.push (PHead_melodic_tuple (info_l_.elem_l_, note_req_l_,
118 note_req_l_->length_mom ()));
123 Porrectus_engraver::create_grobs ()
125 if (porrectus_req_l_)
127 left_heads_.sort (PHead_melodic_tuple::pitch_compare);
128 right_heads_.sort (PHead_melodic_tuple::pitch_compare);
129 int i = left_heads_.size () - 1;
130 int j = right_heads_.size () - 1;
132 while ((i >= 0) && (j >= 0))
134 Item *left_head = dynamic_cast<Item*> (left_heads_[i].head_l_);
135 Item *right_head = dynamic_cast<Item*> (right_heads_[j].head_l_);
136 left_head->set_grob_property("transparent", gh_bool2scm(true));
137 right_head->set_grob_property("transparent", gh_bool2scm(true));
139 Grob *porrectus_p_ = new Item (get_property ("Porrectus"));
140 Porrectus::set_left_head(porrectus_p_, left_head);
141 Porrectus::set_right_head(porrectus_p_, right_head);
142 porrectus_p_arr_.push (porrectus_p_);
143 announce_grob (porrectus_p_, porrectus_req_l_);
145 past_notes_pq_. insert (right_heads_[i]);
147 right_heads_.del (j);
155 Porrectus_engraver::stop_translation_timestep ()
157 for (int i = 0; i < right_heads_.size (); i++)
159 past_notes_pq_.insert (right_heads_[i]);
161 right_heads_.clear ();
163 for (int i = 0; i < porrectus_p_arr_.size (); i++)
165 typeset_grob (porrectus_p_arr_[i]);
167 porrectus_p_arr_.clear ();
171 Porrectus_engraver::start_translation_timestep ()
173 porrectus_req_l_ = 0;
174 Moment now = now_mom ();
175 while (past_notes_pq_.size () && past_notes_pq_.front ().end_ < now)
176 past_notes_pq_.delmin ();
178 left_heads_.clear ();
179 while (past_notes_pq_.size () &&
180 (past_notes_pq_.front ().end_ == now))
181 left_heads_.push (past_notes_pq_.get ());
184 ADD_THIS_TRANSLATOR (Porrectus_engraver);
186 // TODO: PHead_melodic_tuple is duplicated code from tie-engraver.cc.
187 // Maybe put this into public class?
189 PHead_melodic_tuple::PHead_melodic_tuple ()
196 PHead_melodic_tuple::PHead_melodic_tuple (Grob *h, Melodic_req*m, Moment mom)
204 signed compare, should use pitch<?
207 PHead_melodic_tuple::pitch_compare (PHead_melodic_tuple const&h1,
208 PHead_melodic_tuple const &h2)
210 SCM p1 = h1.req_l_->get_mus_property ("pitch");
211 SCM p2 = h2.req_l_->get_mus_property ("pitch");
213 int result = Pitch::compare (*unsmob_pitch (p1),
219 PHead_melodic_tuple::time_compare (PHead_melodic_tuple const&h1,
220 PHead_melodic_tuple const &h2)
222 int result = Moment::compare(h1.end_, h2.end_);