1 /*
2 This file is part of LilyPond, the GNU music typesetter.
3
4 Copyright (C) 2001--2021 Han-Wen Nienhuys <hanwen@xs4all.nl>
5 Erik Sandberg <mandolaerik@gmail.com>
6
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.
11
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.
16
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/>.
19 */
20
21 #include "callback.hh"
22 #include "context.hh"
23 #include "input.hh"
24 #include "music.hh"
25 #include "sequential-iterator.hh"
26 #include "lily-imports.hh"
27
28 class Percent_repeat_iterator final : public Sequential_iterator
29 {
30 public:
31 OVERRIDE_CLASS_NAME (Percent_repeat_iterator);
32 DECLARE_SCHEME_CALLBACK (constructor, ());
33 Percent_repeat_iterator () = default;
34
35 protected:
36 void create_contexts () override;
37 void derived_mark () const override;
38 void next_element () override;
39
40 private:
41 int done_count_ = 0;
42 int rep_count_ = 0;
43 int starting_bar_ = -1;
44 Moment body_length_;
45 SCM event_type_ = SCM_UNDEFINED;
46 SCM slash_count_ = SCM_UNDEFINED;
47 };
48
49 IMPLEMENT_CTOR_CALLBACK (Percent_repeat_iterator);
50
51 void
derived_mark() const52 Percent_repeat_iterator::derived_mark () const
53 {
54 scm_gc_mark (event_type_);
55 scm_gc_mark (slash_count_);
56 Sequential_iterator::derived_mark ();
57 }
58
59 void
create_contexts()60 Percent_repeat_iterator::create_contexts ()
61 {
62 auto *mus = get_music ();
63 if (auto *body = unsmob<Music> (get_property (mus, "element")))
64 body_length_ = body->get_length ();
65 rep_count_ = from_scm<int> (get_property (mus, "repeat-count"));
66
67 Sequential_iterator::create_contexts ();
68
69 descend_to_bottom_context ();
70 if (!measure_position (get_context ()).main_part_)
71 starting_bar_
72 = from_scm (get_property (get_context (), "internalBarNumber"), 0);
73 }
74
75 // Arrive here for the first time after the original percent expression is
76 // completed, and then after each placeholder element. At this point of time,
77 // we can determine what kind of percent expression we are dealing with and
78 // provide the respective music expressions for the remaining repeats.
79 void
next_element()80 Percent_repeat_iterator::next_element ()
81 {
82 Sequential_iterator::next_element ();
83
84 ++done_count_;
85 if (done_count_ < rep_count_)
86 {
87 Music *mus = get_music ();
88 if (done_count_ == 1)
89 {
90 int current_bar = -1;
91 if (!measure_position (get_context ()).main_part_)
92 {
93 current_bar = from_scm (get_property (get_context (),
94 "internalBarNumber"), 0);
95 }
96
97 if (starting_bar_ >= 0 && current_bar == starting_bar_ + 1)
98 event_type_ = ly_symbol2scm ("PercentEvent");
99 else if (starting_bar_ >= 0 && current_bar == starting_bar_ + 2)
100 event_type_ = ly_symbol2scm ("DoublePercentEvent");
101 else
102 {
103 if (auto *body = unsmob<Music> (get_property (mus, "element")))
104 {
105 slash_count_
106 = Lily::calc_repeat_slash_count (body->self_scm ());
107 }
108 event_type_ = ly_symbol2scm ("RepeatSlashEvent");
109 }
110 }
111
112 Music *percent = make_music_by_name (event_type_);
113 percent->set_spot (*mus->origin ());
114 set_property (percent, "length", body_length_.smobbed_copy ());
115 set_property (percent, "repeat-count", to_scm (done_count_ + 1));
116 if (!SCM_UNBNDP (slash_count_))
117 set_property (percent, "slash-count", slash_count_);
118 report_event (percent);
119 percent->unprotect ();
120 }
121 }
122