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