X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ftuplet-engraver.cc;h=c25d2a9a4e6f547ac42cfc76a334aa5011730fb8;hb=d1f044d19e0e3c163374973ee8a6c61611c3408e;hp=542b0f7ae4e410ce2ddf3f952e0233e40569adfb;hpb=38fa6a3720e1187ec51514ab2a209c67ce19e14c;p=lilypond.git diff --git a/lily/tuplet-engraver.cc b/lily/tuplet-engraver.cc index 542b0f7ae4..c25d2a9a4e 100644 --- a/lily/tuplet-engraver.cc +++ b/lily/tuplet-engraver.cc @@ -1,160 +1,225 @@ -/* - plet-engraver.cc -- implement Tuplet_engraver - +/* + tuplet-engraver.cc -- implement Tuplet_engraver + source file of the GNU LilyPond music typesetter - - (c) 1998--2000 Han-Wen Nienhuys - - */ + (c) 1998--2007 Han-Wen Nienhuys +*/ -#include "command-request.hh" -#include "tuplet-spanner.hh" -#include "note-column.hh" -#include "time-scaled-music.hh" #include "beam.hh" -#include "music-list.hh" #include "engraver.hh" +#include "international.hh" +#include "note-column.hh" #include "spanner.hh" +#include "stream-event.hh" +#include "tuplet-bracket.hh" +#include "warn.hh" +#include "item.hh" +#include "moment.hh" + +#include "translator.icc" + +struct Tuplet_description +{ + Stream_event *event_; + Spanner *bracket_; + Spanner *number_; + + bool full_length_; + bool full_length_note_; + Moment stop_moment_; + Moment start_moment_; + Moment length_; + + Tuplet_description () + { + event_ = 0; + full_length_note_ = false; + full_length_ = false; + bracket_ = 0; + number_ = 0; + } +}; class Tuplet_engraver : public Engraver { public: - VIRTUAL_COPY_CONS(Translator); + TRANSLATOR_DECLARATIONS (Tuplet_engraver); protected: - Link_array time_scaled_music_arr_; - /// when does the scaled music stop? Array order is synced with time_scaled_music_arr_ - Array stop_moments_; - /// when does the current spanner stop? Array order is synced with time_scaled_music_arr_ - Array span_stop_moments_; + vector tuplets_; + vector new_tuplets_; + vector stopped_tuplets_; + vector last_tuplets_; - /// The spanners. Array order is synced with time_scaled_music_arr_ - Link_array started_span_p_arr_; - - virtual void do_removal_processing (); - virtual void acknowledge_grob (Grob_info); - virtual bool try_music (Music*r); - virtual void start_translation_timestep (); - virtual void create_grobs (); + DECLARE_ACKNOWLEDGER (note_column); + DECLARE_TRANSLATOR_LISTENER (tuplet_span); + virtual void finalize (); + void start_translation_timestep (); + void process_music (); }; -bool -Tuplet_engraver::try_music (Music *r) +IMPLEMENT_TRANSLATOR_LISTENER (Tuplet_engraver, tuplet_span); +void +Tuplet_engraver::listen_tuplet_span (Stream_event *ev) { - if (Time_scaled_music * c = dynamic_cast (r)) + Direction dir = to_dir (ev->get_property ("span-direction")); + if (dir == START) { - Music *el = c->element (); - if (!dynamic_cast (el)) - { - time_scaled_music_arr_.push (c); - Moment m = now_mom () + c->length_mom (); - stop_moments_.push (m); + Tuplet_description d; + d.event_ = ev; - SCM s = get_property ("tupletSpannerDuration"); - if (unsmob_moment(s)) - m = m get_property ("length"), + Moment (0)); + d.start_moment_ = now_mom (); + d.stop_moment_ = now_mom () + d.length_; + + for (vsize i=0; i < new_tuplets_.size (); i++) + { + /* + discard duplicates. + */ + if (new_tuplets_[i].stop_moment_ == d.stop_moment_) + return; } - return true; + + new_tuplets_.push_back (d); + } + else if (dir == STOP) + { + if (tuplets_.size ()) + { + stopped_tuplets_.push_back (tuplets_.back ()); + tuplets_.pop_back (); + } + else + ev->origin ()->warning (_f ("No tuplet to end")); } - return false; + else + ev->origin ()->programming_error ("direction tuplet-span-event_ invalid."); } void -Tuplet_engraver::create_grobs () +Tuplet_engraver::process_music () { - SCM v = get_property ("tupletInvisible"); - if (to_boolean (v)) - return; + /* + This may happen if the end of a tuplet is part of a quoted voice. + */ + Moment now = now_mom(); + for (vsize i = tuplets_.size (); i --; ) + { + if (tuplets_[i].stop_moment_ == now) + { + stopped_tuplets_.push_back (tuplets_[i]); + tuplets_.erase (tuplets_.begin () + i); + } + } + + for (vsize i = 0; i < stopped_tuplets_.size (); i++) + { + Spanner *bracket = stopped_tuplets_[i].bracket_; + Spanner *number = stopped_tuplets_[i].number_; + if (bracket) + { + if (stopped_tuplets_[i].full_length_) + { + Item *col = + unsmob_item (stopped_tuplets_[i].full_length_note_ + ? get_property ("currentMusicalColumn") + : get_property ("currentCommandColumn")); + + bracket->set_bound (RIGHT, col); + number->set_bound (RIGHT, col); + } + else if (!bracket->get_bound (RIGHT)) + { + bracket->set_bound (RIGHT, + bracket->get_bound (LEFT)); + 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 (bracket); + last_tuplets_.push_back (number); + } + } + stopped_tuplets_.clear (); - for (int i= 0; i < time_scaled_music_arr_.size (); i++) + concat (tuplets_, new_tuplets_); + new_tuplets_.clear (); + for (vsize j = tuplets_.size (); j > 0; j--) { - if (i < started_span_p_arr_.size () && started_span_p_arr_[i]) + /* i goes from size-1 downto 0, inclusively */ + vsize i = j - 1; + + + if (tuplets_[i].bracket_) continue; - Spanner* glep = new Spanner (get_property ("TupletBracket")); - Tuplet_spanner::set_interface (glep); - if (i >= started_span_p_arr_.size ()) - started_span_p_arr_.push (glep); - else - started_span_p_arr_[i] = glep; + tuplets_[i].full_length_ = to_boolean (get_property ("tupletFullLength")); + tuplets_[i].full_length_note_ + = to_boolean (get_property ("tupletFullLengthNote")); + + tuplets_[i].bracket_ = make_spanner ("TupletBracket", + tuplets_[i].event_->self_scm ()); + tuplets_[i].number_ = make_spanner ("TupletNumber", + tuplets_[i].event_->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 ()); + tuplets_[i].stop_moment_.grace_part_ = 0; + - glep->set_grob_property ("text", - ly_str02scm (to_str (time_scaled_music_arr_[i]->den_i_).ch_C())); + if (i + 1 < tuplets_.size () && tuplets_[i + 1].bracket_) + Tuplet_bracket::add_tuplet_bracket (tuplets_[i].bracket_, tuplets_[i + 1].bracket_); - announce_grob (glep, time_scaled_music_arr_ [i]); + if (i > 0 && tuplets_[i - 1].bracket_) + Tuplet_bracket::add_tuplet_bracket (tuplets_[i - 1].bracket_, tuplets_[i].bracket_); + } } void -Tuplet_engraver::acknowledge_grob (Grob_info i) +Tuplet_engraver::acknowledge_note_column (Grob_info inf) { - bool grace= to_boolean (i.elem_l_->get_grob_property ("grace")); - SCM wg = get_property ("weAreGraceContext"); - bool wgb = to_boolean (wg); - if (grace != wgb) - return; - - if (Note_column::has_interface(i.elem_l_)) - { - for (int j =0; j (i.elem_l_)); - } - else if (Beam::has_interface (i.elem_l_)) - { - for (int j = 0; j < started_span_p_arr_.size (); j++) - if (started_span_p_arr_[j]) - Tuplet_spanner::add_beam (started_span_p_arr_[j],i.elem_l_); - } + for (vsize j = 0; j < tuplets_.size (); j++) + if (tuplets_[j].bracket_) + { + Item *i = dynamic_cast (inf.grob ()); + Tuplet_bracket::add_column (tuplets_[j].bracket_, i); + add_bound_item (tuplets_[j].number_, i); + } } void Tuplet_engraver::start_translation_timestep () { - Moment now = now_mom (); - - Moment tsd; - SCM s = get_property ("tupletSpannerDuration"); - if (unsmob_moment (s)) - tsd = *unsmob_moment (s); - - for (int i= started_span_p_arr_.size (); i--; ) - { - if (now >= span_stop_moments_[i]) - { - if (started_span_p_arr_[i]) - { - typeset_grob (started_span_p_arr_[i]); - started_span_p_arr_[i] =0; - } - - if (tsd) - span_stop_moments_[i] += tsd; - } - - if (now >= stop_moments_[i]) - { - started_span_p_arr_.del (i); - stop_moments_.del(i); - span_stop_moments_.del (i); - time_scaled_music_arr_.del(i); - } - } + last_tuplets_.clear (); } void -Tuplet_engraver::do_removal_processing () +Tuplet_engraver::finalize () { - for (int i=0; i < started_span_p_arr_.size (); i++) - { - if (started_span_p_arr_[i]) - typeset_grob (started_span_p_arr_[i]); - } + 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); + } } -ADD_THIS_TRANSLATOR(Tuplet_engraver); - +Tuplet_engraver::Tuplet_engraver () +{ +} +ADD_ACKNOWLEDGER (Tuplet_engraver, note_column); +ADD_TRANSLATOR (Tuplet_engraver, + /* doc */ "Catch TupletSpannerEvent and generate appropriate bracket ", + /* create */ + "TupletBracket " + "TupletNumber ", + /* read */ + "tupletFullLength " + "tupletFullLengthNote ", + /* write */ "");