]> git.donarmstrong.com Git - lilypond.git/blob - lily/lyric-engraver.cc
use SCM_ASSERT_TYPE for graphing functions.
[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         }
73     }
74 }
75
76 Context *
77 get_voice_to_lyrics (Context *lyrics)
78 {
79   SCM avc = lyrics->get_property ("associatedVoiceContext");
80   if (Context *c = unsmob_context (avc))
81     return c;
82
83   SCM voice_name = lyrics->get_property ("associatedVoice");
84   string nm = lyrics->id_string ();
85
86   if (scm_is_string (voice_name))
87     nm = ly_scm2string (voice_name);
88   else
89     {
90       ssize idx = nm.rfind ('-');
91       if (idx != NPOS)
92         nm = nm.substr (0, idx);
93     }
94
95   Context *parent = lyrics;
96   Context *voice = 0;
97   while (parent && !voice)
98     {
99       voice = find_context_below (parent, ly_symbol2scm ("Voice"), nm);
100       parent = parent->get_parent_context ();
101     }
102
103   if (voice)
104     return voice;
105
106   parent = lyrics;
107   voice = 0;
108   while (parent && !voice)
109     {
110       voice = find_context_below (parent, ly_symbol2scm ("Voice"), "");
111       parent = parent->get_parent_context ();
112     }
113
114   return voice;
115 }
116
117 Grob *
118 get_current_note_head (Context *voice)
119 {
120   for (SCM s = voice->get_property ("busyGrobs");
121        scm_is_pair (s); s = scm_cdr (s))
122     {
123       Item *g = dynamic_cast<Item *> (unsmob_grob (scm_cdar (s)));
124
125       if (g && !g->get_column ()
126           && Note_head::has_interface (g))
127         return g;
128     }
129
130   return 0;
131 }
132
133 void
134 Lyric_engraver::stop_translation_timestep ()
135 {
136   if (text_)
137     {
138       Context *voice = get_voice_to_lyrics (context ());
139
140       if (voice)
141         {
142           Grob *head = get_current_note_head (voice);
143
144           if (head)
145             {
146               text_->set_parent (head, X_AXIS);
147               if (melisma_busy (voice))
148                 text_->set_property ("self-alignment-X", scm_from_int (LEFT));
149             }
150         }
151
152       last_text_ = text_;
153       text_ = 0;
154     }
155   event_ = 0;
156 }
157
158 ADD_TRANSLATOR (Lyric_engraver,
159                 /* doc */ "",
160                 /* create */ "LyricText",
161                 /* read */ "",
162                 /* write */ "");