]> git.donarmstrong.com Git - lilypond.git/blob - lily/time-scaled-music-iterator.cc
Merge branch 'master' of git+ssh://jneem@git.sv.gnu.org/srv/git/lilypond
[lilypond.git] / lily / time-scaled-music-iterator.cc
1 /*
2   time-scaled-music-iterator.cc -- implement Time_scaled_music_iterator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>,
7                  Erik Sandberg <mandolaerik@gmail.com>
8 */
9
10 #include "context.hh"
11 #include "input.hh"
12 #include "international.hh"
13 #include "music.hh"
14 #include "music-wrapper-iterator.hh"
15
16 /*
17   Iterates \times, by sending TupletSpanEvents at the start/end of each
18   tuplet bracket. Extra stop/start events are sent at regular
19   intervals if tupletSpannerDuration is set.
20 */
21 class Time_scaled_music_iterator : public Music_wrapper_iterator
22 {
23 public:
24   DECLARE_SCHEME_CALLBACK (constructor, ());
25   /* construction */
26   DECLARE_CLASSNAME(Time_scaled_music_iterator);
27   Time_scaled_music_iterator ();
28 protected:
29   virtual void process (Moment m);
30   virtual void construct_children ();
31   virtual void derived_mark () const;
32   virtual Moment pending_moment () const;
33 private:
34
35   /* tupletSpannerDuration */
36   Moment spanner_duration_;
37
38   /* next time to add a stop/start pair */
39   Moment next_split_mom_;
40   
41   /* Recycle start/stop events if tupletSpannerDuration is set. */
42   Music *start_;
43   Music *stop_;
44
45   bool done_first_;
46   
47   Context_handle tuplet_handler_;
48 };
49
50 Time_scaled_music_iterator::Time_scaled_music_iterator ()
51 {
52   spanner_duration_ = next_split_mom_ = 0;
53   done_first_ = 0;
54 }
55
56
57 Moment
58 Time_scaled_music_iterator::pending_moment () const
59 {
60   if (!done_first_)
61     return Moment (0);
62   
63   Moment next_mom = Music_wrapper_iterator::pending_moment ();
64
65   if (spanner_duration_.to_bool () &&
66       next_mom.main_part_ > next_split_mom_)
67     {
68       next_mom = next_split_mom_;
69     }
70
71   return next_mom;
72 }
73
74
75 void
76 Time_scaled_music_iterator::process (Moment m)
77 {
78   if (!done_first_)
79     {
80       done_first_ = true;
81       descend_to_bottom_context ();
82       report_event (start_);
83       tuplet_handler_.set_context (get_outlet());
84     }
85
86   if (spanner_duration_.to_bool () &&
87       m.main_part_ == next_split_mom_)
88     {
89       descend_to_bottom_context ();
90       stop_->send_to_context (tuplet_handler_.get_outlet ());
91       
92       tuplet_handler_.set_context (get_outlet ());
93       report_event (start_);
94       
95       next_split_mom_ += spanner_duration_;
96       /* avoid sending events twice at the end */
97       if (next_split_mom_ == get_music ()->get_length ().main_part_)
98         next_split_mom_.set_infinite (1);
99     }
100
101   Music_wrapper_iterator::process(m);
102   if (child_iter_ && child_iter_->ok ())
103     descend_to_child (child_iter_->get_outlet ());
104   
105   if (m.main_part_ == music_get_length ().main_part_)
106     {
107       stop_->send_to_context (tuplet_handler_.get_outlet ());
108       tuplet_handler_.set_context (0);
109     }
110 }
111
112 void
113 Time_scaled_music_iterator::construct_children ()
114 {
115   /*
116     Inheritance trickery:
117     Time_scaled_music_iterator::construct_children initialises start_
118     and stop_, and calls Sequential_music::construct_children, which
119     in turn calls Time_scaled_music_iterator::get_music which reads
120     start_ and stop_.
121    */
122
123   Music *mus = get_music ();
124   Input *origin = mus->origin ();
125
126   SCM tuplet_symbol = ly_symbol2scm ("TupletSpanEvent");
127   SCM start_scm = scm_call_2 (ly_lily_module_constant ("make-span-event"), tuplet_symbol, scm_from_int (START));
128   start_ = unsmob_music (start_scm);
129   start_->set_spot (*origin);
130   start_->set_property ("numerator", mus->get_property ("numerator"));
131   start_->set_property ("denominator", mus->get_property ("denominator"));
132   start_->set_property ("tweaks", mus->get_property ("tweaks"));
133   
134
135   SCM stop_scm = scm_call_2 (ly_lily_module_constant ("make-span-event"), tuplet_symbol, scm_from_int (STOP));
136   stop_ = unsmob_music (stop_scm);
137   stop_->set_spot (*origin);
138
139   Moment *mp = unsmob_moment (get_outlet ()->get_property ("tupletSpannerDuration"));
140
141   if (mp)
142     {
143       spanner_duration_ = mp->main_part_;
144       next_split_mom_ = spanner_duration_;
145     }
146
147   Music_wrapper_iterator::construct_children ();
148
149   if (child_iter_ && child_iter_->ok ())
150     descend_to_child (child_iter_->get_outlet ());
151 }
152
153 void
154 Time_scaled_music_iterator::derived_mark () const
155 {
156   if (start_)
157     scm_gc_mark (start_->self_scm ());
158   if (stop_)
159     scm_gc_mark (stop_->self_scm ());
160
161   Music_wrapper_iterator::derived_mark ();
162 }
163
164 IMPLEMENT_CTOR_CALLBACK (Time_scaled_music_iterator);