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: The following issues are currently not handled by this
19 * engraver: (1) accidentals placement, (2) spacing. For example,
20 * currently only the accidental for the second note (cp. the above
21 * FIXME) is printed. These issues should be resolved by some sort of
22 * ligature context that encloses use of this engraver, using syntax
23 * like: \ligature { e \~ c }.
25 * TODO: Do not allow a series of adjacent porrectus requests, as in:
28 * TODO: Junk duplicate (or rather triple) implementation of
29 * create_ledger_line in porrectus.cc, custos.cc and note-head.cc.
32 #include "staff-symbol-referencer.hh"
33 #include "porrectus.hh"
34 #include "musical-request.hh"
35 #include "command-request.hh"
36 #include "rhythmic-head.hh"
38 #include "engraver.hh"
39 #include "score-engraver.hh"
43 // TODO: PHead_melodic_tuple is duplicated code from tie-engraver.cc.
44 // Maybe put this into public class?
45 struct PHead_melodic_tuple {
49 PHead_melodic_tuple ();
50 PHead_melodic_tuple (Grob*, Melodic_req*, Moment);
51 static int pitch_compare (PHead_melodic_tuple const &,
52 PHead_melodic_tuple const &);
53 static int time_compare (PHead_melodic_tuple const &,
54 PHead_melodic_tuple const &);
57 inline int compare (PHead_melodic_tuple const &a, PHead_melodic_tuple const &b)
59 return PHead_melodic_tuple::time_compare (a,b);
62 class Porrectus_engraver : public Engraver {
64 TRANSLATOR_DECLARATIONS(Porrectus_engraver);
67 virtual bool try_music (Music *req_l);
68 virtual void process_music ();
69 virtual void create_grobs ();
70 virtual void stop_translation_timestep ();
71 virtual void start_translation_timestep ();
72 virtual void acknowledge_grob (Grob_info);
75 PQueue<PHead_melodic_tuple> past_notes_pq_;
76 Porrectus_req *porrectus_req_l_;
77 Array<PHead_melodic_tuple> left_heads_;
78 Array<PHead_melodic_tuple> right_heads_;
79 Link_array<Grob> porrectus_p_arr_;
82 Porrectus_engraver::Porrectus_engraver ()
88 Porrectus_engraver::try_music (Music *m)
90 if (Porrectus_req *req_l_ = dynamic_cast <Porrectus_req *> (m))
92 porrectus_req_l_ = req_l_;
100 Porrectus_engraver::process_music ()
102 if (porrectus_req_l_)
104 // TODO: Move code that forbids breaking into ligature music
106 Score_engraver *engraver = 0;
107 for (Translator *translator = daddy_grav_l ();
108 translator && !engraver;
109 translator = translator->daddy_trans_l_)
111 engraver = dynamic_cast<Score_engraver*> (translator);
115 programming_error ("No score engraver!");
117 engraver->forbid_breaks ();
122 Porrectus_engraver::acknowledge_grob (Grob_info info_l_)
124 if (Rhythmic_head::has_interface (info_l_.grob_l_))
126 Note_req *note_req_l_ = dynamic_cast <Note_req *> (info_l_.req_l_);
129 right_heads_.push (PHead_melodic_tuple (info_l_.grob_l_, note_req_l_,
131 note_req_l_->length_mom ()));
136 Porrectus_engraver::create_grobs ()
138 if (porrectus_req_l_)
140 left_heads_.sort (PHead_melodic_tuple::pitch_compare);
141 right_heads_.sort (PHead_melodic_tuple::pitch_compare);
142 int i = left_heads_.size () - 1;
143 int j = right_heads_.size () - 1;
145 while ((i >= 0) && (j >= 0))
147 Item *left_head = dynamic_cast<Item*> (left_heads_[i].head_l_);
148 Item *right_head = dynamic_cast<Item*> (right_heads_[j].head_l_);
149 left_head->set_grob_property("transparent", gh_bool2scm(true));
150 right_head->set_grob_property("transparent", gh_bool2scm(true));
152 Grob *porrectus_p_ = new Item (get_property ("Porrectus"));
153 Porrectus::set_left_head(porrectus_p_, left_head);
154 Porrectus::set_right_head(porrectus_p_, right_head);
155 porrectus_p_arr_.push (porrectus_p_);
156 announce_grob (porrectus_p_, porrectus_req_l_);
158 past_notes_pq_. insert (right_heads_[i]);
160 right_heads_.del (j);
168 Porrectus_engraver::stop_translation_timestep ()
170 for (int i = 0; i < right_heads_.size (); i++)
172 past_notes_pq_.insert (right_heads_[i]);
174 right_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 left_heads_.clear ();
192 while (past_notes_pq_.size () &&
193 (past_notes_pq_.front ().end_ == now))
194 left_heads_.push (past_notes_pq_.get ());
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_);
238 ENTER_DESCRIPTION(Porrectus_engraver,
239 /* descr */ "Join adjacent notes to a porrectus ligature.",
240 /* creats*/ "Porrectus",
241 /* acks */ "rhythmic-head-interface",