]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-engraver.cc
*** empty log message ***
[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_acknowledged_grobs ();
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         }
84       else if (d == STOP)
85         {
86           /*
87             Swallow other events.
88           */
89           for (int j = new_slur_evs_.size(); j--;)
90             {
91               Direction nd = to_dir (new_slur_evs_[j]->get_mus_property ("span-direction"));
92               
93               if (nd == STOP)
94                 return true;
95             }
96               
97           new_slur_evs_.push (ev);
98           return true;
99         }
100     }
101   return false;
102 }
103
104 void
105 Slur_engraver::set_melisma (bool m)
106 {
107   daddy_trans_->set_property ("slurMelismaBusy", m ? SCM_BOOL_T :SCM_BOOL_F);
108 }
109
110 void
111 Slur_engraver::acknowledge_grob (Grob_info info)
112 {
113   if (Note_column::has_interface (info.grob_))
114     {
115       Grob *e =info.grob_;
116       for (int i = 0; i < slur_stack_.size (); i++)
117         Slur::add_column (slur_stack_[i], e);
118       for (int i = 0; i < end_slurs_.size (); i++)
119         Slur::add_column (end_slurs_[i], e);
120     }
121 }
122
123 void
124 Slur_engraver::finalize ()
125 {
126   for (int i = 0; i < slur_stack_.size (); i++)
127     {
128 #if 0
129       typeset_grob (slur_stack_[i]);
130 #else
131       /*
132         Let's not typeset unterminated stuff
133        */
134       slur_stack_[i]->suicide ();
135 #endif     
136     }
137   slur_stack_.clear ();
138
139   for (int i=0; i < events_.size (); i++)
140       {
141         events_[i]->origin ()->warning (_ ("unterminated slur"));
142       }
143 }
144
145 void
146 Slur_engraver::process_acknowledged_grobs ()
147 {
148   Link_array<Grob> start_slurs;
149   for (int i=0; i< new_slur_evs_.size (); i++)
150     {
151       Music* slur_ev = new_slur_evs_[i];
152       // end slur: move the slur to other array
153       Direction d = to_dir (slur_ev->get_mus_property ("span-direction"));
154       if (d== STOP)
155         {
156           if (slur_stack_.empty ())
157             /* How to shut up this warning, when Voice_devnull_engraver has
158                eaten start event? */
159             slur_ev->origin ()->warning (_f ("can't find start of slur"));
160           else
161             {
162               Grob* slur = slur_stack_.pop ();
163             
164               end_slurs_.push (slur);
165               events_.pop ();
166             }
167         }
168       else  if (d == START)
169         {
170           // push a new slur onto stack.
171           // (use temp. array to wait for all slur STOPs)
172           Grob* slur = new Spanner (get_property ("Slur"));
173           Slur::set_interface (slur); // cannot remove yet!
174
175
176           if (Direction updown = to_dir (slur_ev->get_mus_property ("direction")))
177             {
178               slur->set_grob_property ("direction", gh_int2scm (updown));
179             }
180           
181           start_slurs.push (slur);
182           events_.push (slur_ev);
183           announce_grob (slur, slur_ev->self_scm ());
184         }
185     }
186   for (int i=0; i < start_slurs.size (); i++)
187     slur_stack_.push (start_slurs[i]);
188   new_slur_evs_.clear ();
189 }
190
191 void
192 Slur_engraver::stop_translation_timestep ()
193 {
194   for (int i = 0; i < end_slurs_.size (); i++)
195     {
196       typeset_grob (end_slurs_[i]);
197     }
198   end_slurs_.clear ();
199 }
200
201 void
202 Slur_engraver::start_translation_timestep ()
203 {
204   new_slur_evs_.clear ();
205   SCM m = get_property ("automaticMelismata");
206   if (to_boolean (m))
207     {
208       set_melisma (slur_stack_.size ());
209     }
210 }
211
212
213
214 ENTER_DESCRIPTION (Slur_engraver,
215 /* descr */       "Build slurs from Slur_evs",
216 /* creats*/       "Slur",
217 /* accepts */     "slur-event",
218 /* acks  */      "note-column-interface",
219 /* reads */       "slurMelismaBusy",
220 /* write */       "");