midi2ly: bump version in output to 2.7.38 (oldest supported).
[lilypond/patrick.git] / lily / dynamic-align-engraver.cc
blob8e82b834748720e8748140fe6badc4fe7b643511
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2008--2010 Han-Wen Nienhuys <hanwen@lilypond.org>
7 LilyPond is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 LilyPond is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
21 #include <set>
23 #include "engraver.hh"
25 #include "axis-group-interface.hh"
26 #include "directional-element-interface.hh"
27 #include "item.hh"
28 #include "side-position-interface.hh"
29 #include "spanner.hh"
30 #include "stream-event.hh"
32 #include "translator.icc"
34 class Dynamic_align_engraver : public Engraver
36 TRANSLATOR_DECLARATIONS (Dynamic_align_engraver);
37 DECLARE_TRANSLATOR_LISTENER (break_span);
38 DECLARE_ACKNOWLEDGER (note_column);
39 DECLARE_ACKNOWLEDGER (dynamic);
40 DECLARE_END_ACKNOWLEDGER (dynamic);
42 protected:
43 virtual void stop_translation_timestep ();
45 private:
46 void create_line_spanner (Stream_event *cause);
47 Spanner *line_;
48 vector<Spanner *> ended_;
49 vector<Spanner *> started_;
50 vector<Grob *> scripts_;
51 vector<Grob *> support_;
53 set<Spanner *> running_;
55 bool early_end_;
58 Dynamic_align_engraver::Dynamic_align_engraver ()
60 line_ = 0;
61 early_end_ = false;
64 ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
65 ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column);
66 ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
68 void
69 Dynamic_align_engraver::create_line_spanner (Stream_event *event)
71 if (!line_)
72 line_ = make_spanner ("DynamicLineSpanner",
73 event ? event->self_scm () : SCM_EOL);
76 void
77 Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info)
79 if (Spanner::has_interface (info.grob ()))
80 ended_.push_back (info.spanner ());
83 void
84 Dynamic_align_engraver::acknowledge_note_column (Grob_info info)
86 support_.push_back (info.grob ());
89 IMPLEMENT_TRANSLATOR_LISTENER (Dynamic_align_engraver, break_span);
90 void
91 Dynamic_align_engraver::listen_break_span (Stream_event *event)
93 if (event->in_event_class ("break-dynamic-span-event"))
94 early_end_ = true;
97 void
98 Dynamic_align_engraver::acknowledge_dynamic (Grob_info info)
100 Stream_event *cause = info.event_cause ();
101 create_line_spanner (cause);
102 if (Spanner::has_interface (info.grob ()))
104 started_.push_back (info.spanner ());
106 If we are using text spans instead of hairpins and the line
107 is hidden, end the alignment spanner early: this allows dynamics
108 to be spaced individually instead of being linked together.
110 if (info.grob ()->internal_has_interface (ly_symbol2scm ("dynamic-text-spanner-interface"))
111 && (info.grob ()->get_property ("style") == ly_symbol2scm ("none")))
112 early_end_ = true;
114 else if (info.item ())
115 scripts_.push_back (info.item ());
116 else
117 info.grob ()->programming_error ("unknown dynamic grob");
119 Axis_group_interface::add_element (line_, info.grob ());
121 if (cause)
123 if (Direction d = to_dir (cause->get_property ("direction")))
124 set_grob_direction (line_, d);
128 void
129 Dynamic_align_engraver::stop_translation_timestep ()
131 for (vsize i = 0; i < started_.size (); i++)
132 running_.insert (started_[i]);
133 for (vsize i = 0; i < ended_.size (); i++)
135 Spanner *sp = ended_[i];
137 set<Spanner *>::iterator it = running_.find (sp);
138 if (it != running_.end ())
139 running_.erase (it);
140 else
141 started_[i]->programming_error ("lost track of this dynamic spanner");
144 bool end = line_ && (running_.empty ()
145 || early_end_);
146 Direction d = LEFT;
149 if (line_
150 && ((d == LEFT && !line_->get_bound (LEFT))
151 || (end && d == RIGHT && !line_->get_bound (RIGHT))))
153 vector<Spanner *> const &spanners
154 = (d == LEFT) ? started_ : ended_;
156 Grob *bound = 0;
157 if (scripts_.size ())
158 bound = scripts_[0];
159 else if (spanners.size ())
160 bound = spanners[0]->get_bound (d);
161 else
163 bound = unsmob_grob (get_property ("currentMusicalColumn"));
164 if (!early_end_)
165 programming_error ("started DynamicLineSpanner but have no left bound");
168 line_->set_bound (d, bound);
171 while (flip (&d) != LEFT);
173 for (vsize i = 0; line_ && i < support_.size (); i++)
174 Side_position_interface::add_support (line_, support_[i]);
176 if (end)
178 line_ = 0;
179 early_end_ = false;
182 ended_.clear ();
183 started_.clear ();
184 scripts_.clear ();
185 support_.clear ();
188 ADD_TRANSLATOR (Dynamic_align_engraver,
189 /* doc */
190 "Align hairpins and dynamic texts on a horizontal line.",
192 /* create */
193 "DynamicLineSpanner ",
195 /* read */
196 "currentMusicalColumn ",
198 /* write */