]> git.donarmstrong.com Git - lilypond.git/blob - lily/ligature-engraver.cc
* lily/mensural-ligature-engraver.cc:
[lilypond.git] / lily / ligature-engraver.cc
1 /*   
2   ligature-engraver.cc -- implement Ligature_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2002 Juergen Reuter <reuter@ipd.uka.de>
7   
8  */
9 #include "ligature-engraver.hh"
10 #include "ligature-head.hh"
11 #include "spanner.hh"
12 #include "score-engraver.hh"
13 #include "rest.hh"
14 #include "warn.hh"
15
16 /*
17  * TODO: lyrics/melisma/syllables: there should be at most one
18  * syllable of lyrics per ligature (i.e. for the lyrics context, a
19  * ligature should count as a single note, regardless of how many
20  * heads the ligature consists of).
21  *
22  * TODO: currently, you have to add/remove the proper
23  * Ligature_engraver (Ligature_bracket_engraver,
24  * Mensural_ligature_engraver) to the proper translator
25  * (e.g. VoiceContext) to choose between various representations.
26  * Since adding/removing an engraver to a translator is a global
27  * action in the paper block, you can not mix various representations
28  * _within_ the same score.  Hence, for selecting a representation,
29  * one would rather like to have a property that can be set e.g. for
30  * several staves individually.  However, it seems that this approach
31  * would require to have a single, complicated Ligature_engraver that
32  * consists of all the code...  This needs further thoughts.
33  */
34 Ligature_engraver::Ligature_engraver ()
35 {
36   ligature_ = 0;
37   finished_ligature_ = 0;
38   reqs_drul_[LEFT] = reqs_drul_[RIGHT] = 0;
39   prev_start_req_ = 0;
40   last_bound = 0;
41   brew_ligature_primitive_proc = SCM_EOL;
42 }
43
44 bool
45 Ligature_engraver::try_music (Music *m)
46 {
47   if (Span_req *req_ = dynamic_cast<Span_req*> (m))
48     {
49       if (scm_equal_p (req_->get_mus_property ("span-type"),
50                        scm_makfrom0str ("abort")) == SCM_BOOL_T)
51         {
52           reqs_drul_[START] = 0;
53           reqs_drul_[STOP] = 0;
54           if (ligature_)
55             ligature_->suicide ();
56           ligature_ = 0;
57         }
58       else if (scm_equal_p (req_->get_mus_property ("span-type"),
59                             scm_makfrom0str ("ligature")) == SCM_BOOL_T)
60         {
61           Direction d = req_->get_span_dir ();
62           reqs_drul_[d] = req_;
63           return true;
64         }
65     }
66   return false;
67 }
68
69 Spanner *
70 Ligature_engraver::create_ligature_spanner ()
71 {
72   return new Spanner (SCM_EOL);
73 }
74
75 void
76 Ligature_engraver::process_music ()
77 {
78   if (reqs_drul_[STOP])
79     {
80       if (!ligature_)
81         reqs_drul_[STOP]->origin ()->warning (_ ("can't find start of ligature"));
82       else
83         {
84           if (!last_bound)
85             {
86               reqs_drul_[STOP]->origin ()->warning (_ ("no right bound"));
87             }
88           else
89             {
90               ligature_->set_bound (RIGHT, last_bound);
91             }
92         }
93       prev_start_req_ = 0;
94       finished_ligature_ = ligature_;
95       ligature_ = 0;
96     }
97   last_bound = unsmob_grob (get_property ("currentMusicalColumn"));
98
99   if (ligature_)
100     {
101       // TODO: maybe forbid breaks only if not transcribing
102       top_engraver ()->forbid_breaks ();
103     }
104   if (reqs_drul_[START])
105     {
106       if (ligature_)
107         {
108           reqs_drul_[START]->origin ()->warning (_ ("already have a ligature"));
109           return;
110         }
111
112       prev_start_req_ = reqs_drul_[START];
113       ligature_ = create_ligature_spanner ();
114       brew_ligature_primitive_proc =
115         ligature_->get_grob_property ("ligature-primitive-callback");
116       if (brew_ligature_primitive_proc == SCM_EOL)
117         {
118           warning ("Ligature_engraver: ligature-primitive-callback undefined");
119         }
120
121       Grob *bound = unsmob_grob (get_property ("currentMusicalColumn"));
122       if (!bound)
123         {
124           reqs_drul_[START]->origin ()->warning (_ ("no left bound"));
125         }
126       else
127         {
128           ligature_->set_bound (LEFT, bound);
129         }
130
131       ligature_start_mom_ = now_mom ();
132       
133       announce_grob(ligature_, reqs_drul_[START]->self_scm());
134     }
135 }
136
137 void
138 Ligature_engraver::start_translation_timestep ()
139 {
140   reqs_drul_[START] = 0;
141   reqs_drul_[STOP] = 0;
142 }
143
144 void
145 Ligature_engraver::try_stop_ligature ()
146 {
147   if (finished_ligature_)
148     {
149       typeset_grob (finished_ligature_);
150       finished_ligature_ = 0;
151     }
152 }
153
154 void
155 Ligature_engraver::stop_translation_timestep ()
156 {
157   try_stop_ligature ();
158 }
159
160 void
161 Ligature_engraver::finalize ()
162 {
163   try_stop_ligature ();
164   if (ligature_)
165     {
166       prev_start_req_->origin ()->warning (_ ("unterminated ligature"));
167       ligature_->suicide ();
168     }
169 }
170
171 void
172 Ligature_engraver::acknowledge_grob (Grob_info info)
173 {
174   if (ligature_)
175     {
176       if (Ligature_head::has_interface (info.grob_))
177         {
178           info.grob_->set_grob_property ("ligature-primitive-callback",
179                                            brew_ligature_primitive_proc);
180         }
181       else if (Rest::has_interface (info.grob_))
182         {
183           info.music_cause ()->origin ()->warning (_ ("ligature may not contain rest; ignoring rest"));
184           prev_start_req_->origin ()->warning (_ ("ligature was started here"));
185           // TODO: maybe better should stop ligature here rather than
186           // ignoring the rest?
187         }
188     }
189 }
190
191 ENTER_DESCRIPTION (Ligature_engraver,
192 /* descr */       "Abstract class; a concrete subclass handles Ligature_requests by engraving Ligatures in a concrete style.",
193 /* creats*/       "Ligature",
194 /* acks  */       "ligature-head-interface rest-interface",
195 /* reads */       "",
196 /* write */       "ligature-primitive-callback");