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