]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-engraver.cc
Fix some bugs in the dynamic engraver and PostScript backend
[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
18 /**
19    Generate texts for lyric syllables.  We only do one lyric at a time.
20    Multiple copies of this engraver should be used to do multiple voices.
21 */
22 class Lyric_engraver : public Engraver
23 {
24 protected:
25   void stop_translation_timestep ();
26   virtual bool try_music (Music *);
27   void process_music ();
28
29 public:
30   TRANSLATOR_DECLARATIONS (Lyric_engraver);
31
32 private:
33   Music *event_;
34   Item *text_;
35   Item *last_text_;
36
37   Context *get_voice_context ();
38 };
39
40 Lyric_engraver::Lyric_engraver ()
41 {
42   text_ = 0;
43   last_text_ = 0;
44   event_ = 0;
45 }
46
47 bool
48 Lyric_engraver::try_music (Music *r)
49 {
50   if (!event_)
51     {
52       event_ = r;
53       return true;
54     }
55   return false;
56 }
57
58 void
59 Lyric_engraver::process_music ()
60 {
61   if (event_)
62     {
63       SCM text = event_->get_property ("text");
64
65       if (ly_is_equal (text, scm_makfrom0str (" ")))
66         {
67           if (last_text_)
68             last_text_->set_property ("self-alignment-X", scm_from_int (LEFT));
69         }
70       else
71         {
72           text_ = make_item ("LyricText", event_->self_scm ());
73           text_->set_property ("text", text);
74         }
75     }
76 }
77
78 Context *
79 get_voice_to_lyrics (Context *lyrics)
80 {
81   SCM avc = lyrics->get_property ("associatedVoiceContext");
82   if (Context *c = unsmob_context (avc))
83     return c;
84
85   SCM voice_name = lyrics->get_property ("associatedVoice");
86   string nm = lyrics->id_string ();
87
88   if (scm_is_string (voice_name))
89     nm = ly_scm2string (voice_name);
90   else
91     {
92       ssize idx = nm.rfind ('-');
93       if (idx != NPOS)
94         nm = nm.substr (0, idx);
95     }
96
97   Context *parent = lyrics;
98   Context *voice = 0;
99   while (parent && !voice)
100     {
101       voice = find_context_below (parent, ly_symbol2scm ("Voice"), nm);
102       parent = parent->get_parent_context ();
103     }
104
105   if (voice)
106     return voice;
107
108   parent = lyrics;
109   voice = 0;
110   while (parent && !voice)
111     {
112       voice = find_context_below (parent, ly_symbol2scm ("Voice"), "");
113       parent = parent->get_parent_context ();
114     }
115
116   return voice;
117 }
118
119 Grob *
120 get_current_note_head (Context *voice)
121 {
122   for (SCM s = voice->get_property ("busyGrobs");
123        scm_is_pair (s); s = scm_cdr (s))
124     {
125       Item *g = dynamic_cast<Item *> (unsmob_grob (scm_cdar (s)));
126
127       if (g && !g->get_column ()
128           && Note_head::has_interface (g))
129         return g;
130     }
131
132   return 0;
133 }
134
135 void
136 Lyric_engraver::stop_translation_timestep ()
137 {
138   if (text_)
139     {
140       Context *voice = get_voice_to_lyrics (context ());
141
142       if (voice)
143         {
144           Grob *head = get_current_note_head (voice);
145
146           if (head)
147             {
148               text_->set_parent (head, X_AXIS);
149               if (melisma_busy (voice))
150                 text_->set_property ("self-alignment-X", scm_from_int (LEFT));
151             }
152         }
153
154       last_text_ = text_;
155       text_ = 0;
156     }
157   event_ = 0;
158 }
159
160 #include "translator.icc"
161
162 ADD_TRANSLATOR (Lyric_engraver,
163                 /* doc */ "",
164                 /* create */ "LyricText",
165                 /* accept */ "lyric-event",
166                 /* read */ "",
167                 /* write */ "");