]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-engraver.cc
* scm/music-functions.scm (skip-to-last): new function. Show only
[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--2005 Han-Wen Nienhuys <hanwen@cs.uu.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   PRECOMPUTED_VIRTUAL void stop_translation_timestep ();
26   virtual bool try_music (Music *);
27   PRECOMPUTED_VIRTUAL 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   event_ = 0;
44 }
45
46 bool
47 Lyric_engraver::try_music (Music *r)
48 {
49   if (!event_)
50     {
51       event_ = r;
52       return true;
53     }
54   return false;
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_int2num (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       int idx = nm.index_last ('-');
92       if (idx >= 0)
93         nm = nm.left_string (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_int2num (LEFT));
150             }
151         }
152           
153       last_text_ = text_;
154       text_ = 0;
155     }
156   event_ = 0;
157 }
158
159 #include "translator.icc"
160
161 ADD_TRANSLATOR (Lyric_engraver,
162                 /* descr */ "",
163                 /* creats*/ "LyricText",
164                 /* accepts */ "lyric-event",
165                 /* acks  */ "",
166                 /* reads */ "",
167                 /* write */ "");