Hi, Here's a patch that massively refactors tuplets and percent repeats.
Highlights: - tuplets are now signalled by start/stop events. - each percent/slash is signalled by an individual event, whose repeat-count property tells whether it should be numbered (this moves some decisions from engraver to iterator) The diffs of some files are huge, so I'm sending the new files instead. I think it's a bit out of place to merge percent_repeat and double_percent_repeat into one engraver. Some next steps that would be nice are: - move handling of double percent repeats to slash_engraver (or possibly to a new double_percent_engraver, but imho they are similar enough to share engraver) - handle percent_repeat with start/stop event - create different event types for percent event, slash event and double percent event. These are however not very related to music streams. Erik
/*
new-chord-tremolo-engraver.cc -- implement Chord_tremolo_engraver
source file of the GNU LilyPond music typesetter
(c) 2000--2006 Han-Wen Nienhuys <[EMAIL PROTECTED]>, Erik Sandberg <[EMAIL
PROTECTED]>
*/
#include "score-engraver.hh"
#include "bar-line.hh"
#include "global-context.hh"
#include "international.hh"
#include "item.hh"
#include "misc.hh"
#include "percent-repeat-iterator.hh"
#include "repeated-music.hh"
#include "score-context.hh"
#include "side-position-interface.hh"
#include "spanner.hh"
#include "warn.hh"
#include "translator.icc"
/*
* TODO: Create separate Double_percent_repeat_engraver?
* Or, at least move double percent handling to Slash_repeat_engraver
*/
class Percent_repeat_engraver : public Engraver
{
void typeset_perc ();
public:
TRANSLATOR_DECLARATIONS (Percent_repeat_engraver);
protected:
Music *percent_event_;
/// moment (global time) where percent started.
Moment stop_mom_;
Moment start_mom_;
enum Repeat_sign_type
{
UNKNOWN,
MEASURE,
DOUBLE_MEASURE,
};
Repeat_sign_type repeat_sign_type_;
Spanner *percent_;
Spanner *percent_counter_;
protected:
virtual void finalize ();
virtual bool try_music (Music *);
void stop_translation_timestep ();
void start_translation_timestep ();
void process_music ();
};
Percent_repeat_engraver::Percent_repeat_engraver ()
{
percent_ = 0;
percent_counter_ = 0;
percent_event_ = 0;
}
bool
Percent_repeat_engraver::try_music (Music *m)
{
if (m->is_mus_type ("percent-event")
&& !percent_event_)
{
Moment body_length = m->get_length ();
Moment meas_len (robust_scm2moment (get_property ("measureLength"),
Moment (1)));
if (meas_len == body_length)
{
repeat_sign_type_ = MEASURE;
start_mom_ = now_mom ();
stop_mom_ = now_mom () + body_length;
get_global_context ()->add_moment_to_process (stop_mom_);
}
else if (Moment (2) * meas_len == body_length)
{
repeat_sign_type_ = DOUBLE_MEASURE;
start_mom_ = now_mom () + meas_len;
stop_mom_ = now_mom () + body_length; /* never used */
get_global_context ()->add_moment_to_process (start_mom_);
}
else
return false;
percent_event_ = m;
return true;
}
return false;
}
void
Percent_repeat_engraver::process_music ()
{
if (percent_event_ && now_mom ().main_part_ == start_mom_.main_part_)
{
if (repeat_sign_type_ == MEASURE)
{
if (percent_)
typeset_perc ();
percent_ = make_spanner ("PercentRepeat", percent_event_->self_scm
());
Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
percent_->set_bound (LEFT, col);
SCM count = percent_event_->get_property ("repeat-count");
if (count != SCM_EOL && to_boolean (get_property
("countPercentRepeats")))
{
percent_counter_
= make_spanner ("PercentRepeatCounter",
percent_event_->self_scm ());
SCM text = scm_number_to_string (count, scm_from_int (10));
percent_counter_->set_property ("text", text);
percent_counter_->set_bound (LEFT, col);
Side_position_interface::add_support (percent_counter_,
percent_);
percent_counter_->set_parent (percent_, Y_AXIS);
}
else
percent_counter_ = 0;
}
else if (repeat_sign_type_ == DOUBLE_MEASURE)
{
Item *double_percent = make_item ("DoublePercentRepeat",
percent_event_->self_scm ());
SCM count = percent_event_->get_property ("repeat-count");
if (count != SCM_EOL
&& to_boolean (get_property ("countPercentRepeats")))
{
Item *double_percent_counter = make_item
("DoublePercentRepeatCounter",
percent_event_->self_scm());
SCM text = scm_number_to_string (count,
scm_from_int (10));
double_percent_counter->set_property ("text", text);
Side_position_interface::add_support (double_percent_counter,
double_percent);
double_percent_counter->set_parent (double_percent, Y_AXIS);
double_percent_counter->set_parent (double_percent, X_AXIS);
}
/* forbid breaks on a % line. Should forbid all breaks, really. */
context ()->get_score_context ()->set_property ("forbidBreak",
SCM_BOOL_T);
/* No more processing needed. */
repeat_sign_type_ = UNKNOWN;
}
}
}
void
Percent_repeat_engraver::finalize ()
{
if (percent_)
{
percent_event_->origin ()->warning (_ ("unterminated percent repeat"));
percent_->suicide ();
percent_counter_->suicide();
}
}
void
Percent_repeat_engraver::typeset_perc ()
{
if (percent_)
{
Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
percent_->set_bound (RIGHT, col);
percent_ = 0;
if (percent_counter_)
percent_counter_->set_bound (RIGHT, col);
percent_counter_ = 0;
}
}
void
Percent_repeat_engraver::start_translation_timestep ()
{
if (stop_mom_.main_part_ == now_mom ().main_part_)
{
if (percent_)
typeset_perc ();
percent_event_ = 0;
repeat_sign_type_ = UNKNOWN;
}
}
void
Percent_repeat_engraver::stop_translation_timestep ()
{
}
ADD_TRANSLATOR (Percent_repeat_engraver,
/* doc */
"Make whole bar and double bar repeats.",
/* create */
"PercentRepeat "
"DoublePercentRepeat "
"PercentRepeatCounter "
"DoublePercentRepeatCounter",
/* accept */
"percent-event",
/* read */
"measureLength "
"currentCommandColumn "
"countPercentRepeats",
/* write */
"forbidBreak "
);
/*
percent-repeat-iterator.cc -- implement Percent_repeat_iterator
source file of the GNU LilyPond music typesetter
(c) 2001--2006 Han-Wen Nienhuys <[EMAIL PROTECTED]>, Erik Sandberg <[EMAIL
PROTECTED]>
*/
#include "percent-repeat-iterator.hh"
#include "input.hh"
#include "international.hh"
#include "music.hh"
#include "repeated-music.hh"
IMPLEMENT_CTOR_CALLBACK (Percent_repeat_iterator);
Percent_repeat_iterator::Percent_repeat_iterator ()
{
child_list_ = SCM_EOL;
}
void
Percent_repeat_iterator::construct_children ()
{
/* TODO: Distinction between percent and slash */
Music *mus = get_music ();
Music *child = Repeated_music::body (mus);
SCM length = child->get_length ().smobbed_copy ();
child_list_ = SCM_EOL;
int repeats = scm_to_int (mus->get_property ("repeat-count"));
for (int i = repeats; i > 1; i--)
{
Music *percent = make_music_by_name (ly_symbol2scm ("PercentEvent"));
percent->set_spot (*mus->origin ());
percent->set_property ("length", length);
if (repeats > 1)
percent->set_property ("repeat-count", scm_int2num (i - 1));
Music *percent_chord = make_music_by_name (ly_symbol2scm ("EventChord"));
percent_chord->set_spot (*mus->origin ());
percent_chord->set_property ("elements", scm_list_1 (percent->self_scm ()));
child_list_ = scm_cons (percent_chord->self_scm (), child_list_);
}
child_list_ = scm_cons (child->self_scm (), child_list_);
Sequential_iterator::construct_children ();
}
SCM
Percent_repeat_iterator::get_music_list () const
{
return child_list_;
}
void
Percent_repeat_iterator::derived_mark () const
{
scm_gc_mark (child_list_);
Sequential_iterator::derived_mark ();
}
/*
slash-repeat-engraver.cc -- implement Slash_repeat_engraver
source file of the GNU LilyPond music typesetter
(c) 2000--2006 Han-Wen Nienhuys <[EMAIL PROTECTED]>, Erik Sandberg <[EMAIL
PROTECTED]>
*/
#include "repeated-music.hh"
#include "global-context.hh"
#include "warn.hh"
#include "misc.hh"
#include "spanner.hh"
#include "item.hh"
#include "percent-repeat-iterator.hh"
#include "bar-line.hh"
#include "score-engraver.hh"
/**
This acknowledges repeated music with "percent" style. It typesets
a slash sign.
*/
class Slash_repeat_engraver : public Engraver
{
public:
TRANSLATOR_DECLARATIONS (Slash_repeat_engraver);
protected:
Music *slash_;
protected:
virtual bool try_music (Music *);
void process_music ();
};
Slash_repeat_engraver::Slash_repeat_engraver ()
{
slash_ = 0;
}
bool
Slash_repeat_engraver::try_music (Music *m)
{
/*todo: separate events for percent and slash */
if (m->is_mus_type ("percent-event"))
{
Moment meas_length
= robust_scm2moment (get_property ("measureLength"), Moment (0));
if (m->get_length () < meas_length)
slash_ = m;
else
return false;
return true;
}
return false;
}
void
Slash_repeat_engraver::process_music ()
{
if (slash_)
{
make_item ("RepeatSlash", slash_->self_scm ());
slash_ = 0;
}
}
#include "translator.icc"
ADD_TRANSLATOR (Slash_repeat_engraver,
/* doc */ "Make beat repeats.",
/* create */ "RepeatSlash",
/* accept */ "percent-event",
/* read */ "measureLength",
/* write */ "");
/*
tuplet-engraver.cc -- implement Tuplet_engraver
source file of the GNU LilyPond music typesetter
(c) 1998--2006 Han-Wen Nienhuys <[EMAIL PROTECTED]>
*/
#include "tuplet-bracket.hh"
#include "note-column.hh"
#include "beam.hh"
#include "engraver.hh"
#include "spanner.hh"
#include "translator.icc"
struct Tuplet_description
{
Music *music_;
Spanner *bracket_;
Spanner *number_;
Tuplet_description ()
{
music_ = 0;
bracket_ = 0;
number_ = 0;
}
};
class Tuplet_engraver : public Engraver
{
public:
TRANSLATOR_DECLARATIONS (Tuplet_engraver);
protected:
vector<Tuplet_description> tuplets_;
vector<Tuplet_description> stopped_tuplets_;
vector<Spanner*> last_tuplets_;
DECLARE_ACKNOWLEDGER (note_column);
virtual bool try_music (Music *r);
virtual void finalize ();
void start_translation_timestep ();
void process_music ();
};
bool
Tuplet_engraver::try_music (Music *music)
{
if (music->is_mus_type ("tuplet-spanner-event"))
{
Direction dir = to_dir (music->get_property ("span-direction"));
if (dir == START)
{
Tuplet_description d;
d.music_ = music;
tuplets_.push_back (d);
}
if (dir == STOP)
{
stopped_tuplets_.push_back (tuplets_.back ());
tuplets_.pop_back ();
}
return true;
}
return false;
}
void
Tuplet_engraver::process_music ()
{
for (vsize i = 0; i < stopped_tuplets_.size (); i++)
{
bool full_length = to_boolean (get_property ("tupletFullLength"));
if (stopped_tuplets_[i].bracket_)
{
if (full_length)
{
Item *col = unsmob_item (get_property ("currentMusicalColumn"));
stopped_tuplets_[i].bracket_->set_bound (RIGHT, col);
stopped_tuplets_[i].number_->set_bound (RIGHT, col);
}
else if (!stopped_tuplets_[i].bracket_->get_bound (RIGHT))
{
stopped_tuplets_[i].bracket_->set_bound (RIGHT,
stopped_tuplets_[i].bracket_->get_bound (LEFT));
stopped_tuplets_[i].number_->set_bound (RIGHT,
stopped_tuplets_[i].bracket_->get_bound (LEFT));
}
// todo: scrap last_tuplets_, use stopped_tuplets_ only.
// clear stopped_tuplets_ at start_translation_timestep
last_tuplets_.push_back (tuplets_[i].bracket_);
last_tuplets_.push_back (tuplets_[i].number_);
}
}
stopped_tuplets_.clear ();
if (!tuplets_.size ())
return;
for (vsize i = 0; i < tuplets_.size (); i++)
{
if (tuplets_[i].bracket_)
continue;
tuplets_[i].bracket_ = make_spanner ("TupletBracket",
tuplets_[i].music_->self_scm ());
tuplets_[i].number_ = make_spanner ("TupletNumber",
tuplets_[i].music_->self_scm ());
tuplets_[i].number_->set_object ("bracket",
tuplets_[i].bracket_->self_scm ());
tuplets_[i].bracket_->set_object ("tuplet-number",
tuplets_[i].number_->self_scm ());
if (i > 0 && tuplets_[i - 1].bracket_)
Tuplet_bracket::add_tuplet_bracket (tuplets_[i].bracket_, tuplets_[i -
1].bracket_);
if (i < tuplets_.size () - 1 && tuplets_[i + 1].bracket_)
Tuplet_bracket::add_tuplet_bracket (tuplets_[i + 1].bracket_,
tuplets_[i].bracket_);
SCM proc = get_property ("tupletNumberFormatFunction");
if (ly_is_procedure (proc))
{
SCM t = scm_apply_0 (proc, scm_list_1 (tuplets_[i].music_->self_scm
()));
tuplets_[i].number_->set_property ("text", t);
}
}
}
void
Tuplet_engraver::acknowledge_note_column (Grob_info inf)
{
for (vsize j = 0; j < tuplets_.size (); j++)
if (tuplets_[j].bracket_)
{
Item *i = dynamic_cast<Item *> (inf.grob ());
Tuplet_bracket::add_column (tuplets_[j].bracket_, i);
add_bound_item (tuplets_[j].number_, i);
}
}
void
Tuplet_engraver::start_translation_timestep ()
{
last_tuplets_.clear ();
}
void
Tuplet_engraver::finalize ()
{
if (to_boolean (get_property ("tupletFullLength")))
{
for (vsize i = 0; i < last_tuplets_.size (); i++)
{
Item *col = unsmob_item (get_property ("currentCommandColumn"));
last_tuplets_[i]->set_bound (RIGHT, col);
}
}
}
Tuplet_engraver::Tuplet_engraver ()
{
}
ADD_ACKNOWLEDGER (Tuplet_engraver, note_column);
ADD_TRANSLATOR (Tuplet_engraver,
/* doc */ "Catch TupletSpannerEvent and generate appropriate
bracket ",
/* create */ "TupletBracket TupletNumber",
/* accept */ "tuplet-spanner-event",
/* read */ "tupletNumberFormatFunction tupletSpannerDuration
tupletFullLength",
/* write */ "");
repeats.diff
Description: Binary data
_______________________________________________ lilypond-devel mailing list [email protected] http://lists.gnu.org/mailman/listinfo/lilypond-devel
