]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-engraver.cc
Configure only pristine build tree or on user
[lilypond.git] / lily / slur-engraver.cc
1 /*
2   slur-engraver.cc -- implement Slur_engraver
3
4   (c) 1997--2004 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 "context.hh"
12
13 #include "engraver.hh"
14 #include "spanner.hh"
15
16 /*
17   TODO: junk nested slur functionality.
18  */
19 class Slur_engraver : public Engraver
20 {
21   Link_array<Music> events_;
22   Link_array<Music> new_slur_evs_;
23   Link_array<Grob> slur_stack_;
24   Link_array<Grob> end_slurs_;
25   Moment last_start_;
26
27   void set_melisma (bool);
28
29 protected:
30   virtual bool try_music (Music*);
31   virtual void acknowledge_grob (Grob_info);
32   virtual void stop_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 ("slur-event"))
49     {
50       /*
51         Let's not start more than one slur per moment.
52       */
53       Direction d = to_dir (ev->get_property ("span-direction"));
54       if (d == START)
55         {
56           if (now_mom () > last_start_)
57             {
58               new_slur_evs_.push (ev);
59               last_start_ = now_mom ();
60             }
61
62           /*
63             But we swallow other slur events.
64           */
65               
66           return true;
67         }
68       else if (d == STOP)
69         {
70           /*
71             Swallow other events.
72           */
73           for (int j = new_slur_evs_.size (); j--;)
74             {
75               Direction nd = to_dir (new_slur_evs_[j]->get_property ("span-direction"));
76               
77               if (nd == STOP)
78                 return true;
79             }
80               
81           new_slur_evs_.push (ev);
82           return true;
83         }
84     }
85   return false;
86 }
87
88 void
89 Slur_engraver::set_melisma (bool m)
90 {
91   context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T :SCM_BOOL_F);
92 }
93
94 void
95 Slur_engraver::acknowledge_grob (Grob_info info)
96 {
97   if (Note_column::has_interface (info.grob_))
98     {
99       Grob *e =info.grob_;
100       for (int i = 0; i < slur_stack_.size (); i++)
101         Slur::add_column (slur_stack_[i], e);
102       for (int i = 0; i < end_slurs_.size (); i++)
103         Slur::add_column (end_slurs_[i], e);
104     }
105 }
106
107 void
108 Slur_engraver::finalize ()
109 {
110   for (int i = 0; i < slur_stack_.size (); i++)
111     {
112       /*
113         Let's not typeset unterminated stuff
114        */
115       slur_stack_[i]->suicide ();
116     }
117   slur_stack_.clear ();
118
119   for (int i=0; i < events_.size (); i++)
120       {
121         events_[i]->origin ()->warning (_ ("unterminated slur"));
122       }
123 }
124
125 void
126 Slur_engraver::process_music ()
127 {
128   Link_array<Grob> start_slurs;
129   for (int i=0; i< new_slur_evs_.size (); i++)
130     {
131       Music* slur_ev = new_slur_evs_[i];
132       // end slur: move the slur to other array
133       Direction d = to_dir (slur_ev->get_property ("span-direction"));
134       if (d== STOP)
135         {
136           if (slur_stack_.is_empty ())
137             /* How to shut up this warning, when Voice_devnull_engraver has
138                eaten start event? */
139             slur_ev->origin ()->warning (_f ("can't find start of slur"));
140           else
141             {
142               Grob* slur = slur_stack_.pop ();
143             
144               end_slurs_.push (slur);
145               events_.pop ();
146             }
147         }
148       else  if (d == START)
149         {
150           // push a new slur onto stack.
151           // (use temp. array to wait for all slur STOPs)
152           Grob* slur = make_spanner ("Slur", slur_ev->self_scm ());
153           Slur::set_interface (slur); // cannot remove yet!
154
155
156           if (Direction updown = to_dir (slur_ev->get_property ("direction")))
157             {
158               slur->set_property ("direction", scm_int2num (updown));
159             }
160           
161           start_slurs.push (slur);
162           events_.push (slur_ev);
163         }
164     }
165
166   slur_stack_.concat  (start_slurs);
167
168   set_melisma (slur_stack_.size ());
169
170   new_slur_evs_.clear ();
171 }
172
173 void
174 Slur_engraver::stop_translation_timestep ()
175 {
176   end_slurs_.clear ();
177   new_slur_evs_.clear ();
178 }
179
180
181
182 ENTER_DESCRIPTION (Slur_engraver,
183 /* descr */       "Build slurs from Slur_evs",
184 /* creats*/       "Slur",
185 /* accepts */     "slur-event",
186 /* acks  */      "note-column-interface",
187 /* reads */       "slurMelismaBusy",
188 /* write */       "");