]> git.donarmstrong.com Git - lilypond.git/commitdiff
New dynamics engravers
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Fri, 2 May 2008 02:22:26 +0000 (23:22 -0300)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Fri, 2 May 2008 02:22:26 +0000 (23:22 -0300)
  Dynamic_align_engraver
  New_dynamic_engraver

The New_dynamic_engraver handles creation of (de)crescendi and scripts
while Dynamic_align_engraver is responsible for the spanner that keeps
related dynamics on a single line.

lily/dynamic-align-engraver.cc [new file with mode: 0644]
lily/new-dynamic-engraver.cc [new file with mode: 0644]
ly/engraver-init.ly
ly/spanners-init.ly

diff --git a/lily/dynamic-align-engraver.cc b/lily/dynamic-align-engraver.cc
new file mode 100644 (file)
index 0000000..77feb08
--- /dev/null
@@ -0,0 +1,164 @@
+/* 
+  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 */
+               ""
+               );
diff --git a/lily/new-dynamic-engraver.cc b/lily/new-dynamic-engraver.cc
new file mode 100644 (file)
index 0000000..0db0587
--- /dev/null
@@ -0,0 +1,223 @@
+/* 
+  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 */
+               ""
+               );
index c2239ec05424d3816f086e3296d4ffe5ea7a4de6..480a1ad6dc8551b8a629fc0eab5602c149549ebe 100644 (file)
@@ -222,7 +222,9 @@ multiple voices on the same staff."
   \consists "Part_combine_engraver"
 
   \consists "Text_engraver"
-  \consists "Dynamic_engraver"
+  \consists "New_dynamic_engraver"
+  \consists "Dynamic_align_engraver"
+%  \consists "Dynamic_engraver"
   \consists "Fingering_engraver"
   \consists "Bend_engraver"
 
@@ -505,6 +507,9 @@ automatically when an output definition (a @code{\score} or
   middleCClefPosition = #-6
   middleCPosition = #-6
   firstClef = ##t
+
+  crescendoSpanner = #'hairpin
+  decrescendoSpanner = #'hairpin
   
   defaultBarType = #"|"
   barNumberVisibility = #first-bar-number-invisible
index 60989ede0cd2ed21a70613b7cbe4060d62f4f90a..1425b22b14954315deea2483a50c4b3a110e737e 100644 (file)
@@ -51,31 +51,38 @@ endcresc =  {
 
 setTextCresc = {
     \set crescendoText = \markup { \italic "cresc." }
-    \set crescendoSpanner = #'dashed-line
+    \set crescendoSpanner = #'text
+    \override DynamicTextSpanner #'style = #'dashed-line
 }
 
 setTextDecresc = {
     \set decrescendoText = \markup { \italic "decresc." }
-    \set decrescendoSpanner = #'dashed-line
+    \set decrescendoSpanner = #'text
+    \override DynamicTextSpanner #'style = #'dashed-line
 }
 
 setTextDecr = {
     \set decrescendoText = \markup { \italic "decr." }
-    \set decrescendoSpanner = #'dashed-line
+    \set decrescendoSpanner = #'text
+    \override DynamicTextSpanner #'style = #'dashed-line
 }
 
 setTextDim = {
     \set decrescendoText = \markup { \italic "dim." }
-    \set decrescendoSpanner = #'dashed-line
+    \set decrescendoSpanner = #'text
+    \override DynamicTextSpanner #'style = #'dashed-line
 }
+
 setHairpinCresc = {
     \unset crescendoText 
     \unset crescendoSpanner 
 }
+
 setHairpinDecresc = {
     \unset decrescendoText 
     \unset decrescendoSpanner 
 }
+
 setHairpinDim = {
     \unset decrescendoText 
     \unset decrescendoSpanner