OLD | NEW |
1 /* | 1 /* |
2 This file is part of LilyPond, the GNU music typesetter. | 2 This file is part of LilyPond, the GNU music typesetter. |
3 | 3 |
4 Copyright (C) 1998--2015 Jan Nieuwenhuizen <janneke@gnu.org> | 4 Copyright (C) 1998--2015 Jan Nieuwenhuizen <janneke@gnu.org> |
5 Han-Wen Nienhuys <hanwen@xs4all.nl> | 5 Han-Wen Nienhuys <hanwen@xs4all.nl> |
6 | 6 |
7 LilyPond is free software: you can redistribute it and/or modify | 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 | 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 | 9 the Free Software Foundation, either version 3 of the License, or |
10 (at your option) any later version. | 10 (at your option) any later version. |
(...skipping 21 matching lines...) Expand all Loading... |
32 /** | 32 /** |
33 The name says it all: make multi measure rests | 33 The name says it all: make multi measure rests |
34 */ | 34 */ |
35 class Multi_measure_rest_engraver : public Engraver | 35 class Multi_measure_rest_engraver : public Engraver |
36 { | 36 { |
37 public: | 37 public: |
38 TRANSLATOR_DECLARATIONS (Multi_measure_rest_engraver); | 38 TRANSLATOR_DECLARATIONS (Multi_measure_rest_engraver); |
39 | 39 |
40 protected: | 40 protected: |
41 void process_music (); | 41 void process_music (); |
42 void stop_translation_timestep (); | |
43 void start_translation_timestep (); | 42 void start_translation_timestep (); |
44 virtual void finalize (); | |
45 DECLARE_TRANSLATOR_LISTENER (multi_measure_rest); | 43 DECLARE_TRANSLATOR_LISTENER (multi_measure_rest); |
46 DECLARE_TRANSLATOR_LISTENER (multi_measure_text); | 44 DECLARE_TRANSLATOR_LISTENER (multi_measure_text); |
| 45 DECLARE_TRANSLATOR_LISTENER (note); |
| 46 DECLARE_TRANSLATOR_LISTENER (rest); |
47 | 47 |
48 private: | 48 private: |
| 49 void add_bound_item_to_grobs (Item *); |
| 50 void clear_lapsed_events (const Moment &now); |
| 51 void disable_mmrest_during_event (Stream_event *); |
| 52 bool grobs_initialized () const { return mmrest_; } |
| 53 void initialize_grobs (); |
| 54 void reset_grobs (); |
| 55 void set_measure_count (int n); |
| 56 |
| 57 private: |
| 58 vector<Stream_event *> text_events_; |
| 59 // text_[0] is a MultiMeasureRestNumber grob |
| 60 // the rest are optional MultiMeasureRestText grobs |
| 61 vector<Spanner *> text_; |
49 Stream_event *rest_ev_; | 62 Stream_event *rest_ev_; |
50 vector<Stream_event *> text_events_; | 63 Spanner *mmrest_; |
| 64 // Don't create grobs before this moment, even if a multi-measure-rest event |
| 65 // calls for it. |
| 66 Moment enable_moment_; |
| 67 // Stop creating grobs at this moment. |
| 68 Moment stop_moment_; |
51 int start_measure_; | 69 int start_measure_; |
52 Rational last_main_moment_; | 70 // Ugh, this is a kludge - need this for multi-measure-rest-grace.ly |
53 Moment stop_moment_; | |
54 | |
55 bool bar_seen_; | |
56 Item *last_command_item_; | 71 Item *last_command_item_; |
57 Spanner *last_rest_; | 72 bool first_time_; |
58 Spanner *mmrest_; | 73 bool enabled_in_current_measure_; |
59 | |
60 vector<Spanner *> numbers_; | |
61 vector<Spanner *> last_numbers_; | |
62 }; | 74 }; |
63 | 75 |
64 Multi_measure_rest_engraver::Multi_measure_rest_engraver () | 76 Multi_measure_rest_engraver::Multi_measure_rest_engraver () |
| 77 : rest_ev_ (0), |
| 78 mmrest_ (0), |
| 79 start_measure_ (0), |
| 80 last_command_item_ (0), |
| 81 first_time_ (true), |
| 82 enabled_in_current_measure_ (false) |
65 { | 83 { |
66 last_command_item_ = 0; | 84 enable_moment_.set_infinite (-1); |
67 | |
68 /* | |
69 For the start of a score. | |
70 */ | |
71 bar_seen_ = true; | |
72 start_measure_ = 0; | |
73 mmrest_ = 0; | |
74 last_rest_ = 0; | |
75 rest_ev_ = 0; | |
76 } | 85 } |
77 | 86 |
78 IMPLEMENT_TRANSLATOR_LISTENER (Multi_measure_rest_engraver, multi_measure_rest); | 87 IMPLEMENT_TRANSLATOR_LISTENER (Multi_measure_rest_engraver, multi_measure_rest); |
79 void | 88 void |
80 Multi_measure_rest_engraver::listen_multi_measure_rest (Stream_event *ev) | 89 Multi_measure_rest_engraver::listen_multi_measure_rest (Stream_event *ev) |
81 { | 90 { |
82 /* FIXME: Should use ASSIGN_EVENT_ONCE. Can't do that yet because of | 91 /* FIXME: Should use ASSIGN_EVENT_ONCE. Can't do that yet because of |
83 the kill-mm-rests hack in part-combine-iterator. */ | 92 the kill-mm-rests hack in part-combine-iterator. */ |
84 rest_ev_ = ev; | 93 rest_ev_ = ev; |
85 stop_moment_ = now_mom () + get_event_length (rest_ev_, now_mom ()); | 94 const Moment now (now_mom ()); |
| 95 stop_moment_ = now + get_event_length (rest_ev_, now); |
86 /* | 96 /* |
87 if (ASSIGN_EVENT_ONCE (rest_ev_, ev)) | 97 if (ASSIGN_EVENT_ONCE (rest_ev_, ev)) |
88 stop_moment_ = now_mom () + get_event_length (rest_ev_); | 98 stop_moment_ = now_mom () + get_event_length (rest_ev_); |
89 */ | 99 */ |
| 100 |
| 101 clear_lapsed_events (now); |
90 } | 102 } |
91 | 103 |
92 IMPLEMENT_TRANSLATOR_LISTENER (Multi_measure_rest_engraver, multi_measure_text); | 104 IMPLEMENT_TRANSLATOR_LISTENER (Multi_measure_rest_engraver, multi_measure_text); |
93 void | 105 void |
94 Multi_measure_rest_engraver::listen_multi_measure_text (Stream_event *ev) | 106 Multi_measure_rest_engraver::listen_multi_measure_text (Stream_event *ev) |
95 { | 107 { |
96 text_events_.push_back (ev); | 108 text_events_.push_back (ev); |
97 } | 109 } |
98 | 110 |
| 111 IMPLEMENT_TRANSLATOR_LISTENER (Multi_measure_rest_engraver, note); |
| 112 void |
| 113 Multi_measure_rest_engraver::listen_note (Stream_event *ev) |
| 114 { |
| 115 disable_mmrest_during_event (ev); |
| 116 } |
| 117 |
| 118 IMPLEMENT_TRANSLATOR_LISTENER (Multi_measure_rest_engraver, rest); |
| 119 void |
| 120 Multi_measure_rest_engraver::listen_rest (Stream_event *ev) |
| 121 { |
| 122 disable_mmrest_during_event (ev); |
| 123 } |
| 124 |
| 125 void |
| 126 Multi_measure_rest_engraver::add_bound_item_to_grobs (Item *item) |
| 127 { |
| 128 add_bound_item (mmrest_, item); |
| 129 for (vsize i = 0; i < text_.size (); ++i) |
| 130 add_bound_item (text_[i], item); |
| 131 } |
| 132 |
| 133 void |
| 134 Multi_measure_rest_engraver::clear_lapsed_events (const Moment &now) |
| 135 { |
| 136 if (now.main_part_ >= stop_moment_.main_part_) |
| 137 { |
| 138 rest_ev_ = 0; |
| 139 text_events_.clear (); |
| 140 } |
| 141 } |
| 142 |
| 143 void |
| 144 Multi_measure_rest_engraver::disable_mmrest_during_event (Stream_event *ev) |
| 145 { |
| 146 const Moment now (now_mom ()); |
| 147 enable_moment_ = max (enable_moment_, now + get_event_length (ev, now)); |
| 148 } |
| 149 |
| 150 void |
| 151 Multi_measure_rest_engraver::initialize_grobs () |
| 152 { |
| 153 mmrest_ = make_spanner ("MultiMeasureRest", rest_ev_->self_scm ()); |
| 154 text_.push_back (make_spanner ("MultiMeasureRestNumber", |
| 155 rest_ev_->self_scm ())); |
| 156 |
| 157 if (text_events_.size ()) |
| 158 { |
| 159 for (vsize i = 0; i < text_events_.size (); i++) |
| 160 { |
| 161 Stream_event *e = text_events_[i]; |
| 162 Spanner *sp = make_spanner ("MultiMeasureRestText", e->self_scm ()); |
| 163 SCM t = e->get_property ("text"); |
| 164 SCM dir = e->get_property ("direction"); |
| 165 sp->set_property ("text", t); |
| 166 if (is_direction (dir)) |
| 167 sp->set_property ("direction", dir); |
| 168 |
| 169 text_.push_back (sp); |
| 170 } |
| 171 |
| 172 /* |
| 173 Stack different scripts. |
| 174 */ |
| 175 for (DOWN_and_UP (d)) |
| 176 { |
| 177 SCM dir = scm_from_int (d); |
| 178 Grob *last = 0; |
| 179 for (vsize i = 0; i < text_.size (); i++) |
| 180 { |
| 181 if (scm_is_eq (dir, text_[i]->get_property ("direction"))) |
| 182 { |
| 183 if (last) |
| 184 Side_position_interface::add_support (text_[i], last); |
| 185 last = text_[i]; |
| 186 } |
| 187 } |
| 188 } |
| 189 } |
| 190 |
| 191 for (vsize i = 0; i < text_.size (); i++) |
| 192 { |
| 193 Side_position_interface::add_support (text_[i], mmrest_); |
| 194 text_[i]->set_parent (mmrest_, Y_AXIS); |
| 195 text_[i]->set_parent (mmrest_, X_AXIS); |
| 196 } |
| 197 } |
| 198 |
| 199 void |
| 200 Multi_measure_rest_engraver::reset_grobs () |
| 201 { |
| 202 text_.clear (); |
| 203 mmrest_ = 0; |
| 204 } |
| 205 |
| 206 void |
| 207 Multi_measure_rest_engraver::set_measure_count (int n) |
| 208 { |
| 209 SCM n_scm = scm_from_int (n); |
| 210 assert (mmrest_); |
| 211 mmrest_->set_property ("measure-count", n_scm); |
| 212 |
| 213 Grob *g = text_[0]; // the MultiMeasureRestNumber |
| 214 assert (g); |
| 215 if (scm_is_null (g->get_property ("text"))) |
| 216 { |
| 217 SCM thres = get_property ("restNumberThreshold"); |
| 218 int t = 1; |
| 219 if (scm_is_number (thres)) |
| 220 t = scm_to_int (thres); |
| 221 |
| 222 if (n <= t) |
| 223 g->suicide (); |
| 224 else |
| 225 { |
| 226 SCM text = scm_number_to_string (n_scm, scm_from_int (10)); |
| 227 g->set_property ("text", text); |
| 228 } |
| 229 } |
| 230 } |
| 231 |
99 void | 232 void |
100 Multi_measure_rest_engraver::process_music () | 233 Multi_measure_rest_engraver::process_music () |
101 { | 234 { |
102 if (rest_ev_ && !mmrest_ | 235 const bool measure_end |
103 && stop_moment_ > now_mom ()) | 236 = scm_is_string (get_property ("whichBar")) |
| 237 && (robust_scm2moment (get_property ("measurePosition"), |
| 238 Moment (0)).main_part_ == Rational (0)); |
| 239 |
| 240 if (measure_end || first_time_) |
104 { | 241 { |
105 mmrest_ = make_spanner ("MultiMeasureRest", rest_ev_->self_scm ()); | 242 enabled_in_current_measure_ = (enable_moment_ <= now_mom ()); |
| 243 last_command_item_ = unsmob<Item> (get_property ("currentCommandColumn")); |
106 | 244 |
107 Spanner *sp | 245 // Finalize the current grobs. |
108 = make_spanner ("MultiMeasureRestNumber", rest_ev_->self_scm ()); | 246 if (grobs_initialized ()) |
109 numbers_.push_back (sp); | |
110 | |
111 if (text_events_.size ()) | |
112 { | 247 { |
113 for (vsize i = 0; i < text_events_.size (); i++) | 248 int curr_measure = scm_to_int (get_property ("internalBarNumber")); |
114 { | 249 set_measure_count (curr_measure - start_measure_); |
115 Stream_event *e = text_events_[i]; | 250 if (last_command_item_) |
116 Spanner *sp | 251 add_bound_item_to_grobs (last_command_item_); |
117 = make_spanner ("MultiMeasureRestText", e->self_scm ()); | 252 reset_grobs (); |
118 SCM t = e->get_property ("text"); | |
119 SCM dir = e->get_property ("direction"); | |
120 sp->set_property ("text", t); | |
121 if (is_direction (dir)) | |
122 sp->set_property ("direction", dir); | |
123 | |
124 numbers_.push_back (sp); | |
125 } | |
126 | |
127 /* | |
128 Stack different scripts. | |
129 */ | |
130 for (DOWN_and_UP (d)) | |
131 { | |
132 Grob *last = 0; | |
133 for (vsize i = 0; i < numbers_.size (); i++) | |
134 { | |
135 if (scm_is_eq (scm_from_int (d), | |
136 numbers_[i]->get_property ("direction"))) | |
137 { | |
138 if (last) | |
139 Side_position_interface::add_support (numbers_[i], last)
; | |
140 last = numbers_[i]; | |
141 } | |
142 } | |
143 } | |
144 } | |
145 | |
146 for (vsize i = 0; i < numbers_.size (); i++) | |
147 { | |
148 Side_position_interface::add_support (numbers_[i], mmrest_); | |
149 numbers_[i]->set_parent (mmrest_, Y_AXIS); | |
150 numbers_[i]->set_parent (mmrest_, X_AXIS); | |
151 } | |
152 | |
153 start_measure_ | |
154 = scm_to_int (get_property ("internalBarNumber")); | |
155 } | |
156 | |
157 bar_seen_ = bar_seen_ || scm_is_string (get_property ("whichBar")); | |
158 } | |
159 | |
160 void | |
161 Multi_measure_rest_engraver::stop_translation_timestep () | |
162 { | |
163 /* We cannot do this earlier, as breakableSeparationItem is not yet | |
164 there. | |
165 | |
166 Actually, we no longer use breakableSeparationItem -- should this be moved? | |
167 -- jneem */ | |
168 if (bar_seen_) | |
169 { | |
170 Grob *cmc = unsmob<Grob> (get_property ("currentCommandColumn")); | |
171 | |
172 /* Ugh, this is a kludge - need this for multi-measure-rest-grace.ly */ | |
173 last_command_item_ = dynamic_cast<Item *> (cmc); | |
174 } | |
175 | |
176 if (last_command_item_ && (mmrest_ || last_rest_)) | |
177 { | |
178 if (last_rest_) | |
179 { | |
180 add_bound_item (last_rest_, last_command_item_); | |
181 for (vsize i = 0; i < last_numbers_.size (); i++) | |
182 add_bound_item (last_numbers_[i], last_command_item_); | |
183 } | |
184 | |
185 if (mmrest_) | |
186 { | |
187 add_bound_item (mmrest_, last_command_item_); | |
188 for (vsize i = 0; i < numbers_.size (); i++) | |
189 add_bound_item (numbers_[i], last_command_item_); | |
190 | |
191 last_command_item_ = 0; | |
192 } | 253 } |
193 } | 254 } |
194 | 255 |
195 Moment mp (robust_scm2moment (get_property ("measurePosition"), Moment (0))); | 256 // Create new grobs if a rest event is (still) active. |
196 if (last_rest_) | 257 if (!grobs_initialized () && rest_ev_ && enabled_in_current_measure_) |
197 { | 258 { |
198 last_rest_ = 0; | 259 initialize_grobs (); |
199 last_numbers_.clear (); | 260 text_events_.clear (); |
| 261 |
| 262 if (last_command_item_) |
| 263 { |
| 264 add_bound_item_to_grobs (last_command_item_); |
| 265 last_command_item_ = 0; |
| 266 } |
| 267 |
| 268 start_measure_ = scm_to_int (get_property ("internalBarNumber")); |
200 } | 269 } |
201 | 270 |
202 text_events_.clear (); | 271 first_time_ = false; |
203 bar_seen_ = false; | |
204 } | 272 } |
205 | 273 |
206 void | 274 void |
207 Multi_measure_rest_engraver::start_translation_timestep () | 275 Multi_measure_rest_engraver::start_translation_timestep () |
208 { | 276 { |
209 if (now_mom ().main_part_ >= stop_moment_.main_part_) | 277 clear_lapsed_events (now_mom ()); |
210 rest_ev_ = 0; | |
211 | |
212 Moment mp (robust_scm2moment (get_property ("measurePosition"), Moment (0))); | |
213 | |
214 Moment now = now_mom (); | |
215 if (mmrest_ | |
216 && now.main_part_ != last_main_moment_ | |
217 && mp.main_part_ == Rational (0)) | |
218 { | |
219 last_rest_ = mmrest_; | |
220 last_numbers_ = numbers_; | |
221 | |
222 int cur = scm_to_int (get_property ("internalBarNumber")); | |
223 int num = cur - start_measure_; | |
224 | |
225 /* | |
226 We can't plug a markup directly into the grob, since the | |
227 measure-count determines the formatting of the mmrest. | |
228 */ | |
229 last_rest_->set_property ("measure-count", scm_from_int (num)); | |
230 | |
231 mmrest_ = 0; | |
232 numbers_.clear (); | |
233 | |
234 Grob *last = last_numbers_.size () ? last_numbers_[0] : 0; | |
235 if (last && scm_is_null (last->get_property ("text"))) | |
236 { | |
237 SCM thres = get_property ("restNumberThreshold"); | |
238 int t = 1; | |
239 if (scm_is_number (thres)) | |
240 t = scm_to_int (thres); | |
241 | |
242 if (num <= t) | |
243 last->suicide (); | |
244 else | |
245 { | |
246 SCM text | |
247 = scm_number_to_string (scm_from_int (num), scm_from_int (10)); | |
248 last->set_property ("text", text); | |
249 } | |
250 } | |
251 } | |
252 | |
253 last_main_moment_ = now.main_part_; | |
254 } | |
255 | |
256 void | |
257 Multi_measure_rest_engraver::finalize () | |
258 { | |
259 } | 278 } |
260 | 279 |
261 ADD_TRANSLATOR (Multi_measure_rest_engraver, | 280 ADD_TRANSLATOR (Multi_measure_rest_engraver, |
262 /* doc */ | 281 /* doc */ |
263 "Engrave multi-measure rests that are produced with" | 282 "Engrave multi-measure rests that are produced with" |
264 " @samp{R}. It reads @code{measurePosition} and" | 283 " @samp{R}. It reads @code{measurePosition} and" |
265 " @code{internalBarNumber} to determine what number to print" | 284 " @code{internalBarNumber} to determine what number to print" |
266 " over the @ref{MultiMeasureRest}.", | 285 " over the @ref{MultiMeasureRest}.", |
267 | 286 |
268 /* create */ | 287 /* create */ |
269 "MultiMeasureRest " | 288 "MultiMeasureRest " |
270 "MultiMeasureRestNumber " | 289 "MultiMeasureRestNumber " |
271 "MultiMeasureRestText ", | 290 "MultiMeasureRestText ", |
272 | 291 |
273 /* read */ | 292 /* read */ |
274 "internalBarNumber " | 293 "internalBarNumber " |
275 "restNumberThreshold " | 294 "restNumberThreshold " |
276 "currentCommandColumn " | 295 "currentCommandColumn " |
277 "measurePosition ", | 296 "measurePosition " |
| 297 "whichBar ", |
278 | 298 |
279 /* write */ | 299 /* write */ |
280 "" | 300 "" |
281 ); | 301 ); |
OLD | NEW |