/*
- dynamic-reg.cc -- implement Dynamic_engraver
+ dynamic-engraver.cc -- implement Dynamic_engraver
source file of the GNU LilyPond music typesetter
(c) 1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
*/
#include "debug.hh"
+#include "dimensions.hh"
#include "crescendo.hh"
#include "musical-request.hh"
#include "lookup.hh"
#include "stem.hh"
#include "note-head.hh"
#include "group-interface.hh"
+#include "directional-element-interface.hh"
+#include "staff-symbol-referencer.hh"
+
+#define DYN_LINE
+
+#ifdef DYN_LINE
+
+class Dynamic_line_spanner : public Spanner
+{
+public:
+ Dynamic_line_spanner ();
+
+ void add_element (Score_element*);
+ void add_column (Note_column*);
+ Direction get_default_dir () const;
+
+protected:
+ virtual void do_add_processing ();
+ // URG: see Dynamic_engraver::do_removal_processing
+ friend class Dynamic_engraver;
+ virtual void do_post_processing ();
+
+private:
+ void translate_elements (Real);
+ Real get_extreme_y () const;
+};
+
+Dynamic_line_spanner::Dynamic_line_spanner ()
+{
+ set_elt_property ("transparent", SCM_BOOL_T);
+}
+
+void
+Dynamic_line_spanner::add_element (Score_element* e)
+{
+ Group_interface gi (this, "elements");
+ gi.add_element (e);
+ //?
+ Side_position_interface (e).set_axis (Y_AXIS);
+ add_dependency (e);
+}
+
+void
+Dynamic_line_spanner::add_column (Note_column* n)
+{
+ Group_interface gi (this, "note-columns");
+ gi.add_element (n);
+ add_dependency (n);
+}
+
+/*
+ Copied (urg: literally!) from slur.
+ Why not do this once, at post-processing stage?
+ */
+void
+Dynamic_line_spanner::do_add_processing ()
+{
+ Link_array<Note_column> encompass_arr =
+ Group_interface__extract_elements (this, (Note_column*)0, "note-columns");
+
+ if (encompass_arr.size ())
+ {
+ set_bounds (LEFT, encompass_arr[0]);
+ if (encompass_arr.size () > 1)
+ set_bounds (RIGHT, encompass_arr.top ());
+ }
+}
+
+#if 0
+Molecule
+Dynamic_line_spanner::do_brew_molecule () const
+{
+ return Molecule ();
+}
+#endif
+
+void
+Dynamic_line_spanner::do_post_processing ()
+{
+ translate_elements (get_extreme_y ());
+}
+
+void
+Dynamic_line_spanner::translate_elements (Real dy)
+{
+ SCM s = get_elt_property ("elements");
+ for (; gh_pair_p (s); s = gh_cdr (s))
+ {
+ Score_element* se = unsmob_element (gh_car (s));
+ se->translate_axis (dy, Y_AXIS);
+ }
+}
+
+Direction
+Dynamic_line_spanner::get_default_dir () const
+{
+ return DOWN;
+ //Direction dir = directional_element (this).get ();
+}
+
+Real
+Dynamic_line_spanner::get_extreme_y () const
+{
+ Link_array<Note_column> encompass_arr =
+ Group_interface__extract_elements (this, (Note_column*)0, "note-columns");
+
+ Staff_symbol_referencer_interface si (this);
+ int stafflines = si.line_count ();
+ //hurg?
+ stafflines = stafflines != 0 ? stafflines : 5;
+ Direction dir = get_default_dir ();
+
+ Real staff_space = si.staff_space ();
+ // burp? when are these available?
+ staff_space = staff_space != 0 ? staff_space : 5 PT;
+
+ // urg: TODO: padding
+ Real y = (stafflines / 2 + 1) * staff_space;
+
+ for (int i = 0; i < encompass_arr.size (); i++)
+ {
+ Note_column* column = encompass_arr[i];
+ Stem* stem = column->stem_l ();
+ if (stem)
+ {
+ Direction stem_dir = directional_element (stem).get ();
+ if ((stem_dir == dir)
+ && !stem->extent (Y_AXIS).empty_b ())
+ {
+ y = y >? (stem->extent (Y_AXIS)[dir]) * dir;
+ }
+ else
+ {
+ y = y >? (column->extent (Y_AXIS)[dir]) * dir;
+ }
+ }
+ }
+
+ return y * dir;
+}
+
+#endif
/*
TODO:
Span_req * cresc_req_l_;
Array<Request*> dynamic_req_l_arr_;
+
+#ifdef DYN_LINE
+ /*
+ We probably need two of these: line-up above and below staff
+ */
+ Dynamic_line_spanner* spanner_;
+ Moment last_request_mom_;
+#endif
+
void typeset_all ();
public:
VIRTUAL_COPY_CONS(Translator);
virtual void typeset_element (Score_element*);
};
+ADD_THIS_TRANSLATOR (Dynamic_engraver);
+
void
Dynamic_engraver::announce_element (Score_element_info i)
{
}
-Dynamic_engraver::Dynamic_engraver()
+Dynamic_engraver::Dynamic_engraver ()
{
do_post_move_processing();
abs_text_p_ = 0;
cr_text_p_ = 0;
to_end_cresc_p_ = cresc_p_ = 0;
cresc_req_l_ = 0;
+#ifdef DYN_LINE
+ spanner_ = 0;
+#endif
}
void
dynamic_req_l_arr_.clear();
}
+/*
+ ugr
+ */
bool
Dynamic_engraver::do_try_music (Music * m)
{
else
return false;
+#ifdef DYN_LINE
+ if (!spanner_)
+ spanner_ = new Dynamic_line_spanner;
+ last_request_mom_ = now_mom ();
+#endif
+
for (int i=0; i < dynamic_req_l_arr_.size (); i++)
if (r->equal_b (dynamic_req_l_arr_[i]))
return true;
abs_text_p_->set_elt_property ("script-priority",
gh_int2scm (100));
+#ifdef DYN_LINE
+ assert (spanner_);
+ spanner_->add_element (abs_text_p_);
+#else
Side_position_interface (abs_text_p_).set_axis (Y_AXIS);
-
if (absd->get_direction ())
{
{
abs_text_p_->set_elt_property ("padding", prop);
}
+#endif
announce_element (Score_element_info (abs_text_p_, absd));
+
}
else if (Span_req *span_l
= dynamic_cast <Span_req *> (dynamic_req_l_arr_[i]))
Side_position_interface (cr_text_p_).set_axis (X_AXIS);
Side_position_interface (cr_text_p_).add_support (abs_text_p_);
}
+
+#ifdef DYN_LINE
+ assert (spanner_);
+ spanner_->add_element (cr_text_p_);
+#endif
+
//Side_position_interface (cr_text_p_).set_axis (Y_AXIS);
announce_element (Score_element_info (cr_text_p_, span_l));
}
new_cresc_p->set_elt_property ("spanner", s);
}
+#ifdef DYN_LINE
+ assert (spanner_);
+ spanner_->add_element (new_cresc_p);
+#else
+ // what's the diff between side_position and Side_pos_iface?
side_position (new_cresc_p).set_axis (Y_AXIS);
+#endif
announce_element (Score_element_info (new_cresc_p, span_l));
}
}
RIGHT, SCM_BOOL_T);
}
}
+
}
void
typeset_all ();
}
-
-
-ADD_THIS_TRANSLATOR(Dynamic_engraver);
-
void
Dynamic_engraver::do_removal_processing ()
{
cresc_req_l_->warning (_ ("unended crescendo"));
cresc_p_ =0;
}
+#ifdef DYN_LINE
+ if (spanner_)
+ {
+ // URG urg. We did't get a post_processing call !?
+ spanner_->do_post_processing ();
+ typeset_element (spanner_);
+ spanner_ = 0;
+ }
+#endif
typeset_all ();
}
typeset_element (cr_text_p_);
cr_text_p_ = 0;
}
+#ifdef DYN_LINE
+ /*
+ TODO: This should be optionised:
+ * break when group of dynamic requests ends
+ * break now
+ * continue through piece
+ */
+ if (spanner_ && last_request_mom_ < now_mom ())
+ {
+ typeset_element (spanner_);
+ spanner_ = 0;
+ }
+#endif
}
void
Dynamic_engraver::typeset_element (Score_element * e)
{
+#ifndef DYN_LINE
side_position(e).add_staff_support ();
+#endif
Engraver::typeset_element (e);
}
+#ifdef DYN_LINE
+
+void
+Dynamic_engraver::acknowledge_element (Score_element_info i)
+{
+ if (spanner_)
+ {
+ if (Note_column* n = dynamic_cast<Note_column*> (i.elem_l_))
+ spanner_->add_column (n);
+ }
+}
+
+#else
+
void
Dynamic_engraver::acknowledge_element (Score_element_info i)
{
}
}
+#endif
};
/**
- handle perform span-dynamics
+ perform span-dynamics
*/
class Span_dynamic_performer : public Performer
{
virtual void do_pre_move_processing ();
private:
+ Audio_dynamic* audio_p_;
Drul_array<Span_req*> request_drul_;
- Drul_array<Moment> moment_drul_;
- Drul_array<int> volume_drul_;
Array<Audio_dynamic_tuple> dynamic_tuple_arr_;
-
- // BURP
- Drul_array<Moment> done_moment_drul_;
- Drul_array<int> done_volume_drul_;
- Array<Audio_dynamic_tuple> done_dynamic_tuple_arr_;
-
- Audio_dynamic* audio_p_;
+ Array<Audio_dynamic_tuple> finished_dynamic_tuple_arr_;
+ Direction finished_dir_;
};
ADD_THIS_TRANSLATOR (Span_dynamic_performer);
Span_dynamic_performer::Span_dynamic_performer ()
{
request_drul_[START] = request_drul_[STOP] = 0;
- volume_drul_[START] = volume_drul_[STOP] = 0;
audio_p_ = 0;
}
{
if (Audio_dynamic * d = dynamic_cast <Audio_dynamic*> (i.elem_l_))
{
- Direction dir = volume_drul_[START] ? STOP : START;
- volume_drul_[dir] = d->volume_i_;
- if (done_dynamic_tuple_arr_.size ())
- done_volume_drul_[STOP] = d->volume_i_;
-#if 0
Audio_dynamic_tuple a = { d, now_mom () };
+ if (!request_drul_[START])
+ dynamic_tuple_arr_.clear ();
dynamic_tuple_arr_.push (a);
-#endif
+ if (finished_dynamic_tuple_arr_.size ())
+ finished_dynamic_tuple_arr_.push (a);
}
}
void
Span_dynamic_performer::do_process_requests ()
{
- if (request_drul_[START])
- {
- audio_p_ = new Audio_dynamic (volume_drul_[START]);
- Audio_element_info info (audio_p_, 0);
- announce_element (info);
-
- Audio_dynamic_tuple a = { audio_p_, now_mom () };
- dynamic_tuple_arr_.push (a);
- }
-
- if (done_dynamic_tuple_arr_.size ())
+ if (finished_dynamic_tuple_arr_.size () > 1
+ && finished_dynamic_tuple_arr_.top ().audio_l_->volume_i_)
{
- if (done_volume_drul_[STOP])
+ Real start_volume = finished_dynamic_tuple_arr_[0].audio_l_->volume_i_;
+ Real dv = finished_dynamic_tuple_arr_.top ().audio_l_->volume_i_
+ - start_volume;
+ if (!dv)
+ {
+ // urg. about one volume step
+ dv = (int)finished_dir_ * 13;
+ if (!start_volume)
+ start_volume = finished_dynamic_tuple_arr_.top
+ ().audio_l_->volume_i_ - dv;
+ }
+ Moment start_mom = finished_dynamic_tuple_arr_[0].mom_;
+ Moment dt = finished_dynamic_tuple_arr_.top ().mom_ - start_mom;
+ for (int i=0; i < finished_dynamic_tuple_arr_.size (); i++)
{
- Real dv = done_volume_drul_[STOP] - done_volume_drul_[START];
- Moment dt = done_moment_drul_[STOP] - done_moment_drul_[START];
- for (int i=0; i < done_dynamic_tuple_arr_.size (); i++)
- {
- Real volume =
- (done_volume_drul_[START]
- + dv * (Real)(done_dynamic_tuple_arr_[i].mom_
- - done_moment_drul_[START]) / (Real)dt);
- done_dynamic_tuple_arr_[i].audio_l_->volume_i_ = (int)volume;
- }
+ Audio_dynamic_tuple* a = &finished_dynamic_tuple_arr_[i];
+ Real volume = start_volume + dv * (Real)(a->mom_ - start_mom)
+ / (Real)dt;
+ a->audio_l_->volume_i_ = (int)volume;
}
- done_dynamic_tuple_arr_.clear ();
+ finished_dynamic_tuple_arr_.clear ();
}
if (request_drul_[STOP])
{
- done_dynamic_tuple_arr_ = dynamic_tuple_arr_;
+ finished_dynamic_tuple_arr_ = dynamic_tuple_arr_;
+ finished_dir_ = request_drul_[STOP]->span_type_str_ == "crescendo"
+ ? RIGHT : LEFT;
dynamic_tuple_arr_.clear ();
- done_volume_drul_[START] = volume_drul_[START];
- done_volume_drul_[STOP] = volume_drul_[STOP];
- done_moment_drul_[START] = moment_drul_[START];
- done_moment_drul_[STOP] = moment_drul_[STOP];
+ if (finished_dynamic_tuple_arr_.size ())
+ dynamic_tuple_arr_.push (finished_dynamic_tuple_arr_.top ());
request_drul_[STOP] = 0;
- volume_drul_[START] = volume_drul_[STOP];
- volume_drul_[STOP] = 0;
+ request_drul_[START] = 0;
+ }
+
+ if (request_drul_[START])
+ {
+ audio_p_ = new Audio_dynamic (0);
+ Audio_element_info info (audio_p_, 0);
+ announce_element (info);
+
+ Audio_dynamic_tuple a = { audio_p_, now_mom () };
+ dynamic_tuple_arr_.push (a);
}
}
return false;
}
request_drul_[d] = s;
- moment_drul_[d] = now_mom ();
- if (d == START && volume_drul_[STOP])
- volume_drul_[START] = volume_drul_[STOP];
return true;
}
return false;