--- /dev/null
+/*
+ dynamic-align-engraver.cc -- implement Dynamic_align_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2008 Han-Wen Nienhuys <hanwen@lilypond.org>
+
+*/
+
+#include <set>
+
+#include "engraver.hh"
+
+#include "axis-group-interface.hh"
+#include "directional-element-interface.hh"
+#include "item.hh"
+#include "side-position-interface.hh"
+#include "spanner.hh"
+#include "stream-event.hh"
+
+#include "translator.icc"
+
+class Dynamic_align_engraver : public Engraver
+{
+ TRANSLATOR_DECLARATIONS (Dynamic_align_engraver);
+ DECLARE_ACKNOWLEDGER (note_column);
+ DECLARE_ACKNOWLEDGER (dynamic);
+ DECLARE_END_ACKNOWLEDGER (dynamic);
+
+protected:
+ virtual void stop_translation_timestep ();
+
+private:
+ void create_line_spanner (Stream_event *cause);
+ Spanner* line_;
+
+ vector<Spanner*> ended_;
+ vector<Spanner*> started_;
+ vector<Grob*> scripts_;
+ vector<Grob*> support_;
+
+ set<Spanner*> running_;
+};
+
+Dynamic_align_engraver::Dynamic_align_engraver ()
+{
+ line_ = 0;
+}
+
+ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
+ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column);
+ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
+
+void
+Dynamic_align_engraver::create_line_spanner (Stream_event* event)
+{
+ if (!line_)
+ line_ = make_spanner ("DynamicLineSpanner",
+ event ? event->self_scm() : SCM_EOL);
+}
+
+void
+Dynamic_align_engraver::acknowledge_end_dynamic (Grob_info info)
+{
+ if (Spanner::has_interface(info.grob()))
+ ended_.push_back (info.spanner ());
+}
+
+void
+Dynamic_align_engraver::acknowledge_note_column (Grob_info info)
+{
+ support_.push_back (info.grob ());
+}
+
+void
+Dynamic_align_engraver::acknowledge_dynamic (Grob_info info)
+{
+ Stream_event *cause = info.event_cause ();
+ create_line_spanner (cause);
+ if (Spanner::has_interface(info.grob()))
+ started_.push_back (info.spanner ());
+ else if (info.item())
+ scripts_.push_back (info.item());
+ else
+ info.grob ()->programming_error ("Unknown dynamic grob.");
+
+ Axis_group_interface::add_element (line_, info.grob ());
+
+ if (cause)
+ {
+ if (Direction d = to_dir (cause->get_property ("direction")))
+ set_grob_direction (line_, d);
+ }
+}
+
+void
+Dynamic_align_engraver::stop_translation_timestep ()
+{
+ for (vsize i = 0; i < started_.size(); i++)
+ running_.insert (started_[i]);
+ for (vsize i = 0; i < ended_.size(); i++)
+ {
+ Spanner *sp = ended_[i];
+
+ set<Spanner*>::iterator it = running_.find (sp);
+ if (it != running_.end())
+ running_.erase (it);
+ else
+ started_[i]->programming_error ("Lost track of this dynamic spanner.");
+ }
+
+ bool end = line_ && running_.empty ();
+ Direction d = LEFT;
+ do
+ {
+ if (line_
+ && ((d == LEFT && !line_->get_bound (LEFT))
+ || (end && d == RIGHT && !line_->get_bound (RIGHT))))
+ {
+ vector<Spanner*> const &spanners =
+ (d == LEFT) ? started_ : ended_;
+
+ Grob *bound = 0;
+ if (scripts_.size())
+ bound = scripts_[0];
+ else if (spanners.size())
+ bound = spanners[0]->get_bound (d);
+ else
+ {
+ programming_error ("Started DynamicLineSpanner but have no left bound.");
+ bound = unsmob_grob (get_property ("currentMusicalColumn"));
+ }
+
+ line_->set_bound (d, bound);
+ }
+ }
+ while (flip (&d) != LEFT);
+
+ for (vsize i = 0; line_ && i < support_.size (); i++)
+ Side_position_interface::add_support (line_, support_[i]);
+
+ if (end)
+ line_ = 0;
+
+ ended_.clear ();
+ started_.clear ();
+ scripts_.clear ();
+ support_.clear ();
+}
+
+
+ADD_TRANSLATOR (Dynamic_align_engraver,
+ /* doc */
+ "Align hairpins and dynamic texts on a horizontal line",
+
+ /* create */
+ "DynamicLineSpanner ",
+
+ /* read */
+ "currentMusicalColumn ",
+
+ /* write */
+ ""
+ );
--- /dev/null
+/*
+ new-dynamic-engraver.cc -- implement New_dynamic_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2008 Han-Wen Nienhuys <hanwen@lilypond.org>
+
+*/
+
+
+#include "engraver.hh"
+
+#include "item.hh"
+#include "pointer-group-interface.hh"
+#include "text-interface.hh"
+#include "note-column.hh"
+#include "self-alignment-interface.hh"
+#include "spanner.hh"
+#include "stream-event.hh"
+
+#include "translator.icc"
+
+class New_dynamic_engraver : public Engraver
+{
+ TRANSLATOR_DECLARATIONS (New_dynamic_engraver);
+ DECLARE_ACKNOWLEDGER (note_column);
+ DECLARE_TRANSLATOR_LISTENER (absolute_dynamic);
+ DECLARE_TRANSLATOR_LISTENER (span_dynamic);
+
+protected:
+ virtual void process_music ();
+ virtual void stop_translation_timestep ();
+private:
+ Drul_array<Stream_event *> accepted_spanevents_drul_;
+ Spanner *current_spanner_;
+ Spanner *finished_spanner_;
+
+ Item *script_;
+ Stream_event *script_event_;
+ Stream_event *current_span_event_;
+};
+
+New_dynamic_engraver::New_dynamic_engraver ()
+{
+ script_event_ = 0;
+ current_span_event_ = 0;
+ script_ = 0;
+ finished_spanner_ = 0;
+ current_spanner_ = 0;
+ accepted_spanevents_drul_.set (0, 0);
+}
+
+IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, absolute_dynamic);
+void
+New_dynamic_engraver::listen_absolute_dynamic (Stream_event *ev)
+{
+ ASSIGN_EVENT_ONCE (script_event_, ev);
+}
+
+IMPLEMENT_TRANSLATOR_LISTENER (New_dynamic_engraver, span_dynamic);
+void
+New_dynamic_engraver::listen_span_dynamic (Stream_event *ev)
+{
+ Direction d = to_dir (ev->get_property ("span-direction"));
+
+ ASSIGN_EVENT_ONCE (accepted_spanevents_drul_[d], ev);
+}
+
+
+void
+New_dynamic_engraver::process_music ()
+{
+ if (current_spanner_
+ && (accepted_spanevents_drul_[STOP] || script_event_ || accepted_spanevents_drul_[START]))
+ {
+ Stream_event* ender = accepted_spanevents_drul_[STOP];
+ if (!ender)
+ ender = script_event_;
+
+ if (!ender)
+ ender = accepted_spanevents_drul_[START];
+
+ finished_spanner_ = current_spanner_;
+ announce_end_grob (finished_spanner_, ender->self_scm ());
+ current_spanner_ = 0;
+ current_span_event_ = 0;
+ }
+
+ if (accepted_spanevents_drul_[START])
+ {
+ current_span_event_ = accepted_spanevents_drul_[START];
+
+ SCM start_sym = current_span_event_->get_property ("class");
+ string start_type;
+
+ if (start_sym == ly_symbol2scm ("decrescendo-event"))
+ start_type = "decrescendo";
+ else if (start_sym == ly_symbol2scm ("crescendo-event"))
+ start_type = "crescendo";
+ else
+ {
+ programming_error ("unknown dynamic spanner type");
+ return;
+ }
+
+ SCM cresc_type = get_property ((start_type + "Spanner").c_str ());
+
+ if (cresc_type == ly_symbol2scm ("text"))
+ {
+ current_spanner_
+ = make_spanner ("DynamicTextSpanner",
+ accepted_spanevents_drul_[START]->self_scm ());
+
+ SCM text = get_property ((start_type + "Text").c_str ());
+ if (Text_interface::is_markup (text))
+ {
+ current_spanner_->set_property ("text", text);
+ }
+ }
+ else
+ {
+ if (cresc_type != ly_symbol2scm ("hairpin"))
+ {
+ // Fixme: should put value in error message.
+ ly_display_scm (cresc_type);
+ current_span_event_
+ ->origin()->warning ("unknown crescendo style; defaulting to hairpin.");
+ }
+ current_spanner_ = make_spanner ("Hairpin",
+ current_span_event_->self_scm ());
+ if (finished_spanner_)
+ {
+ Pointer_group_interface::add_grob (finished_spanner_,
+ ly_symbol2scm ("adjacent-hairpins"),
+ current_spanner_);
+
+ Pointer_group_interface::add_grob (current_spanner_,
+ ly_symbol2scm ("adjacent-hairpins"),
+ finished_spanner_);
+ }
+ }
+ }
+
+ if (script_event_)
+ {
+ script_ = make_item ("DynamicText", script_event_->self_scm ());
+ script_->set_property ("text",
+ script_event_->get_property ("text"));
+
+ if (finished_spanner_)
+ finished_spanner_->set_bound (RIGHT, script_);
+ if (current_spanner_)
+ {
+ current_spanner_->set_bound (LEFT, script_);
+ set_nested_property (current_spanner_,
+ scm_list_3 (ly_symbol2scm ("bound-details"),
+ ly_symbol2scm ("left"),
+ ly_symbol2scm ("attach-dir")
+ ),
+ scm_from_int (RIGHT));
+
+ }
+ }
+}
+
+
+
+void
+New_dynamic_engraver::stop_translation_timestep ()
+{
+ if (finished_spanner_ && !finished_spanner_->get_bound (RIGHT))
+ finished_spanner_->set_bound (RIGHT,
+ unsmob_grob (get_property ("currentMusicalColumn")));
+
+ if (current_spanner_ && !current_spanner_->get_bound (LEFT))
+ current_spanner_->set_bound (LEFT,
+ unsmob_grob (get_property ("currentMusicalColumn")));
+ script_ = 0;
+ script_event_ = 0;
+ accepted_spanevents_drul_.set (0, 0);
+ finished_spanner_ = 0;
+}
+
+void
+New_dynamic_engraver::acknowledge_note_column (Grob_info info)
+{
+ if (script_ && !script_->get_parent (X_AXIS))
+ {
+ extract_grob_set (info.grob (), "note-heads", heads);
+ if (heads.size ())
+ {
+ Grob *head = heads[0];
+ script_->set_parent (head, X_AXIS);
+ Self_alignment_interface::set_center_parent (script_, X_AXIS);
+ }
+ }
+
+ if (current_spanner_ && !current_spanner_->get_bound (LEFT))
+ current_spanner_->set_bound (LEFT, info.grob ());
+ if (finished_spanner_ && !finished_spanner_->get_bound (RIGHT))
+ finished_spanner_->set_bound (RIGHT, info.grob ());
+}
+
+ADD_ACKNOWLEDGER (New_dynamic_engraver, note_column);
+ADD_TRANSLATOR (New_dynamic_engraver,
+ /* doc */
+ "Create hairpins, dynamic texts, and their vertical"
+ " alignments. The symbols are collected onto a"
+ " @code{DynamicLineSpanner} grob which takes care of vertical"
+ " positioning.",
+
+ /* create */
+ "DynamicTextSpanner "
+ "DynamicText "
+ "Hairpin "
+ "TextSpanner ",
+
+ /* read */
+ "currentMusicalColumn x",
+
+ /* write */
+ ""
+ );