]> 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--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 */
6
7 #include "event.hh"
8 #include "slur.hh"
9 #include "note-column.hh"
10 #include "context.hh"
11 #include "directional-element-interface.hh"
12 #include "engraver.hh"
13 #include "spanner.hh"
14 #include "tie.hh"
15 #include "input.hh"
16 /*
17   It is possible that a slur starts and ends on the same note.  At
18   least, it is for phrasing slurs: a note can be both beginning and
19   ending of a phrase.
20 */
21
22 class Slur_engraver : public Engraver
23 {
24   Drul_array<Music *> events_;
25   Music * running_slur_start_;
26   Link_array<Grob> slurs_;
27   Link_array<Grob> end_slurs_;
28
29   void set_melisma (bool);
30
31 protected:
32   virtual bool try_music (Music*);
33   virtual void acknowledge_grob (Grob_info);
34   virtual void stop_translation_timestep ();
35   virtual void finalize ();
36   virtual void process_music ();
37
38 public:
39   TRANSLATOR_DECLARATIONS (Slur_engraver);
40 };
41
42 Slur_engraver::Slur_engraver ()
43 {
44   events_[START] =events_[STOP] = 0;
45 }
46
47 bool
48 Slur_engraver::try_music (Music *m)
49 {
50   if (m->is_mus_type ("slur-event"))
51     {
52       Direction d = to_dir (m->get_property ("span-direction"));
53       if (d == START)
54         {
55           events_[START] = m;
56           return true;
57         }
58       else if (d == STOP)
59         {
60           events_[STOP] = m;
61           return true;
62         }
63     }
64   return false;
65 }
66
67 void
68 Slur_engraver::set_melisma (bool m)
69 {
70   context ()->set_property ("slurMelismaBusy", m ? SCM_BOOL_T :SCM_BOOL_F);
71 }
72
73 void
74 Slur_engraver::acknowledge_grob (Grob_info info)
75 {
76   Grob *e =info.grob_;
77   if (Note_column::has_interface (info.grob_))
78     {
79       for (int i = slurs_.size (); i--; )
80         Slur::add_column (slurs_[i], e);
81       for (int i = end_slurs_.size (); i-- ; )
82         Slur::add_column (end_slurs_[i], e);
83     }
84   else
85     {
86       SCM inside = e->get_property ("inside-slur");
87       if (Tie::has_interface (e)
88           || to_boolean (inside))
89         {
90           for (int i = slurs_.size (); i--; )
91             Slur::add_extra_encompass (slurs_[i], e);
92           for (int i = end_slurs_.size (); i--; )
93             Slur::add_extra_encompass (end_slurs_[i], e);
94         }
95       else if (inside == SCM_BOOL_F)
96         {
97           Grob *slur = slurs_.size()?slurs_[0] : 0;
98           slur =  (end_slurs_.size () && !slur)
99             ? end_slurs_[0] : slur;
100
101           if (slur)
102             {
103               e->add_offset_callback (Slur::outside_slur_callback_proc, Y_AXIS);
104               e->set_property ("slur", slur->self_scm());
105             }
106         }
107     }
108 }
109
110 void
111 Slur_engraver::finalize ()
112 {
113   if (slurs_.size ())
114     slurs_[0]->warning (_("unterminated slur"));
115 }
116
117 void
118 Slur_engraver::process_music ()
119 {
120   if (events_[STOP])
121     {
122       if (slurs_.size() == 0)
123         {
124           events_[STOP]->origin()->warning (_ ("No slur to end"));
125         }
126       
127       end_slurs_ = slurs_;
128       slurs_.clear ();
129     }
130   
131   if (events_[START] && slurs_.is_empty ())
132     {
133       Music *ev = events_[START];
134
135       bool double_slurs = to_boolean (get_property ("doubleSlurs"));
136
137       Grob * slur = make_spanner ("Slur", events_[START]->self_scm ());
138       Direction updown = to_dir (ev->get_property ("direction"));
139       if (updown && !double_slurs)
140         set_grob_direction (slur, updown);
141
142       slurs_.push (slur);
143
144       if (double_slurs)
145         {
146           set_grob_direction (slur, DOWN);
147           slur = make_spanner ("Slur", events_[START]->self_scm ());
148           set_grob_direction (slur, UP);
149           slurs_.push (slur); 
150         }
151     }
152   set_melisma (slurs_.size ());
153 }
154
155 void
156 Slur_engraver::stop_translation_timestep ()
157 {
158   end_slurs_.clear ();
159   events_[START] = events_[STOP] = 0;
160 }
161
162 ENTER_DESCRIPTION (Slur_engraver,
163   /* descr */       "Build slurs grobs from slur events",
164   /* creats*/       "Slur",
165   /* accepts */     "slur-event",
166   /* acks  */      "note-column-interface accidental-interface fingering-interface script-interface tie-interface",
167   /* reads */       "slurMelismaBusy doubleSlurs",
168   /* write */       "");