]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-phrasing-engraver.cc
* mf/feta18.mf: design size is 18 not 22.5
[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_context = tr->get_property ("associatedVoiceContext");
95   if (Translator *vc = unsmob_translator (voice_context))
96     {
97       return dynamic_cast<Translator_group*> (vc)->id_string_;
98     }
99   
100   SCM voice = tr->get_property ("associatedVoice");
101   String nm = tr->id_string_;
102   if (gh_string_p (voice))
103     nm = ly_scm2string (voice);
104   else
105     {
106       int idx = nm.index_last ('-');
107       if (idx >= 0)
108         nm = nm.left_string (idx);
109     }
110
111   return nm;
112 }
113
114
115 void
116 Lyric_phrasing_engraver::add_lyric_extender (Grob_info inf)
117 {
118   Translator_group * tr = inf.origin_trans_->daddy_trans_;
119   while (tr && !tr->is_alias (ly_symbol2scm ("LyricsVoice")))
120     tr = tr->daddy_trans_;
121
122   if (!tr)
123     return;
124
125   
126   Phrasing_association *a =  get_phrasing_assoc (get_voice_name_for_lyric (tr));
127   a->new_extenders_.push (dynamic_cast<Spanner*> (inf.grob_));  
128 }
129
130
131 void
132 Lyric_phrasing_engraver::add_voice_phrasing (Grob_info inf)
133 {
134   Translator_group * tr = inf.origin_trans_->daddy_trans_;
135   while (tr && !tr->is_alias (ly_symbol2scm ("Voice")))
136     tr = tr->daddy_trans_;
137
138   if (!tr)
139     return;
140
141   Phrasing_association *a =  get_phrasing_assoc (tr->id_string_);
142   a->heads_.push (inf.grob_);
143   a->melisma_ = melisma_busy (inf.origin_trans_);
144 }
145
146 void
147 Lyric_phrasing_engraver::add_lyric_phrasing (Grob_info inf)
148 {
149   Translator_group * tr = inf.origin_trans_->daddy_trans_;
150   while (tr && !tr->is_alias (ly_symbol2scm ("LyricsVoice")))
151     tr = tr->daddy_trans_;
152
153   if (!tr)
154     return;
155
156
157   Phrasing_association *a =  get_phrasing_assoc (get_voice_name_for_lyric (tr));
158   a->lyrics_.push (inf.grob_);
159   a->past_extenders_.clear ();
160 }
161
162 void
163 Lyric_phrasing_engraver::stop_translation_timestep ()
164 {
165   for (int i = assocs_.size ();  i--; )
166     {
167       assocs_[i]->heads_.clear ();
168       assocs_[i]->lyrics_.clear ();
169       assocs_[i]->past_extenders_.concat (assocs_[i]->new_extenders_) ;
170       assocs_[i]->new_extenders_.clear ();
171     }
172 }
173
174 void
175 Lyric_phrasing_engraver::process_acknowledged_grobs ()
176 {
177   for (int i = 0; i < assocs_.size ();  i++)
178     {
179       Phrasing_association * a = assocs_[i];
180       if (! (a->heads_.size()  && (a->lyrics_.size () || a->past_extenders_.size ())))
181         continue;
182
183       Grob *h = a->heads_[0];   
184       Direction alignment = CENTER;
185       if (a->melisma_)
186         alignment = LEFT;
187       
188       for (int j = 0; j < a->lyrics_.size (); j++)
189         {
190           Grob *l = a->lyrics_[j];
191           if (!l->get_parent (X_AXIS))
192             {
193               l->set_parent (h, X_AXIS);
194               if (alignment)
195                 l->set_grob_property ("self-alignment-X", gh_int2scm (alignment));
196             }
197         }
198
199       for (int j = a->past_extenders_.size(); j--;)
200         Pointer_group_interface::add_grob (a->past_extenders_[j],ly_symbol2scm ("heads"), h);
201     }
202 }
203
204 Lyric_phrasing_engraver::~Lyric_phrasing_engraver ()
205 {
206   for (int i =assocs_.size(); i--;)
207     delete assocs_[i];
208 }
209
210 ENTER_DESCRIPTION(Lyric_phrasing_engraver,
211                   "This engraver combines note heads and lyrics for alignment. ",
212                   "",
213                   "",
214                   "lyric-syllable-interface note-head-interface lyric-extender-interface",
215                   "associatedVoice",
216                   "");
217