]> git.donarmstrong.com Git - lilypond.git/blob - lily/ligature-engraver.cc
* input/trip.ly (fugaIILeft): add arpeggio
[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 (m->is_mus_type ("abort-event"))
48     {
49       reqs_drul_[START] = 0;
50       reqs_drul_[STOP] = 0;
51       if (ligature_)
52         ligature_->suicide ();
53       ligature_ = 0;
54     }
55   else if (m->is_mus_type ("ligature-event"))
56     {
57       Direction d = to_dir (m->get_mus_property ("span-direction"));
58       reqs_drul_[d] = m;
59       return true;
60     }
61   return false;
62 }
63
64 Spanner *
65 Ligature_engraver::create_ligature_spanner ()
66 {
67   return new Spanner (SCM_EOL);
68 }
69
70 void
71 Ligature_engraver::process_music ()
72 {
73   if (reqs_drul_[STOP])
74     {
75       if (!ligature_)
76         reqs_drul_[STOP]->origin ()->warning (_ ("can't find start of ligature"));
77       else
78         {
79           if (!last_bound)
80             {
81               reqs_drul_[STOP]->origin ()->warning (_ ("no right bound"));
82             }
83           else
84             {
85               ligature_->set_bound (RIGHT, last_bound);
86             }
87         }
88       prev_start_req_ = 0;
89       finished_ligature_ = ligature_;
90       ligature_ = 0;
91     }
92   last_bound = unsmob_grob (get_property ("currentMusicalColumn"));
93
94   if (ligature_)
95     {
96       // TODO: maybe forbid breaks only if not transcribing
97       top_engraver ()->forbid_breaks ();
98     }
99   if (reqs_drul_[START])
100     {
101       if (ligature_)
102         {
103           reqs_drul_[START]->origin ()->warning (_ ("already have a ligature"));
104           return;
105         }
106
107       prev_start_req_ = reqs_drul_[START];
108       ligature_ = create_ligature_spanner ();
109       brew_ligature_primitive_proc =
110         ligature_->get_grob_property ("ligature-primitive-callback");
111       if (brew_ligature_primitive_proc == SCM_EOL)
112         {
113           warning ("Ligature_engraver: ligature-primitive-callback undefined");
114         }
115
116       Grob *bound = unsmob_grob (get_property ("currentMusicalColumn"));
117       if (!bound)
118         {
119           reqs_drul_[START]->origin ()->warning (_ ("no left bound"));
120         }
121       else
122         {
123           ligature_->set_bound (LEFT, bound);
124         }
125
126       ligature_start_mom_ = now_mom ();
127       
128       announce_grob(ligature_, reqs_drul_[START]->self_scm());
129     }
130 }
131
132 void
133 Ligature_engraver::start_translation_timestep ()
134 {
135   reqs_drul_[START] = 0;
136   reqs_drul_[STOP] = 0;
137 }
138
139 void
140 Ligature_engraver::try_stop_ligature ()
141 {
142   if (finished_ligature_)
143     {
144       typeset_grob (finished_ligature_);
145       finished_ligature_ = 0;
146     }
147 }
148
149 void
150 Ligature_engraver::stop_translation_timestep ()
151 {
152   try_stop_ligature ();
153 }
154
155 void
156 Ligature_engraver::finalize ()
157 {
158   try_stop_ligature ();
159   if (ligature_)
160     {
161       prev_start_req_->origin ()->warning (_ ("unterminated ligature"));
162       ligature_->suicide ();
163     }
164 }
165
166 void
167 Ligature_engraver::acknowledge_grob (Grob_info info)
168 {
169   if (ligature_)
170     {
171       if (Ligature_head::has_interface (info.grob_))
172         {
173           info.grob_->set_grob_property ("ligature-primitive-callback",
174                                            brew_ligature_primitive_proc);
175         }
176       else if (Rest::has_interface (info.grob_))
177         {
178           info.music_cause ()->origin ()->warning (_ ("ligature may not contain rest; ignoring rest"));
179           prev_start_req_->origin ()->warning (_ ("ligature was started here"));
180           // TODO: maybe better should stop ligature here rather than
181           // ignoring the rest?
182         }
183     }
184 }
185
186 ENTER_DESCRIPTION (Ligature_engraver,
187 /* descr */       "Abstract class; a concrete subclass handles Ligature_requests by engraving Ligatures in a concrete style.",
188 /* creats*/       "Ligature",
189 /* accepts */     "ligature-event abort-event",
190 /* acks  */      "ligature-head-interface rest-interface",
191 /* reads */       "",
192 /* write */       "");