]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-phrasing-engraver.cc
b7e5f75ff799bea576f36715b217001a01411dfe
[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 "translator-group.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
18 struct Phrasing_association
19 {
20   String name_;
21   Link_array<Grob> lyrics_;
22   Link_array<Grob> heads_;
23   Link_array<Spanner> past_extenders_;
24   Link_array<Spanner> new_extenders_;
25   
26   bool melisma_;
27   
28   Phrasing_association()
29   {
30     melisma_ = false;
31   }
32 };
33
34 class Lyric_phrasing_engraver : public Engraver
35 {
36 public:
37   ~Lyric_phrasing_engraver ();
38   TRANSLATOR_DECLARATIONS(Lyric_phrasing_engraver);
39 protected:
40   virtual void acknowledge_grob (Grob_info);
41   virtual void process_acknowledged_grobs ();
42   virtual void stop_translation_timestep ();
43
44 private:
45   void add_lyric_phrasing (Grob_info);
46   void add_voice_phrasing (Grob_info);
47   void add_lyric_extender (Grob_info);
48   Phrasing_association *get_phrasing_assoc (String nm);
49   String get_voice_name_for_lyric (Translator_group*tr);
50   Link_array<Phrasing_association> assocs_;
51 };
52
53 Lyric_phrasing_engraver::Lyric_phrasing_engraver()
54 {
55 }
56
57 void
58 Lyric_phrasing_engraver::acknowledge_grob (Grob_info i)
59 {
60   Grob *h = i.grob_;
61
62   if (Note_head::has_interface (h))
63     add_voice_phrasing (i);
64   else if (h->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
65     add_lyric_phrasing (i);
66   else if (Lyric_extender::has_interface (h))
67     add_lyric_extender (i);
68 }
69
70 Phrasing_association *
71 Lyric_phrasing_engraver::get_phrasing_assoc (String nm)
72 {
73   Phrasing_association * a=0;
74   for (int i=0 ; !a && i < assocs_.size (); i++)
75     {
76       if (assocs_[i]->name_ == nm)
77         a = assocs_[i];
78     }
79
80   if (!a)
81     {
82       a = new Phrasing_association ;
83       a->name_ = nm;
84       assocs_.push (a);
85     }
86   return a;
87 }
88
89
90
91 String
92 Lyric_phrasing_engraver::get_voice_name_for_lyric (Translator_group*tr)
93 {
94   SCM voice = tr->get_property ("associatedVoice");
95   String nm = tr->id_string_;
96   if (gh_string_p (voice))
97     nm = ly_scm2string (voice);
98   else
99     {
100       int idx = nm.index_last ('-');
101       if (idx >= 0)
102         nm = nm.left_string (idx);
103     }
104
105   return nm;
106 }
107
108
109 void
110 Lyric_phrasing_engraver::add_lyric_extender (Grob_info inf)
111 {
112   Translator_group * tr = inf.origin_trans_->daddy_trans_;
113   while (tr && !tr->is_alias (ly_symbol2scm ("LyricsVoice")))
114     tr = tr->daddy_trans_;
115
116   if (!tr)
117     return;
118
119   
120   Phrasing_association *a =  get_phrasing_assoc (get_voice_name_for_lyric (tr));
121   a->new_extenders_.push (dynamic_cast<Spanner*> (inf.grob_));  
122 }
123
124
125 void
126 Lyric_phrasing_engraver::add_voice_phrasing (Grob_info inf)
127 {
128   Translator_group * tr = inf.origin_trans_->daddy_trans_;
129   while (tr && !tr->is_alias (ly_symbol2scm ("Voice")))
130     tr = tr->daddy_trans_;
131
132   if (!tr)
133     return;
134
135   Phrasing_association *a =  get_phrasing_assoc (tr->id_string_);
136   a->heads_.push (inf.grob_);
137   a->melisma_ = melisma_busy (inf.origin_trans_);
138 }
139
140 void
141 Lyric_phrasing_engraver::add_lyric_phrasing (Grob_info inf)
142 {
143   Translator_group * tr = inf.origin_trans_->daddy_trans_;
144   while (tr && !tr->is_alias (ly_symbol2scm ("LyricsVoice")))
145     tr = tr->daddy_trans_;
146
147   if (!tr)
148     return;
149
150
151   Phrasing_association *a =  get_phrasing_assoc (get_voice_name_for_lyric (tr));
152   a->lyrics_.push (inf.grob_);
153   a->past_extenders_.clear ();
154 }
155
156 void
157 Lyric_phrasing_engraver::stop_translation_timestep ()
158 {
159   for (int i = assocs_.size ();  i--; )
160     {
161       assocs_[i]->heads_.clear ();
162       assocs_[i]->lyrics_.clear ();
163       assocs_[i]->past_extenders_.concat (assocs_[i]->new_extenders_) ;
164       assocs_[i]->new_extenders_.clear ();
165     }
166 }
167
168 void
169 Lyric_phrasing_engraver::process_acknowledged_grobs ()
170 {
171   for (int i = 0; i < assocs_.size ();  i++)
172     {
173       Phrasing_association * a = assocs_[i];
174       if (! (a->heads_.size()  && (a->lyrics_.size () || a->past_extenders_.size ())))
175         continue;
176
177       Grob *h = a->heads_[0];   
178       Direction alignment = CENTER;
179       if (a->melisma_)
180         alignment = LEFT;
181       
182       for (int j = 0; j < a->lyrics_.size (); j++)
183         {
184           Grob *l = a->lyrics_[j];
185           if (!l->get_parent (X_AXIS))
186             {
187               l->set_parent (h, X_AXIS);
188               if (alignment)
189                 l->set_grob_property ("self-alignment-X", gh_int2scm (alignment));
190             }
191         }
192
193       for (int j = a->past_extenders_.size(); j--;)
194         Pointer_group_interface::add_grob (a->past_extenders_[j],ly_symbol2scm ("heads"), h);
195     }
196 }
197
198 Lyric_phrasing_engraver::~Lyric_phrasing_engraver ()
199 {
200   for (int i =assocs_.size(); i--;)
201     delete assocs_[i];
202 }
203
204 ENTER_DESCRIPTION(Lyric_phrasing_engraver,
205                   "This engraver combines note heads and lyrics for alignment. ",
206                   "",
207                   "",
208                   "lyric-syllable-interface note-head-interface lyric-extender-interface",
209                   "associatedVoice",
210                   "");
211