]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-engraver.cc
* scm/engraver-documentation-lib.scm
[lilypond.git] / lily / slur-engraver.cc
1 /*
2   slur-engraver.cc -- implement Slur_engraver
3
4   (c)  1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 */
6
7 #include "request.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> requests_;
21   Link_array<Music> new_slur_reqs_;
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 *req)
47 {
48   if (req->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       requests_.clear ();
61       new_slur_reqs_.clear ();
62     }
63   else if (req->is_mus_type ("slur-event"))
64     {
65       /*
66         Let's not start more than one slur per moment.
67       */
68       Direction d = to_dir (req->get_mus_property ("span-direction"));
69       if (d == START)
70         {
71           if (now_mom () > last_start_)
72             {
73               new_slur_reqs_.push (req);
74               last_start_ = now_mom ();
75             }
76
77           /*
78             But we swallow other slur requests.
79           */
80               
81           return true;
82
83         }
84       else if (d == STOP)
85         {
86           /*
87             Swallow other requests.
88           */
89           for (int j = new_slur_reqs_.size(); j--;)
90             {
91               Direction nd = to_dir (new_slur_reqs_[j]->get_mus_property ("span-direction"));
92               
93               if (nd == STOP)
94                 return true;
95             }
96               
97           new_slur_reqs_.push (req);
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 < requests_.size (); i++)
140       {
141         requests_[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_reqs_.size (); i++)
150     {
151       Music* slur_req = new_slur_reqs_[i];
152       // end slur: move the slur to other array
153       Direction d = to_dir (slur_req->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 request? */
159             slur_req->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               requests_.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           start_slurs.push (slur);
175           requests_.push (slur_req);
176           announce_grob (slur, slur_req->self_scm ());
177         }
178     }
179   for (int i=0; i < start_slurs.size (); i++)
180     slur_stack_.push (start_slurs[i]);
181   new_slur_reqs_.clear ();
182 }
183
184 void
185 Slur_engraver::stop_translation_timestep ()
186 {
187   for (int i = 0; i < end_slurs_.size (); i++)
188     {
189       typeset_grob (end_slurs_[i]);
190     }
191   end_slurs_.clear ();
192 }
193
194 void
195 Slur_engraver::start_translation_timestep ()
196 {
197   new_slur_reqs_.clear ();
198   SCM m = get_property ("automaticMelismata");
199   if (to_boolean (m))
200     {
201       set_melisma (slur_stack_.size ());
202     }
203 }
204
205
206
207 ENTER_DESCRIPTION (Slur_engraver,
208 /* descr */       "Build slurs from Slur_reqs",
209 /* creats*/       "Slur",
210 /* accepts */     "slur-event",
211 /* acks  */      "note-column-interface",
212 /* reads */       "slurMelismaBusy",
213 /* write */       "");