]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-phrasing-engraver.cc
(LY_DEFINE): use Scheme style naming for
[lilypond.git] / lily / lyric-phrasing-engraver.cc
1 /*   
2   new-phrasing-engraver.cc --  implement New_phrasing_engraver
3
4 source file of the GNU LilyPond music typesetter
5
6 (c) 2003--2004 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8  */
9
10
11 #include "context.hh"
12 #include "engraver.hh"
13 #include "note-head.hh"
14 #include "lyric-extender.hh"
15 #include "item.hh"
16 #include "group-interface.hh"
17 #include "side-position-interface.hh"
18
19 struct Phrasing_association
20 {
21   String name_;
22   Link_array<Grob> lyrics_;
23   Link_array<Grob> heads_;
24   Link_array<Spanner> past_extenders_;
25   Link_array<Spanner> new_extenders_;
26   Link_array<Grob> stanza_numbers_;
27
28   
29   bool melisma_;
30   
31   Phrasing_association()
32   {
33     melisma_ = false;
34   }
35 };
36
37 class Lyric_phrasing_engraver : public Engraver
38 {
39 public:
40   ~Lyric_phrasing_engraver ();
41   TRANSLATOR_DECLARATIONS(Lyric_phrasing_engraver);
42 protected:
43   virtual void acknowledge_grob (Grob_info);
44   virtual void process_acknowledged_grobs ();
45   virtual void stop_translation_timestep ();
46
47 private:
48   void add_lyric_phrasing (Grob_info);
49   void add_voice_phrasing (Grob_info);
50   void add_lyric_extender (Grob_info);
51   void add_stanza_number (Grob_info);
52   Phrasing_association *get_phrasing_assoc (String nm);
53   String get_voice_name_for_lyric (Context *tr);
54   Link_array<Phrasing_association> assocs_;
55 };
56
57 Lyric_phrasing_engraver::Lyric_phrasing_engraver()
58 {
59 }
60
61 void
62 Lyric_phrasing_engraver::acknowledge_grob (Grob_info i)
63 {
64   Grob *h = i.grob_;
65
66   if (Note_head::has_interface (h))
67     add_voice_phrasing (i);
68   else if (h->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
69     add_lyric_phrasing (i);
70   else if (Lyric_extender::has_interface (h))
71     add_lyric_extender (i);
72   else if (h->internal_has_interface (ly_symbol2scm ("stanza-number-interface")))
73     add_stanza_number (i);
74 }
75
76 Phrasing_association *
77 Lyric_phrasing_engraver::get_phrasing_assoc (String nm)
78 {
79   Phrasing_association * a=0;
80   for (int i=0 ; !a && i < assocs_.size (); i++)
81     {
82       if (assocs_[i]->name_ == nm)
83         a = assocs_[i];
84     }
85
86   if (!a)
87     {
88       a = new Phrasing_association ;
89       a->name_ = nm;
90       assocs_.push (a);
91     }
92   return a;
93 }
94
95
96
97 String
98 Lyric_phrasing_engraver::get_voice_name_for_lyric (Context *tr)
99 {
100   SCM voice_context = tr->get_property ("associatedVoiceContext");
101   if (Context *vc = unsmob_context (voice_context))
102     {
103       return vc->id_string_;
104     }
105   
106   SCM voice = tr->get_property ("associatedVoice");
107   String nm = tr->id_string_;
108   if (gh_string_p (voice))
109     nm = ly_scm2string (voice);
110   else
111     {
112       int idx = nm.index_last ('-');
113       if (idx >= 0)
114         nm = nm.left_string (idx);
115     }
116
117   return nm;
118 }
119
120
121 void
122 Lyric_phrasing_engraver::add_lyric_extender (Grob_info inf)
123 {
124   Context * tr = inf.origin_trans_->daddy_context_;
125   while (tr && !tr->is_alias (ly_symbol2scm ("Lyrics")))
126     tr = tr->daddy_context_;
127
128   if (!tr)
129     return;
130
131   
132   Phrasing_association *a =  get_phrasing_assoc (get_voice_name_for_lyric (tr));
133   a->new_extenders_.push (dynamic_cast<Spanner*> (inf.grob_));  
134 }
135
136 void
137 Lyric_phrasing_engraver::add_stanza_number  (Grob_info inf)
138 {
139   Context * tr = inf.origin_trans_->daddy_context_;
140   while (tr && !tr->is_alias (ly_symbol2scm ("Lyrics")))
141     tr = tr->daddy_context_;
142
143   if (!tr)
144     return;
145
146   Phrasing_association *a =  get_phrasing_assoc (get_voice_name_for_lyric (tr));
147   a->stanza_numbers_.push (inf.grob_);
148 }
149
150 void
151 Lyric_phrasing_engraver::add_voice_phrasing (Grob_info inf)
152 {
153   Context * tr = inf.origin_trans_->daddy_context_;
154   while (tr && !tr->is_alias (ly_symbol2scm ("Voice")))
155     tr = tr->daddy_context_;
156
157   if (!tr)
158     return;
159
160   Phrasing_association *a =  get_phrasing_assoc (tr->id_string_);
161   a->heads_.push (inf.grob_);
162   a->melisma_ = melisma_busy (inf.origin_trans_);
163 }
164
165 void
166 Lyric_phrasing_engraver::add_lyric_phrasing (Grob_info inf)
167 {
168   Context * tr = inf.origin_trans_->daddy_context_;
169   while (tr && !tr->is_alias (ly_symbol2scm ("Lyrics")))
170     tr = tr->daddy_context_;
171
172   if (!tr)
173     return;
174
175
176   Phrasing_association *a =  get_phrasing_assoc (get_voice_name_for_lyric (tr));
177   a->lyrics_.push (inf.grob_);
178   a->past_extenders_.clear ();
179 }
180
181 void
182 Lyric_phrasing_engraver::stop_translation_timestep ()
183 {
184   Link_array<Grob> stzs;
185   Link_array<Grob> lyrs;
186   for (int i = assocs_.size ();  i--; )
187     {
188       Phrasing_association * a = assocs_[i];
189       stzs.concat (a->stanza_numbers_);
190       lyrs.concat (a->lyrics_);
191     }
192
193   for(int i= lyrs.size(); i--;)
194     for (int j = stzs.size (); j--;)
195       Side_position_interface::add_support (stzs[j], lyrs[i]);
196     
197   for (int i = assocs_.size ();  i--; )
198     {
199       Phrasing_association * a = assocs_[i];
200
201       a->stanza_numbers_.clear ();
202       a->heads_.clear ();
203       a->lyrics_.clear ();
204       a->past_extenders_.concat (assocs_[i]->new_extenders_) ;
205       a->new_extenders_.clear ();
206     }
207 }
208
209 void
210 Lyric_phrasing_engraver::process_acknowledged_grobs ()
211 {
212   for (int i = 0; i < assocs_.size ();  i++)
213     {
214       Phrasing_association * a = assocs_[i];
215       if (! (a->heads_.size()  && (a->lyrics_.size () || a->past_extenders_.size ())))
216         continue;
217
218       Grob *h = a->heads_[0];   
219       Direction alignment = CENTER;
220       if (a->melisma_)
221         alignment = LEFT;
222       
223       for (int j = 0; j < a->lyrics_.size (); j++)
224         {
225           Grob *l = a->lyrics_[j];
226           if (!l->get_parent (X_AXIS))
227             {
228               l->set_parent (h, X_AXIS);
229               if (alignment)
230                 l->set_property ("self-alignment-X", gh_int2scm (alignment));
231             }
232         }
233
234       for (int j = a->past_extenders_.size(); j--;)
235         Pointer_group_interface::add_grob (a->past_extenders_[j],ly_symbol2scm ("heads"), h);
236     }
237 }
238
239 Lyric_phrasing_engraver::~Lyric_phrasing_engraver ()
240 {
241   for (int i =assocs_.size(); i--;)
242     delete assocs_[i];
243 }
244
245 ENTER_DESCRIPTION(Lyric_phrasing_engraver,
246                   "This engraver combines note heads and lyrics for alignment. ",
247                   "",
248                   "",
249                   "stanza-number-interface lyric-syllable-interface "
250                   "note-head-interface lyric-extender-interface",
251                   "associatedVoice",
252                   "");
253