]> git.donarmstrong.com Git - lilypond.git/blob - lily/porrectus-engraver.cc
patch::: 1.5.18.moh1: [PATCH] 1.4 Lyric alignment
[lilypond.git] / lily / porrectus-engraver.cc
1 /*
2   porrectus-engraver.cc -- implement Porrectus_engraver
3
4   Copyright (C) 2001 Juergen Reuter
5
6   written for the GNU LilyPond music typesetter
7 */
8
9 /*
10  * FIXME: Currently, when creating a porrectus item, it takes the
11  * moment of the second note.  Actually, it should take the moment of
12  * the first note.
13  *
14  * FIXME: Turn off typesetting of stems, flags, dots, etc.
15  *
16  * TODO: Hufnagel support.
17  *
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 }.
24  *
25  * TODO: Do not allow a series of adjacent porrectus requests, as in:
26  * e \~ d \~ c.
27  *
28  * TODO: Junk duplicate (or rather triple) implementation of
29  * create_ledger_line in porrectus.cc, custos.cc and note-head.cc.
30  */
31
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"
37 #include "item.hh"
38 #include "engraver.hh"
39 #include "score-engraver.hh"
40 #include "pqueue.hh"
41 #include "warn.hh"
42
43 // TODO: PHead_melodic_tuple is duplicated code from tie-engraver.cc.
44 // Maybe put this into public class?
45 struct PHead_melodic_tuple {
46   Melodic_req *req_l_;
47   Grob *head_l_;
48   Moment end_;
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 &);  
55 };
56
57 inline int compare (PHead_melodic_tuple const &a, PHead_melodic_tuple const &b)
58 {
59   return PHead_melodic_tuple::time_compare (a,b);
60 }
61
62 class Porrectus_engraver : public Engraver {
63 public:
64   TRANSLATOR_DECLARATIONS(Porrectus_engraver);
65   
66 protected:
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);
73
74 private:
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_;
80 };
81
82 Porrectus_engraver::Porrectus_engraver ()
83 {
84   porrectus_req_l_ = 0;
85 }
86
87 bool
88 Porrectus_engraver::try_music (Music *m)
89 {
90   if (Porrectus_req *req_l_ = dynamic_cast <Porrectus_req *> (m))
91     {
92       porrectus_req_l_ = req_l_;
93       return true;
94     }
95   else
96     return false;
97 }
98
99 void
100 Porrectus_engraver::process_music ()
101 {
102   if (porrectus_req_l_)
103     {
104       // TODO: Move code that forbids breaking into ligature music
105       // wrapper?
106       Score_engraver *engraver = 0;
107       for (Translator *translator = daddy_grav_l ();
108            translator && !engraver;
109            translator = translator->daddy_trans_l_)
110         {
111           engraver = dynamic_cast<Score_engraver*> (translator);
112         }
113       
114       if (!engraver)
115         programming_error ("No score engraver!");
116       else
117         engraver->forbid_breaks ();
118     }
119 }
120
121 void
122 Porrectus_engraver::acknowledge_grob (Grob_info info_l_)
123 {
124   if (Rhythmic_head::has_interface (info_l_.grob_l_))
125     {
126       Note_req *note_req_l_ = dynamic_cast <Note_req *> (info_l_.req_l_);
127       if (!note_req_l_)
128         return;
129       right_heads_.push (PHead_melodic_tuple (info_l_.grob_l_, note_req_l_,
130                                               now_mom () +
131                                               note_req_l_->length_mom ()));
132     }
133 }
134
135 void
136 Porrectus_engraver::create_grobs ()
137 {
138   if (porrectus_req_l_)
139     {
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;
144
145       while ((i >= 0) && (j >= 0))
146         {
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));
151
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_);
157
158           past_notes_pq_. insert (right_heads_[i]);
159           left_heads_.del (i);
160           right_heads_.del (j);
161           i--;
162           j--;
163         }
164     }
165 }
166
167 void
168 Porrectus_engraver::stop_translation_timestep ()
169 {
170   for (int i = 0; i < right_heads_.size (); i++)
171     {
172       past_notes_pq_.insert (right_heads_[i]);
173     }
174   right_heads_.clear ();
175
176   for (int i = 0; i < porrectus_p_arr_.size (); i++)
177     {
178       typeset_grob (porrectus_p_arr_[i]);
179     }
180   porrectus_p_arr_.clear ();
181 }
182
183 void
184 Porrectus_engraver::start_translation_timestep ()
185 {
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 ();
190
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 ());
195 }
196
197
198
199 // TODO: PHead_melodic_tuple is duplicated code from tie-engraver.cc.
200 // Maybe put this into public class?
201
202 PHead_melodic_tuple::PHead_melodic_tuple ()
203 {
204   head_l_ = 0;
205   req_l_ = 0;
206   end_ = 0;
207 }
208
209 PHead_melodic_tuple::PHead_melodic_tuple (Grob *h, Melodic_req*m, Moment mom)
210 {
211   head_l_ = h;
212   req_l_ = m;
213   end_ = mom;
214 }
215
216 /*
217   signed compare, should use pitch<? 
218  */
219 int
220 PHead_melodic_tuple::pitch_compare (PHead_melodic_tuple const&h1,
221                                     PHead_melodic_tuple const &h2)
222 {
223   SCM p1 = h1.req_l_->get_mus_property ("pitch");
224   SCM p2 = h2.req_l_->get_mus_property ("pitch");
225   
226   int result = Pitch::compare (*unsmob_pitch (p1),
227                                *unsmob_pitch (p2));
228   return result;
229 }
230
231 int
232 PHead_melodic_tuple::time_compare (PHead_melodic_tuple const&h1,
233                                    PHead_melodic_tuple const &h2)
234 {
235   int result = Moment::compare(h1.end_,  h2.end_);
236   return result;
237 }
238 ENTER_DESCRIPTION(Porrectus_engraver,
239 /* descr */       "Join adjacent notes to a porrectus ligature.",
240 /* creats*/       "Porrectus",
241 /* acks  */       "rhythmic-head-interface",
242 /* reads */       "",
243 /* write */       "");