]> git.donarmstrong.com Git - lilypond.git/blob - lily/slur-engraver.cc
(spanned_rank_iv): Bugfix.
[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 "new-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 *m)
47 {
48   if (m->is_mus_type ("slur-event"))
49     {
50       /*
51         Let's not start more than one slur per moment.
52       */
53       Direction d = to_dir (m->get_property ("span-direction"));
54       if (d == START)
55         {
56           if (now_mom () > last_start_)
57             {
58               new_slur_evs_.push (m);
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 (m);
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   Grob *e =info.grob_;
98   if (Note_column::has_interface (info.grob_))
99     {
100       for (int i = 0; i < slur_stack_.size (); i++)
101         New_slur::add_column (slur_stack_[i], e);
102       for (int i = 0; i < end_slurs_.size (); i++)
103         New_slur::add_column (end_slurs_[i], e);
104     }
105   else
106     {
107       for (int i = 0; i < slur_stack_.size (); i++)
108         New_slur::add_extra_encompass (slur_stack_[i], e);
109       for (int i = 0; i < end_slurs_.size (); i++)
110         New_slur::add_extra_encompass (end_slurs_[i], e);
111     }
112 }
113
114 void
115 Slur_engraver::finalize ()
116 {
117   for (int i = 0; i < slur_stack_.size (); i++)
118     {
119       /*
120         Let's not typeset unterminated stuff
121        */
122       slur_stack_[i]->suicide ();
123     }
124   slur_stack_.clear ();
125
126   for (int i=0; i < events_.size (); i++)
127       {
128         events_[i]->origin ()->warning (_ ("unterminated slur"));
129       }
130 }
131
132 void
133 Slur_engraver::process_music ()
134 {
135   Link_array<Grob> start_slurs;
136   for (int i=0; i< new_slur_evs_.size (); i++)
137     {
138       Music* slur_ev = new_slur_evs_[i];
139       // end slur: move the slur to other array
140       Direction d = to_dir (slur_ev->get_property ("span-direction"));
141       if (d== STOP)
142         {
143           if (slur_stack_.is_empty ())
144             /* How to shut up this warning, when Voice_devnull_engraver has
145                eaten start event? */
146             slur_ev->origin ()->warning (_f ("can't find start of slur"));
147           else
148             {
149               Grob* slur = slur_stack_.pop ();
150             
151               end_slurs_.push (slur);
152               events_.pop ();
153             }
154         }
155       else  if (d == START)
156         {
157           /* push a new slur onto stack.
158              (use temp. array to wait for all slur STOPs) */
159           Grob *slur = make_spanner ("Slur", slur_ev->self_scm ());
160
161           if (Direction updown = to_dir (slur_ev->get_property ("direction")))
162             slur->set_property ("direction", scm_int2num (updown));
163
164           start_slurs.push (slur);
165           events_.push (slur_ev);
166         }
167     }
168
169   slur_stack_.concat  (start_slurs);
170
171   set_melisma (slur_stack_.size ());
172
173   new_slur_evs_.clear ();
174 }
175
176 void
177 Slur_engraver::stop_translation_timestep ()
178 {
179   end_slurs_.clear ();
180   new_slur_evs_.clear ();
181 }
182
183
184
185 ENTER_DESCRIPTION (Slur_engraver,
186 /* descr */       "Build slurs grobs from slur events",
187 /* creats*/       "Slur",
188 /* accepts */     "slur-event",
189 /* acks  */      "note-column-interface accidental-interface fingering-interface script-interface",
190 /* reads */       "slurMelismaBusy",
191 /* write */       "");