]> git.donarmstrong.com Git - lilypond.git/blob - lily/tuplet-iterator.cc
Web-ja: update introduction
[lilypond.git] / lily / tuplet-iterator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2015 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 "context.hh"
22 #include "input.hh"
23 #include "international.hh"
24 #include "music.hh"
25 #include "music-wrapper-iterator.hh"
26 #include "stream-event.hh"
27 #include "lily-imports.hh"
28
29 /*
30   Iterates \times, by sending TupletSpanEvents at the start/end of each
31   tuplet bracket.  Extra stop/start events are sent at regular
32   intervals if tupletSpannerDuration is set.
33 */
34 class Tuplet_iterator : public Music_wrapper_iterator
35 {
36 public:
37   DECLARE_SCHEME_CALLBACK (constructor, ());
38   /* construction */
39   DECLARE_CLASSNAME (Tuplet_iterator);
40   Tuplet_iterator ();
41 protected:
42   virtual void process (Moment m);
43   virtual void construct_children ();
44   virtual void derived_mark () const;
45   virtual Moment pending_moment () const;
46
47   Music *create_event (Direction d);
48
49 private:
50
51   /* tupletSpannerDuration */
52   Moment spanner_duration_;
53
54   /* next time to add a stop/start pair */
55   Moment next_split_mom_;
56
57   /* Recycle start/stop events if tupletSpannerDuration is set. */
58   SCM synthesized_events_;
59
60   Context_handle tuplet_handler_;
61 };
62
63 Music *
64 Tuplet_iterator::create_event (Direction d)
65 {
66   SCM ev_scm = Lily::make_span_event (ly_symbol2scm ("TupletSpanEvent"),
67                                       scm_from_int (d));
68
69   Music *mus = get_music ();
70
71   Music *ev = unsmob<Music> (ev_scm);
72   ev->set_spot (*mus->origin ());
73   if (d == START)
74     {
75       ev->set_property ("numerator", mus->get_property ("numerator"));
76       ev->set_property ("denominator", mus->get_property ("denominator"));
77       ev->set_property ("tweaks", mus->get_property ("tweaks"));
78       ev->set_property ("length", spanner_duration_.smobbed_copy ());
79     }
80
81   synthesized_events_ = scm_cons (ev_scm, synthesized_events_);
82   return ev;
83 }
84
85 Tuplet_iterator::Tuplet_iterator ()
86 {
87   spanner_duration_ = next_split_mom_ = 0;
88   synthesized_events_ = SCM_EOL;
89 }
90
91 Moment
92 Tuplet_iterator::pending_moment () const
93 {
94   Moment next_mom = Music_wrapper_iterator::pending_moment ();
95   next_mom = min (next_mom, next_split_mom_);
96
97   return next_mom;
98 }
99
100 void
101 Tuplet_iterator::process (Moment m)
102 {
103   if (spanner_duration_.to_bool ()
104       && m.main_part_ == next_split_mom_)
105     {
106       descend_to_bottom_context ();
107       if (tuplet_handler_.get_context ())
108         create_event (STOP)->send_to_context (tuplet_handler_.get_context ());
109
110       if (m.main_part_ < music_get_length ().main_part_)
111         {
112           spanner_duration_ =
113             min (music_get_length () - next_split_mom_, spanner_duration_);
114           tuplet_handler_.set_context (get_outlet ());
115           report_event (create_event (START));
116
117           next_split_mom_ += spanner_duration_;
118         }
119       else
120         tuplet_handler_.set_context (0);
121     }
122   Music_wrapper_iterator::process (m);
123   if (child_iter_ && child_iter_->ok ())
124     descend_to_child (child_iter_->get_outlet ());
125
126 }
127
128 void
129 Tuplet_iterator::construct_children ()
130 {
131   if (Duration *d = unsmob<Duration> (get_music ()->get_property ("duration")))
132     spanner_duration_ = d->get_length ();
133   else if (Moment *mp
134            = unsmob<Moment> (get_outlet ()->get_property ("tupletSpannerDuration")))
135     spanner_duration_ = mp->main_part_;
136   else
137     spanner_duration_.set_infinite (1);
138
139   Music_wrapper_iterator::construct_children ();
140
141   if (child_iter_ && child_iter_->ok ())
142     descend_to_child (child_iter_->get_outlet ());
143 }
144
145 void
146 Tuplet_iterator::derived_mark () const
147 {
148   scm_gc_mark (synthesized_events_);
149   Music_wrapper_iterator::derived_mark ();
150 }
151
152 IMPLEMENT_CTOR_CALLBACK (Tuplet_iterator);