]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-engraver.cc
* lily/lyric-phrasing-engraver.cc: move from
[lilypond.git] / lily / slur-engraver.cc
1 /*
2   slur-engraver.cc -- implement Slur_engraver
3
4   (c)  1997--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 */
6
7 #include "event.hh"
8 #include "slur.hh"
9 #include "warn.hh"
10 #include "note-column.hh"
11 #include "translator-group.hh"
12 #include "engraver.hh"
13 #include "spanner.hh"
14
15 /*
16   TODO: junk nested slur functionality.
17  */
18 class Slur_engraver : public Engraver
19 {
20   Link_array<Music> events_;
21   Link_array<Music> new_slur_evs_;
22   Link_array<Grob> slur_stack_;
23   Link_array<Grob> end_slurs_;
24   Moment last_start_;
25
26   void set_melisma (bool);
27
28 protected:
29   virtual bool try_music (Music*);
30   virtual void acknowledge_grob (Grob_info);
31   virtual void stop_translation_timestep ();
32   virtual void start_translation_timestep ();
33   virtual void finalize ();
34   virtual void process_music ();
35
36 public:
37   TRANSLATOR_DECLARATIONS (Slur_engraver);
38 };
39
40 Slur_engraver::Slur_engraver ()
41 {
42   last_start_ = Moment (-1);
43 }
44
45 bool
46 Slur_engraver::try_music (Music *ev)
47 {
48   if (ev->is_mus_type ("abort-event"))
49     {
50       for (int i = 0; i < slur_stack_.size (); i++)
51         {
52           slur_stack_[i]->suicide ();
53         }
54       slur_stack_.clear ();
55       for (int i = 0; i < end_slurs_.size (); i++)
56         {
57           end_slurs_[i]->suicide ();
58         }
59       end_slurs_.clear ();
60       events_.clear ();
61       new_slur_evs_.clear ();
62     }
63   else if (ev->is_mus_type ("slur-event"))
64     {
65       /*
66         Let's not start more than one slur per moment.
67       */
68       Direction d = to_dir (ev->get_mus_property ("span-direction"));
69       if (d == START)
70         {
71           if (now_mom () > last_start_)
72             {
73               new_slur_evs_.push (ev);
74               last_start_ = now_mom ();
75             }
76
77           /*
78             But we swallow other slur events.
79           */
80               
81           return true;
82         }
83       else if (d == STOP)
84         {
85           /*
86             Swallow other events.
87           */
88           for (int j = new_slur_evs_.size(); j--;)
89             {
90               Direction nd = to_dir (new_slur_evs_[j]->get_mus_property ("span-direction"));
91               
92               if (nd == STOP)
93                 return true;
94             }
95               
96           new_slur_evs_.push (ev);
97           return true;
98         }
99     }
100   return false;
101 }
102
103 void
104 Slur_engraver::set_melisma (bool m)
105 {
106   daddy_trans_->set_property ("slurMelismaBusy", m ? SCM_BOOL_T :SCM_BOOL_F);
107 }
108
109 void
110 Slur_engraver::acknowledge_grob (Grob_info info)
111 {
112   if (Note_column::has_interface (info.grob_))
113     {
114       Grob *e =info.grob_;
115       for (int i = 0; i < slur_stack_.size (); i++)
116         Slur::add_column (slur_stack_[i], e);
117       for (int i = 0; i < end_slurs_.size (); i++)
118         Slur::add_column (end_slurs_[i], e);
119     }
120 }
121
122 void
123 Slur_engraver::finalize ()
124 {
125   for (int i = 0; i < slur_stack_.size (); i++)
126     {
127       /*
128         Let's not typeset unterminated stuff
129        */
130       slur_stack_[i]->suicide ();
131     }
132   slur_stack_.clear ();
133
134   for (int i=0; i < events_.size (); i++)
135       {
136         events_[i]->origin ()->warning (_ ("unterminated slur"));
137       }
138 }
139
140 void
141 Slur_engraver::process_music ()
142 {
143   Link_array<Grob> start_slurs;
144   for (int i=0; i< new_slur_evs_.size (); i++)
145     {
146       Music* slur_ev = new_slur_evs_[i];
147       // end slur: move the slur to other array
148       Direction d = to_dir (slur_ev->get_mus_property ("span-direction"));
149       if (d== STOP)
150         {
151           if (slur_stack_.empty ())
152             /* How to shut up this warning, when Voice_devnull_engraver has
153                eaten start event? */
154             slur_ev->origin ()->warning (_f ("can't find start of slur"));
155           else
156             {
157               Grob* slur = slur_stack_.pop ();
158             
159               end_slurs_.push (slur);
160               events_.pop ();
161             }
162         }
163       else  if (d == START)
164         {
165           // push a new slur onto stack.
166           // (use temp. array to wait for all slur STOPs)
167           Grob* slur = new Spanner (get_property ("Slur"));
168           Slur::set_interface (slur); // cannot remove yet!
169
170
171           if (Direction updown = to_dir (slur_ev->get_mus_property ("direction")))
172             {
173               slur->set_grob_property ("direction", gh_int2scm (updown));
174             }
175           
176           start_slurs.push (slur);
177           events_.push (slur_ev);
178           announce_grob (slur, slur_ev->self_scm ());
179         }
180     }
181
182   slur_stack_.concat  (start_slurs);
183
184   set_melisma (slur_stack_.size ());
185
186   new_slur_evs_.clear ();
187 }
188
189 void
190 Slur_engraver::stop_translation_timestep ()
191 {
192   for (int i = 0; i < end_slurs_.size (); i++)
193     {
194       typeset_grob (end_slurs_[i]);
195     }
196   end_slurs_.clear ();
197 }
198
199 void
200 Slur_engraver::start_translation_timestep ()
201 {
202   new_slur_evs_.clear ();
203 }
204
205
206
207 ENTER_DESCRIPTION (Slur_engraver,
208 /* descr */       "Build slurs from Slur_evs",
209 /* creats*/       "Slur",
210 /* accepts */     "slur-event",
211 /* acks  */      "note-column-interface",
212 /* reads */       "slurMelismaBusy",
213 /* write */       "");