X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Ftuplet-engraver.cc;h=61f623c54638d435d90b71212ac429b7cb48bf3c;hb=8e2eaf4959bec63a1128a444591a540f4f1e2937;hp=2845d4c445a823063346b14438b7c0118cf5d1b8;hpb=9d4a5bbc9687aef811a60aabd9cb839412984e96;p=lilypond.git diff --git a/lily/tuplet-engraver.cc b/lily/tuplet-engraver.cc index 2845d4c445..61f623c546 100644 --- a/lily/tuplet-engraver.cc +++ b/lily/tuplet-engraver.cc @@ -1,37 +1,55 @@ /* - tuplet-engraver.cc -- implement Tuplet_engraver + This file is part of LilyPond, the GNU music typesetter. - source file of the GNU LilyPond music typesetter + Copyright (C) 1998--2015 Han-Wen Nienhuys - (c) 1998--2006 Han-Wen Nienhuys + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ -#include "tuplet-bracket.hh" -#include "note-column.hh" #include "beam.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 { - Music *music_; - Rational stop_; - Rational span_stop_; - Rational length_; + Stream_event *event_; Spanner *bracket_; Spanner *number_; + + bool full_length_; + bool full_length_note_; + Moment stop_moment_; + Moment start_moment_; + Moment length_; + Tuplet_description () { - music_ = 0; + event_ = 0; + full_length_note_ = false; + full_length_ = false; bracket_ = 0; number_ = 0; } - static int compare (Tuplet_description const &a, Tuplet_description const &b) - { - return ::compare (a.length_, b.length_); - } }; class Tuplet_engraver : public Engraver @@ -40,71 +58,145 @@ public: TRANSLATOR_DECLARATIONS (Tuplet_engraver); protected: - std::vector tuplets_; - Link_array__Spanner_ last_tuplets_; - DECLARE_ACKNOWLEDGER (note_column); - virtual bool try_music (Music *r); + vector tuplets_; + vector new_tuplets_; + vector stopped_tuplets_; + vector last_tuplets_; + + void acknowledge_note_column (Grob_info); + void acknowledge_script (Grob_info); + void acknowledge_finger (Grob_info); + void acknowledge_string_number (Grob_info); + void listen_tuplet_span (Stream_event *); virtual void finalize (); void start_translation_timestep (); void process_music (); }; -bool -Tuplet_engraver::try_music (Music *music) +void +Tuplet_engraver::listen_tuplet_span (Stream_event *ev) { - if (music->is_mus_type ("time-scaled-music")) + Direction dir = to_dir (ev->get_property ("span-direction")); + if (dir == START) { - Music *el = unsmob_music (music->get_property ("element")); - if (el && !el->is_mus_type ("event-chord")) - { - Tuplet_description d; - d.music_ = music; - d.length_ = music->get_length ().main_part_; - d.stop_ = now_mom ().main_part_ + d.length_; - d.span_stop_ = d.stop_; - - SCM s = get_property ("tupletSpannerDuration"); - if (unsmob_moment (s)) - d.span_stop_ = min (d.span_stop_, (now_mom () + *unsmob_moment (s)).main_part_); - - tuplets_.push_back (d); - } - return true; + Tuplet_description d; + d.event_ = ev; + + d.length_ = robust_scm2moment (d.event_->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; + } + + new_tuplets_.push_back (d); + } + else if (dir == STOP) + { + if (tuplets_.size ()) + { + stopped_tuplets_.push_back (tuplets_.back ()); + tuplets_.pop_back (); + } + else if (!to_boolean (get_property ("skipTypesetting"))) + ev->origin ()->debug_output (_ ("No tuplet to end")); } - return false; + else + ev->origin ()->programming_error ("direction tuplet-span-event_ invalid."); } void Tuplet_engraver::process_music () { - if (!tuplets_.size ()) - 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); + } + } - vector_sort (tuplets_, Tuplet_description::compare); - for (vsize i = 0; i < tuplets_.size (); 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 (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)) + { + if (bracket->get_bound (LEFT)) + { + bracket->set_bound (RIGHT, + bracket->get_bound (LEFT)); + number->set_bound (RIGHT, + stopped_tuplets_[i].bracket_->get_bound (LEFT)); + } + else + { + warning ("omitting tuplet bracket with neither left nor right bound"); + continue; + } + } + // 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 (); + + concat (tuplets_, new_tuplets_); + new_tuplets_.clear (); + for (vsize j = tuplets_.size (); j > 0; j--) + { + /* i goes from size-1 downto 0, inclusively */ + vsize i = j - 1; + if (tuplets_[i].bracket_) - continue; + continue; + + 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].music_->self_scm ()); + tuplets_[i].event_->self_scm ()); tuplets_[i].number_ = make_spanner ("TupletNumber", - tuplets_[i].music_->self_scm ()); + tuplets_[i].event_->self_scm ()); tuplets_[i].number_->set_object ("bracket", tuplets_[i].bracket_->self_scm ()); + tuplets_[i].number_->set_parent (tuplets_[i].bracket_, X_AXIS); + tuplets_[i].number_->set_parent (tuplets_[i].bracket_, Y_AXIS); 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_); + tuplets_[i].stop_moment_.grace_part_ = 0; + + if (i + 1 < tuplets_.size () && 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_); + if (i > 0 && 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); - } } } @@ -114,83 +206,94 @@ Tuplet_engraver::acknowledge_note_column (Grob_info inf) 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); + 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 () +Tuplet_engraver::acknowledge_script (Grob_info inf) { - Moment now = now_mom (); + for (vsize j = 0; j < tuplets_.size (); j++) + if (tuplets_[j].bracket_) + { + Item *i = dynamic_cast (inf.grob ()); + if (!i->internal_has_interface (ly_symbol2scm ("dynamic-interface"))) + Tuplet_bracket::add_script (tuplets_[j].bracket_, i); + } +} - last_tuplets_.clear (); - if (tuplets_.empty ()) - return; +void +Tuplet_engraver::acknowledge_finger (Grob_info inf) +{ + for (vsize j = 0; j < tuplets_.size (); j++) + if (tuplets_[j].bracket_) + { + Item *i = dynamic_cast (inf.grob ()); + Tuplet_bracket::add_script (tuplets_[j].bracket_, i); + } +} - Moment tsdmom = robust_scm2moment (get_property ("tupletSpannerDuration"), Moment (0)); - bool full_length = to_boolean (get_property ("tupletFullLength")); +void +Tuplet_engraver::acknowledge_string_number (Grob_info inf) +{ + for (vsize j = 0; j < tuplets_.size (); j++) + if (tuplets_[j].bracket_) + { + Item *i = dynamic_cast (inf.grob ()); + Tuplet_bracket::add_script (tuplets_[j].bracket_, i); + } +} - for (vsize i = tuplets_.size (); i--;) - { - Rational tsd = tsdmom.main_part_; - - if (now.main_part_ >= tuplets_[i].span_stop_) - { - if (tuplets_[i].bracket_) - { - if (full_length) - { - Item *col = unsmob_item (get_property ("currentMusicalColumn")); - - tuplets_[i].bracket_->set_bound (RIGHT, col); - tuplets_[i].number_->set_bound (RIGHT, col); - } - else if (!tuplets_[i].bracket_->get_bound (RIGHT)) - { - tuplets_[i].bracket_->set_bound (RIGHT, - tuplets_[i].bracket_->get_bound (LEFT)); - tuplets_[i].number_->set_bound (RIGHT, - tuplets_[i].bracket_->get_bound (LEFT)); - } - last_tuplets_.push_back (tuplets_[i].bracket_); - last_tuplets_.push_back (tuplets_[i].number_); - - tuplets_[i].bracket_ = 0; - tuplets_[i].number_ = 0; - } - - if (tsd) - tuplets_[i].span_stop_ += tsd; - } - - if (now.main_part_ >= tuplets_[i].stop_) - tuplets_.erase (tuplets_.begin () + i); - } +void +Tuplet_engraver::start_translation_timestep () +{ + last_tuplets_.clear (); + /* + May seem superfluous, but necessary for skipTypesetting. + */ + new_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); - } - } + for (vsize i = 0; i < last_tuplets_.size (); i++) + { + Item *col = unsmob (get_property ("currentCommandColumn")); + last_tuplets_[i]->set_bound (RIGHT, col); + } +} + +Tuplet_engraver::Tuplet_engraver (Context *c) + : Engraver (c) +{ } -Tuplet_engraver::Tuplet_engraver () +void +Tuplet_engraver::boot () { + ADD_LISTENER (Tuplet_engraver, tuplet_span); + ADD_ACKNOWLEDGER (Tuplet_engraver, note_column); + ADD_ACKNOWLEDGER (Tuplet_engraver, script); + ADD_ACKNOWLEDGER (Tuplet_engraver, finger); + ADD_ACKNOWLEDGER (Tuplet_engraver, string_number); } -ADD_ACKNOWLEDGER (Tuplet_engraver, note_column); ADD_TRANSLATOR (Tuplet_engraver, - /* doc */ "Catch Time_scaled_music and generate appropriate bracket ", - /* create */ "TupletBracket TupletNumber", - /* accept */ "time-scaled-music", - /* read */ "tupletNumberFormatFunction tupletSpannerDuration tupletFullLength", - /* write */ ""); + /* doc */ + "Catch tuplet events and generate appropriate bracket.", + + /* create */ + "TupletBracket " + "TupletNumber ", + + /* read */ + "tupletFullLength " + "tupletFullLengthNote ", + + /* write */ + "" + );