]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-engraver.cc
e11f4ec222156d18672805fa1338aabbf36d97c6
[lilypond.git] / lily / lyric-engraver.cc
1 /*
2   lyric-engraver.cc -- implement Lyric_engraver
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7   Jan Nieuwenhuizen <janneke@gnu.org>
8 */
9
10 #include "context.hh"
11 #include "engraver.hh"
12 #include "font-metric.hh"
13 #include "item.hh"
14 #include "multi-measure-rest.hh"
15 #include "note-head.hh"
16 #include "rest.hh"
17 #include "stream-event.hh"
18
19 #include "translator.icc"
20
21 /**
22    Generate texts for lyric syllables.  We only do one lyric at a time.
23    Multiple copies of this engraver should be used to do multiple voices.
24 */
25 class Lyric_engraver : public Engraver
26 {
27 protected:
28   void stop_translation_timestep ();
29   void process_music ();
30   DECLARE_TRANSLATOR_LISTENER (lyric);
31
32 public:
33   TRANSLATOR_DECLARATIONS (Lyric_engraver);
34
35 private:
36   Stream_event *event_;
37   Item *text_;
38   Item *last_text_;
39
40   Context *get_voice_context ();
41 };
42
43 Lyric_engraver::Lyric_engraver ()
44 {
45   text_ = 0;
46   last_text_ = 0;
47   event_ = 0;
48 }
49
50 IMPLEMENT_TRANSLATOR_LISTENER (Lyric_engraver, lyric);
51 void
52 Lyric_engraver::listen_lyric (Stream_event *ev)
53 {
54   ASSIGN_EVENT_ONCE (event_, ev);
55 }
56
57 void
58 Lyric_engraver::process_music ()
59 {
60   if (event_)
61     {
62       SCM text = event_->get_property ("text");
63
64       if (ly_is_equal (text, scm_makfrom0str (" ")))
65         {
66           if (last_text_)
67             last_text_->set_property ("self-alignment-X", scm_from_int (LEFT));
68         }
69       else
70         {
71           text_ = make_item ("LyricText", event_->self_scm ());
72           text_->set_property ("text", text);
73         }
74     }
75 }
76
77 Context *
78 get_voice_to_lyrics (Context *lyrics)
79 {
80   SCM avc = lyrics->get_property ("associatedVoiceContext");
81   if (Context *c = unsmob_context (avc))
82     return c;
83
84   SCM voice_name = lyrics->get_property ("associatedVoice");
85   string nm = lyrics->id_string ();
86
87   if (scm_is_string (voice_name))
88     nm = ly_scm2string (voice_name);
89   else
90     {
91       ssize idx = nm.rfind ('-');
92       if (idx != NPOS)
93         nm = nm.substr (0, idx);
94     }
95
96   Context *parent = lyrics;
97   Context *voice = 0;
98   while (parent && !voice)
99     {
100       voice = find_context_below (parent, ly_symbol2scm ("Voice"), nm);
101       parent = parent->get_parent_context ();
102     }
103
104   if (voice)
105     return voice;
106
107   parent = lyrics;
108   voice = 0;
109   while (parent && !voice)
110     {
111       voice = find_context_below (parent, ly_symbol2scm ("Voice"), "");
112       parent = parent->get_parent_context ();
113     }
114
115   return voice;
116 }
117
118 Grob *
119 get_current_note_head (Context *voice)
120 {
121   for (SCM s = voice->get_property ("busyGrobs");
122        scm_is_pair (s); s = scm_cdr (s))
123     {
124       Item *g = dynamic_cast<Item *> (unsmob_grob (scm_cdar (s)));
125
126       if (g && !g->get_column ()
127           && Note_head::has_interface (g))
128         return g;
129     }
130
131   return 0;
132 }
133
134 void
135 Lyric_engraver::stop_translation_timestep ()
136 {
137   if (text_)
138     {
139       Context *voice = get_voice_to_lyrics (context ());
140
141       if (voice)
142         {
143           Grob *head = get_current_note_head (voice);
144
145           if (head)
146             {
147               text_->set_parent (head, X_AXIS);
148               if (melisma_busy (voice))
149                 text_->set_property ("self-alignment-X", scm_from_int (LEFT));
150             }
151         }
152
153       last_text_ = text_;
154       text_ = 0;
155     }
156   event_ = 0;
157 }
158
159 ADD_TRANSLATOR (Lyric_engraver,
160                 /* doc */ "",
161                 /* create */ "LyricText",
162                 /* accept */ "lyric-event",
163                 /* read */ "",
164                 /* write */ "");