source file of the GNU LilyPond music typesetter
- (c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ (c) 1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
*/
-#include "grace-iterator.hh"
+
#include "translator-group.hh"
#include "debug.hh"
#include "sequential-music-iterator.hh"
#include "music-list.hh"
-#include "request-chord-iterator.hh"
-void
-Sequential_music_iterator::do_print() const
-{
- if (iter_p_)
- iter_p_->print();
-}
+/*
+
+ TODO: handling of grace notes is exquisite pain. This handling
+ should be formally specified and then the implementation verified.
+
+*/
+
+/*
+ TODO: the grace note handling hasn't been done for skip() and
+ get_music(), meaning that staff-switching and partcombining will be
+ broken with grace notes.
+
+ */
+/*
+
+ TODO: the grace note handling hasn't been done for skip() and
+ get_music(), meaning that staff-switching and partcombining will be
+ broken with grace notes.
+
+ */
+/*
+ Invariant for the data structure.
+
+
+ if (gh_pair_p (cursor_))
+ iter_p_->music_l_ == unsmob_music (ly_car (cursor_))
+ else
+ iter_p_ == 0;
+
+ The length of musiclist from start to up to cursor_ (cursor_ not
+ including), is summed
+
+ here_mom_ = sum (length (musiclist [start ... cursor>)) %)
+
+ */
Sequential_music_iterator::Sequential_music_iterator ()
{
- cursor_ = 0;
- here_mom_ = 0;
+ cursor_ = SCM_EOL;
+ here_mom_ = Moment (0);
+ grace_fixups_ = 0;
iter_p_ =0;
}
-void
-Sequential_music_iterator::construct_children()
+Sequential_music_iterator::Sequential_music_iterator (Sequential_music_iterator const &src)
+ : Music_iterator (src)
{
- cursor_ = dynamic_cast<Music_sequence const*> (music_l_)->music_list ();
+ grace_fixups_ = src.grace_fixups_;
+ cursor_ = src.cursor_;
+ here_mom_ = src.here_mom_;
+ if (src.iter_p_)
+ iter_p_ = src.iter_p_->clone ();
+ else
+ iter_p_ = 0;
+}
+
+Sequential_music_iterator::~Sequential_music_iterator ()
+{
+ delete iter_p_;
+}
+
+
+/*
+
+
+ if (start_music.grace)
+ here.grace -= start_music.grace
+
+ last
+ if (len
- while (gh_pair_p (cursor_ ))
+ */
+
+Grace_fixup *
+get_grace_fixups (SCM cursor)
+{
+ Moment here;
+ Moment last (-1);
+ Grace_fixup *head = 0;
+ Grace_fixup **tail = &head;
+
+ for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
{
- start_next_element();
- if (!iter_p_->ok())
+ Music * mus = unsmob_music (ly_car (cursor));
+ Moment s = mus->start_mom ();
+ Moment l =mus->length_mom () - s;
+
+ if (s.grace_part_)
{
- leave_element();
+ if (last != Moment (-1))
+ {
+ Grace_fixup *p =new Grace_fixup;
+ p->start_ = last;
+ p->length_ = here - last;
+ p->grace_start_ = s.grace_part_;
+ p->next_ = 0;
+ *tail = p;
+ tail = &(*tail)->next_;
+ }
+
+ here.grace_part_ = s.grace_part_;
}
- else
+
+ if (l.to_bool())
{
- set_sequential_music_translator();
- break;
+ last = here;
+ here += l;
}
}
+ return head;
}
-void
-Sequential_music_iterator::leave_element()
+void
+Sequential_music_iterator::construct_children ()
{
- delete iter_p_;
- iter_p_ =0;
- Moment elt_time = unsmob_music (gh_car (cursor_))->length_mom ();
- here_mom_ += elt_time;
- cursor_ =gh_cdr (cursor_);
+ cursor_ = dynamic_cast<Music_sequence const*> (music_l ())->music_list ();
+
+ iter_p_ = gh_pair_p (cursor_) ? get_iterator_p (unsmob_music (ly_car (cursor_))) : 0;
+ while (iter_p_ && !iter_p_->ok ())
+ {
+ next_element ();
+ }
+
+ here_mom_ = music_l ()->start_mom ();
+ grace_fixups_ = get_grace_fixups (cursor_);
+
+ /*
+ iter_p_->ok () is tautology, but what the heck.
+ */
+ if (iter_p_ && iter_p_->ok ())
+ descend_to_child ();
}
+
+/*
+ maintain invariants: change cursor, iter and here_mom_ in one fell
+ swoop.
+*/
void
-Sequential_music_iterator::start_next_element()
+Sequential_music_iterator::next_element ()
{
- assert (!iter_p_);
- iter_p_ = get_iterator_p (unsmob_music (gh_car (cursor_)));
+ Moment len =iter_p_->music_length_mom () - iter_p_->music_start_mom ();
+ assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
+
+ if (len.main_part_ && grace_fixups_ &&
+ grace_fixups_->start_ == here_mom_)
+ {
+ here_mom_ += grace_fixups_->length_;
+ here_mom_.grace_part_ += grace_fixups_->grace_start_;
+
+ Grace_fixup * n =grace_fixups_->next_;
+ delete grace_fixups_;
+ grace_fixups_ = n;
+ }
+ else if (len.grace_part_ && !len.main_part_)
+ {
+ here_mom_.grace_part_ =0;
+ }
+ else
+ {
+ /*
+ !len.grace_part_ || len.main_part_
+
+ We skip over a big chunk (mainpart != 0). Any starting graces
+ in that chunk should be in len.grace_part_
+
+ */
+ here_mom_ += len;
+ }
+
+ delete iter_p_;
+ cursor_ = ly_cdr (cursor_);
+
+ if (gh_pair_p (cursor_))
+ iter_p_ = get_iterator_p (unsmob_music (ly_car (cursor_)));
+ else
+ iter_p_ = 0;
}
+/*
+ move to context of child iterator if it is deeper down in the
+ hierarchy.
+ */
void
-Sequential_music_iterator::set_sequential_music_translator()
+Sequential_music_iterator::descend_to_child ()
{
Translator_group * child_report = child_report = iter_p_->report_to_l ();
- if (dynamic_cast<Grace_iterator*> (iter_p_))
- child_report = child_report->daddy_trans_l_;
-
- if (report_to_l()->depth_i () < child_report->depth_i ())
+ Translator_group * me_report = report_to_l ();
+
+ Translator_group * c = child_report;
+ while (c && c != me_report)
+ {
+ c= c->daddy_trans_l_;
+ }
+
+ if (c == me_report)
set_translator (child_report);
}
-Sequential_music_iterator::~Sequential_music_iterator()
+
+/*
+ Retrieve all music (starting at HERE), until a music with length L >
+ 0 is found. From the precondition, we know that UNTIL is later than
+ the earliest event. Hence we know
+
+ L >= (UNTIL - HERE)
+
+ so something that comes after this thing with L > 0 happens after
+
+ HERE + L >= HERE + (UNTIL - HERE) = UNTIL
+
+ Hence all events after the one with L>0 are uninteresting, so we
+ ignore them.
+
+*/
+
+SCM
+Sequential_music_iterator::get_music (Moment until)const
{
- if (iter_p_)
+ SCM s = SCM_EOL;
+ if (until < pending_moment ())
+ return s;
+
+ Sequential_music_iterator * me =
+ dynamic_cast<Sequential_music_iterator*> (clone ());
+ while (me->ok ())
{
- if (iter_p_->ok ())
- music_l_->origin ()->warning (_ ("Must stop before this music ends"));
- delete iter_p_;
- iter_p_ = 0;
+ SCM nm = me->iter_p_->get_music (until - me->here_mom_);
+ s = gh_append2 (nm, s);
+
+ Moment m = 0;
+ for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
+ {
+ Music *mus=unsmob_music (ly_car (i));
+ m = m >? (mus->length_mom () - mus->start_mom ());
+ }
+ if (m > Moment (0))
+ break ;
+ else
+ me->next_element ();
}
+ delete me;
+
+ return s;
}
+
+/*
+ Skip events till UNTIL. We don't do any other side effects such as
+ descending to child iterator contexts, because they might depend on
+ \context specs and \translator changes being executed
+
+ TODO: build support for grace notes here.
+ */
void
-Sequential_music_iterator::do_process_and_next (Moment until)
+Sequential_music_iterator::skip (Moment until)
{
- if (!iter_p_)
- return;
+ while (ok ())
+ {
+ Moment l =iter_p_->music_length_mom ();
+ if (l >= until - here_mom_)
+ iter_p_->skip (until - here_mom_);
- while (1)
+ if (iter_p_->ok ())
+ return ;
+
+ next_element ();
+ }
+}
+
+void
+Sequential_music_iterator::process (Moment until)
+{
+ while (iter_p_)
{
- Moment local_until = until - here_mom_;
- while (iter_p_->ok())
+ if (grace_fixups_ &&
+ grace_fixups_->start_ == here_mom_
+ && (grace_fixups_->start_ + grace_fixups_->length_
+ + Moment (Rational (0), grace_fixups_->grace_start_) == until))
{
- Moment here = iter_p_->next_moment();
- if (here != local_until)
- goto loopexit;
-
- iter_p_->process_and_next (local_until);
+ /*
+ do the stuff/note/rest preceding a grace.
+ */
+ iter_p_->process (iter_p_->music_length_mom ());
}
-
- if (!iter_p_->ok())
- {
- set_sequential_music_translator();
- leave_element();
-
- if (gh_pair_p (cursor_))
- start_next_element();
- else
- goto loopexit;
- }
- }
+ else
+ iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
-loopexit:
+ /*
+ if the iter is still OK, there must be events left that have
+
+ TIME > LEFT
+
+ */
+ if (iter_p_->ok ())
+ return ;
- Music_iterator::do_process_and_next (until);
+ descend_to_child ();
+ next_element ();
+ }
}
Moment
-Sequential_music_iterator::next_moment() const
+Sequential_music_iterator::pending_moment () const
{
- return iter_p_->next_moment() + here_mom_;
+ Moment cp = iter_p_->pending_moment ();
+
+ /*
+ Fix-up a grace note halfway in the music.
+ */
+ if (grace_fixups_ && here_mom_ == grace_fixups_->start_
+ && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
+ {
+ return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
+ }
+
+ /*
+ Fix-up a grace note at the start of the music.
+ */
+ return cp + here_mom_ - iter_p_->music_start_mom ();
}
bool
-Sequential_music_iterator::ok() const
+Sequential_music_iterator::ok () const
{
return iter_p_;
}
{
return iter_p_ ? iter_p_->try_music (m) : 0;
}
+IMPLEMENT_CTOR_CALLBACK (Sequential_music_iterator);