]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-engraver.cc
* flower/include/pqueue.hh: Derive from std::vector.
[lilypond.git] / lily / slur-engraver.cc
1 /*
2   slur-engraver.cc -- implement Slur_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "engraver.hh"
10
11 #include "context.hh"
12 #include "directional-element-interface.hh"
13 #include "international.hh"
14 #include "note-column.hh"
15 #include "slur.hh"
16 #include "spanner.hh"
17 #include "tie.hh"
18 #include "warn.hh"
19
20 /*
21   It is possible that a slur starts and ends on the same note.  At
22   least, it is for phrasing slurs: a note can be both beginning and
23   ending of a phrase.
24 */
25 class Slur_engraver : public Engraver
26 {
27   Drul_array<Music *> events_;
28   Music *running_slur_start_;
29   Link_array__Grob_ slurs_;
30   Link_array__Grob_ end_slurs_;
31
32   void set_melisma (bool);
33
34 protected:
35   virtual bool try_music (Music *);
36
37   DECLARE_ACKNOWLEDGER (accidental);
38   DECLARE_ACKNOWLEDGER (dynamic_line_spanner);
39   DECLARE_ACKNOWLEDGER (fingering);
40   DECLARE_ACKNOWLEDGER (note_column);
41   DECLARE_ACKNOWLEDGER (script);
42   DECLARE_ACKNOWLEDGER (text_script);
43   DECLARE_ACKNOWLEDGER (tie);
44   DECLARE_ACKNOWLEDGER (tuplet_number);
45   void acknowledge_extra_object (Grob_info);
46   void stop_translation_timestep ();
47   virtual void finalize ();
48   void process_music ();
49
50 public:
51   TRANSLATOR_DECLARATIONS (Slur_engraver);
52 };
53
54 Slur_engraver::Slur_engraver ()
55 {
56   events_[START] = events_[STOP] = 0;
57 }
58
59 bool
60 Slur_engraver::try_music (Music *m)
61 {
62   if (m->is_mus_type ("slur-event"))
63     {
64       Direction d = to_dir (m->get_property ("span-direction"));
65       if (d == START)
66         {
67           events_[START] = m;
68           return true;
69         }
70       else if (d == STOP)
71         {
72           events_[STOP] = m;
73           return true;
74         }
75     }
76   return false;
77 }
78
79 void
80 Slur_engraver::set_melisma (bool m)
81 {
82   context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T : SCM_BOOL_F);
83 }
84
85 void
86 Slur_engraver::acknowledge_note_column (Grob_info info)
87 {
88   Grob *e = info.grob ();
89   for (vsize i = slurs_.size (); i--;)
90     Slur::add_column (slurs_[i], e);
91   for (vsize i = end_slurs_.size (); i--;)
92     Slur::add_column (end_slurs_[i], e);
93 }
94
95 void
96 Slur_engraver::acknowledge_extra_object (Grob_info info)
97 {
98   if (slurs_.empty () && end_slurs_.empty ())
99     return ;
100   
101   Grob *e = info.grob ();
102   SCM avoid = e->get_property ("avoid-slur");
103   if (Tie::has_interface (e)
104       || avoid == ly_symbol2scm ("inside"))
105     {
106       for (vsize i = slurs_.size (); i--;)
107         Slur::add_extra_encompass (slurs_[i], e);
108       for (vsize i = end_slurs_.size (); i--;)
109         Slur::add_extra_encompass (end_slurs_[i], e);
110     }
111   else if (avoid == ly_symbol2scm ("outside")
112            || avoid == ly_symbol2scm ("around"))
113     {
114       Grob *slur = slurs_.size () ? slurs_[0] : 0;
115       slur = (end_slurs_.size () && !slur)
116         ? end_slurs_[0] : slur;
117
118       if (slur)
119         {
120           chain_offset_callback (e, Slur::outside_slur_callback_proc, Y_AXIS);
121           e->set_object ("slur", slur->self_scm ());
122         }
123     }
124   else
125     e->warning ("Ignoring grob for slur. avoid-slur not set?");
126 }
127
128 void
129 Slur_engraver::acknowledge_accidental (Grob_info info)
130 {
131   acknowledge_extra_object (info);
132 }
133
134 void
135 Slur_engraver::acknowledge_dynamic_line_spanner (Grob_info info)
136 {
137   acknowledge_extra_object (info);
138 }
139
140 void
141 Slur_engraver::acknowledge_fingering (Grob_info info)
142 {
143   acknowledge_extra_object (info);
144 }
145
146 void
147 Slur_engraver::acknowledge_tuplet_number (Grob_info info)
148 {
149   acknowledge_extra_object (info);
150 }
151
152
153 void
154 Slur_engraver::acknowledge_script (Grob_info info)
155 {
156   acknowledge_extra_object (info);
157 }
158
159 void
160 Slur_engraver::acknowledge_text_script (Grob_info info)
161 {
162   //  if (!info.grob ()->internal_has_interface (ly_symbol2scm ("DynamicText")))
163   acknowledge_extra_object (info);
164 }
165
166 void
167 Slur_engraver::acknowledge_tie (Grob_info info)
168 {
169   acknowledge_extra_object (info);
170 }
171
172 void
173 Slur_engraver::finalize ()
174 {
175   if (slurs_.size ())
176     slurs_[0]->warning (_ ("unterminated slur"));
177 }
178
179 void
180 Slur_engraver::process_music ()
181 {
182   if (events_[STOP])
183     {
184       if (slurs_.size () == 0)
185         events_[STOP]->origin ()->warning (_ ("can't end slur"));
186
187       end_slurs_ = slurs_;
188       slurs_.clear ();
189     }
190
191   if (events_[START] && slurs_.empty ())
192     {
193       Music *ev = events_[START];
194
195       bool double_slurs = to_boolean (get_property ("doubleSlurs"));
196
197       Grob *slur = make_spanner ("Slur", events_[START]->self_scm ());
198       Direction updown = to_dir (ev->get_property ("direction"));
199       if (updown && !double_slurs)
200         set_grob_direction (slur, updown);
201
202       slurs_.push_back (slur);
203
204       if (double_slurs)
205         {
206           set_grob_direction (slur, DOWN);
207           slur = make_spanner ("Slur", events_[START]->self_scm ());
208           set_grob_direction (slur, UP);
209           slurs_.push_back (slur);
210         }
211     }
212   set_melisma (slurs_.size ());
213 }
214
215 void
216 Slur_engraver::stop_translation_timestep ()
217 {
218   end_slurs_.clear ();
219   events_[START] = events_[STOP] = 0;
220 }
221
222 #include "translator.icc"
223
224 ADD_ACKNOWLEDGER (Slur_engraver, accidental);
225 ADD_ACKNOWLEDGER (Slur_engraver, dynamic_line_spanner);
226 ADD_ACKNOWLEDGER (Slur_engraver, fingering);
227 ADD_ACKNOWLEDGER (Slur_engraver, note_column);
228 ADD_ACKNOWLEDGER (Slur_engraver, script);
229 ADD_ACKNOWLEDGER (Slur_engraver, text_script);
230 ADD_ACKNOWLEDGER (Slur_engraver, tie);
231 ADD_ACKNOWLEDGER (Slur_engraver, tuplet_number);
232 ADD_TRANSLATOR (Slur_engraver,
233                 /* doc */ "Build slur grobs from slur events",
234                 /* create */ "Slur",
235                 /* accept */ "slur-event",
236                 /* read */ "slurMelismaBusy doubleSlurs",
237                 /* write */ "");