]> git.donarmstrong.com Git - lilypond.git/blob - lily/tuplet-iterator.cc
bf9a223684840885a32edf9d1efbcfa5354676b0
[lilypond.git] / lily / tuplet-iterator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2012 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
28 /*
29   Iterates \times, by sending TupletSpanEvents at the start/end of each
30   tuplet bracket.  Extra stop/start events are sent at regular
31   intervals if tupletSpannerDuration is set.
32 */
33 class Tuplet_iterator : public Music_wrapper_iterator
34 {
35 public:
36   DECLARE_SCHEME_CALLBACK (constructor, ());
37   /* construction */
38   DECLARE_CLASSNAME (Tuplet_iterator);
39   Tuplet_iterator ();
40 protected:
41   virtual void process (Moment m);
42   virtual void construct_children ();
43   virtual void derived_mark () const;
44   virtual Moment pending_moment () const;
45
46   Music *create_event (Direction d);
47
48 private:
49
50   /* tupletSpannerDuration */
51   Moment spanner_duration_;
52
53   /* next time to add a stop/start pair */
54   Moment next_split_mom_;
55
56   /* Recycle start/stop events if tupletSpannerDuration is set. */
57   SCM synthesized_events_;
58
59   Context_handle tuplet_handler_;
60 };
61
62 Music *
63 Tuplet_iterator::create_event (Direction d)
64 {
65   SCM ev_scm = scm_call_2 (ly_lily_module_constant ("make-span-event"),
66                            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           tuplet_handler_.set_context (get_outlet ());
113           report_event (create_event (START));
114
115           next_split_mom_ += spanner_duration_;
116         }
117       else
118         tuplet_handler_.set_context (0);
119     }
120   Music_wrapper_iterator::process (m);
121   if (child_iter_ && child_iter_->ok ())
122     descend_to_child (child_iter_->get_outlet ());
123
124 }
125
126 void
127 Tuplet_iterator::construct_children ()
128 {
129   if (Duration *d = unsmob_duration (get_music ()->get_property ("duration")))
130     spanner_duration_ = d->get_length ();
131   else
132     {
133       spanner_duration_ = music_get_length ();
134
135       Moment *mp
136         = unsmob_moment (get_outlet ()->get_property ("tupletSpannerDuration"));
137       if (mp)
138         spanner_duration_ = min (mp->main_part_, spanner_duration_);
139     }
140
141   Music_wrapper_iterator::construct_children ();
142
143   if (child_iter_ && child_iter_->ok ())
144     descend_to_child (child_iter_->get_outlet ());
145 }
146
147 void
148 Tuplet_iterator::derived_mark () const
149 {
150   scm_gc_mark (synthesized_events_);
151   Music_wrapper_iterator::derived_mark ();
152 }
153
154 IMPLEMENT_CTOR_CALLBACK (Tuplet_iterator);