]> git.donarmstrong.com Git - lilypond.git/blob - lily/porrectus-engraver.cc
release: 1.5.22
[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 #include "grob-pitch-tuple.hh"
43
44 class Porrectus_engraver : public Engraver {
45 public:
46   TRANSLATOR_DECLARATIONS(Porrectus_engraver);
47   
48 protected:
49   virtual bool try_music (Music *req_l);
50   virtual void process_music ();
51   virtual void create_grobs ();
52   virtual void stop_translation_timestep ();
53   virtual void start_translation_timestep ();
54   virtual void acknowledge_grob (Grob_info);
55
56 private:
57   PQueue<Grob_pitch_tuple> past_notes_pq_;
58   Porrectus_req *porrectus_req_l_;
59   Array<Grob_pitch_tuple> left_heads_;
60   Array<Grob_pitch_tuple> right_heads_;
61   Link_array<Grob> porrectus_p_arr_;
62 };
63
64 Porrectus_engraver::Porrectus_engraver ()
65 {
66   porrectus_req_l_ = 0;
67 }
68
69 bool
70 Porrectus_engraver::try_music (Music *m)
71 {
72   if (Porrectus_req *req_l_ = dynamic_cast <Porrectus_req *> (m))
73     {
74       porrectus_req_l_ = req_l_;
75       return true;
76     }
77   else
78     return false;
79 }
80
81 void
82 Porrectus_engraver::process_music ()
83 {
84   if (porrectus_req_l_)
85     {
86       top_engraver ()->forbid_breaks ();
87     }
88 }
89
90 void
91 Porrectus_engraver::acknowledge_grob (Grob_info info_l_)
92 {
93   if (Rhythmic_head::has_interface (info_l_.grob_l_))
94     {
95       Note_req *note_req_l_ = dynamic_cast <Note_req *> (info_l_.req_l_);
96       if (!note_req_l_)
97         return;
98       right_heads_.push (Grob_pitch_tuple (info_l_.grob_l_, note_req_l_,
99                                               now_mom () +
100                                               note_req_l_->length_mom ()));
101     }
102 }
103
104 void
105 Porrectus_engraver::create_grobs ()
106 {
107   if (porrectus_req_l_)
108     {
109       left_heads_.sort (Grob_pitch_tuple::pitch_compare);
110       right_heads_.sort (Grob_pitch_tuple::pitch_compare);
111       int i = left_heads_.size () - 1;
112       int j = right_heads_.size () - 1;
113
114       while ((i >= 0) && (j >= 0))
115         {
116           Item *left_head = dynamic_cast<Item*> (left_heads_[i].head_l_);
117           Item *right_head = dynamic_cast<Item*> (right_heads_[j].head_l_);
118           left_head->set_grob_property("transparent", gh_bool2scm(true));
119           right_head->set_grob_property("transparent", gh_bool2scm(true));
120
121           Grob *porrectus_p_ = new Item (get_property ("Porrectus"));
122           Porrectus::set_left_head(porrectus_p_, left_head);
123           Porrectus::set_right_head(porrectus_p_, right_head);
124           porrectus_p_arr_.push (porrectus_p_);
125           announce_grob (porrectus_p_, porrectus_req_l_);
126
127           past_notes_pq_. insert (right_heads_[i]);
128           left_heads_.del (i);
129           right_heads_.del (j);
130           i--;
131           j--;
132         }
133     }
134 }
135
136 void
137 Porrectus_engraver::stop_translation_timestep ()
138 {
139   for (int i = 0; i < right_heads_.size (); i++)
140     {
141       past_notes_pq_.insert (right_heads_[i]);
142     }
143   right_heads_.clear ();
144
145   for (int i = 0; i < porrectus_p_arr_.size (); i++)
146     {
147       typeset_grob (porrectus_p_arr_[i]);
148     }
149   porrectus_p_arr_.clear ();
150 }
151
152 void
153 Porrectus_engraver::start_translation_timestep ()
154 {
155   porrectus_req_l_ = 0;
156   Moment now = now_mom ();
157   while (past_notes_pq_.size () && past_notes_pq_.front ().end_ < now)
158     past_notes_pq_.delmin ();
159
160   left_heads_.clear ();
161   while (past_notes_pq_.size () &&
162          (past_notes_pq_.front ().end_ == now))
163     left_heads_.push (past_notes_pq_.get ());
164 }
165
166
167
168 ENTER_DESCRIPTION(Porrectus_engraver,
169 /* descr */       "Join adjacent notes to a porrectus ligature.",
170 /* creats*/       "Porrectus",
171 /* acks  */       "rhythmic-head-interface",
172 /* reads */       "",
173 /* write */       "");