--- /dev/null
+\score{
+\notes\relative c''{
+%segfault in engraver
+a1\ppp
+a1\pp
+a\p
+a\mp
+a\mf
+a\f
+a\ff
+a\fff
+a\sf
+}
+\paper{
+}
+\midi{
+\tempo 1 = 60;
+}
+}
--- /dev/null
+\score{
+\notes\relative c''{
+a1\fff\< \!a
+a\> \!a
+\property Voice.crescendoText = "cresc."
+\property Voice.crescendoSpanner = "dashed-line"
+a\mf\cresc \endcresc a
+%a\decresc \enddecresc a
+a1\< \!a
+a\> \!a
+}
+\paper{
+}
+\midi{
+\tempo 1 = 60;
+}
+}
--- /dev/null
+\score{
+\notes\relative c''{
+a1\ppp\<
+a
+a
+a
+a
+a
+a
+\!a\fff
+}
+\paper{
+}
+\midi{
+\tempo 1 = 60;
+}
+}
key_ = k;
}
+Audio_dynamic::Audio_dynamic (int volume)
+{
+ volume_i_ = volume;
+}
+
Audio_tempo::Audio_tempo (int per_minute_4_i)
{
per_minute_4_i_ = per_minute_4_i;
Drul_array<bool> broken;
Direction d = LEFT;
- do {
- Paper_column* s = dynamic_cast<Paper_column*>(spanned_drul_[d]); // UGH
- broken[d] = (!s->musical_b ());
- } while (flip (&d) != LEFT);
+ do
+ {
+ Paper_column* s = dynamic_cast<Paper_column*>(spanned_drul_[d]); // UGH
+ broken[d] = (!s->musical_b ());
+ }
+ while (flip (&d) != LEFT);
- bool continued = broken[Direction (-gd)];
- Real height = paper_l()->get_var ("crescendo_height");
- Real thick = paper_l ()->get_var ("crescendo_thickness");
-
- const char* hairpin = (gd < 0)? "decrescendo" : "crescendo";
-
- Box b (Interval (0, width),
- Interval (-2*height, 2*height));
-
- SCM at = gh_list (ly_symbol2scm (hairpin),
- gh_double2scm (thick),
- gh_double2scm (width),
- gh_double2scm (height),
- gh_double2scm (continued ? height/2 : 0.0),
- SCM_UNDEFINED);
-
+ SCM at;
+ SCM s = get_elt_property ("spanner");
+ Real height;
+ if (gh_string_p (s) && ly_scm2string (s) == "dashed-line")
+ {
+ Real thick = paper_l ()->get_var ("crescendo_dash_thickness");
+ Real dash = paper_l ()->get_var ("crescendo_dash");
+ height = thick;
+ at = gh_list (ly_symbol2scm (ly_scm2string (s).ch_C ()),
+ gh_double2scm (thick),
+ gh_double2scm (dash),
+ gh_double2scm (width),
+ SCM_UNDEFINED);
+ }
+ else
+ {
+ bool continued = broken[Direction (-gd)];
+ height = paper_l()->get_var ("crescendo_height");
+ Real thick = paper_l ()->get_var ("crescendo_thickness");
+
+ const char* hairpin = (gd < 0)? "decrescendo" : "crescendo";
+
+ at = gh_list (ly_symbol2scm (hairpin),
+ gh_double2scm (thick),
+ gh_double2scm (width),
+ gh_double2scm (height),
+ gh_double2scm (continued ? height/2 : 0.0),
+ SCM_UNDEFINED);
+ }
+
+ Box b (Interval (0, width), Interval (-2*height, 2*height));
Molecule m (b, at);
m.translate_axis (extra_left, X_AXIS);
#include "note-head.hh"
#include "group-interface.hh"
+/*
+ TODO:
+ * why handle absolute and span requests in one cryptic engraver,
+ what about Span_dynamic_engraver?
+
+ * hairpin
+ * text:
+ - `cresc. -- -- --'
+ - `cresc. poco a poco -- -- --'
+ */
+
/**
print text & hairpin dynamics.
*/
class Dynamic_engraver : public Engraver
{
- Text_item * text_p_;
+ Text_item * abs_text_p_;
+ Text_item * cr_text_p_;
Crescendo * to_end_cresc_p_;
Crescendo * cresc_p_;
Dynamic_engraver::Dynamic_engraver()
{
do_post_move_processing();
- text_p_ =0;
-
+ abs_text_p_ = 0;
+ cr_text_p_ = 0;
to_end_cresc_p_ = cresc_p_ = 0;
-
cresc_req_l_ = 0;
}
if (Text_script_req *absd =
dynamic_cast<Text_script_req *> ( dynamic_req_l_arr_[i]))
{
- if (text_p_)
+ if (abs_text_p_)
{
dynamic_req_l_arr_[i]->warning (_("Got a dynamic already. Continuing dazed and confused."));
continue;
String loud = absd->text_str_;
- text_p_ = new Text_item;
- text_p_->set_elt_property ("text",
+ abs_text_p_ = new Text_item;
+ abs_text_p_->set_elt_property ("text",
ly_str02scm (loud.ch_C()));
- text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
- text_p_->set_elt_property ("script-priority",
+ abs_text_p_->set_elt_property ("style", gh_str02scm ("dynamic"));
+ abs_text_p_->set_elt_property ("script-priority",
gh_int2scm (100));
- Side_position_interface (text_p_).set_axis (Y_AXIS);
+ Side_position_interface (abs_text_p_).set_axis (Y_AXIS);
if (absd->get_direction ())
{
- text_p_->set_elt_property ("direction", gh_int2scm (absd->get_direction ()));
+ abs_text_p_->set_elt_property ("direction", gh_int2scm (absd->get_direction ()));
}
}
if (isdir_b (prop) && to_dir (prop))
- text_p_->set_elt_property ("direction", prop);
+ abs_text_p_->set_elt_property ("direction", prop);
prop = get_property ("dynamicPadding");
if (gh_number_p(prop))
{
- text_p_->set_elt_property ("padding", prop);
+ abs_text_p_->set_elt_property ("padding", prop);
}
- announce_element (Score_element_info (text_p_, absd));
+ announce_element (Score_element_info (abs_text_p_, absd));
}
else if (Span_req *span_l
= dynamic_cast <Span_req *> (dynamic_req_l_arr_[i]))
cresc_req_l_ = span_l;
assert (!new_cresc_p);
new_cresc_p = new Crescendo;
- new_cresc_p
- ->set_elt_property ("grow-direction",
- gh_int2scm ((span_l->span_type_str_ == "crescendo") ? BIGGER : SMALLER));
+ new_cresc_p->set_elt_property
+ ("grow-direction",
+ gh_int2scm ((span_l->span_type_str_ == "crescendo")
+ ? BIGGER : SMALLER));
+ SCM s = get_property (span_l->span_type_str_ + "Text");
+ if (gh_string_p (s))
+ {
+ cr_text_p_ = new Text_item;
+ cr_text_p_->set_elt_property ("text", s);
+ // urg
+ cr_text_p_->set_elt_property ("style", gh_str02scm ("italic"));
+ // ?
+ cr_text_p_->set_elt_property ("script-priority",
+ gh_int2scm (100));
+
+ /*
+ This doesn't work.
+ I'd like to have support like this:
+ |
+ x|
+ cresc. - - -
+
+ or
+ |
+ x|
+ ff cresc. - - -
+
+ */
+ if (0) //abs_text_p_)
+ {
+ Side_position_interface (cr_text_p_).set_axis (X_AXIS);
+ Side_position_interface (cr_text_p_).add_support (abs_text_p_);
+ }
+ //Side_position_interface (cr_text_p_).set_axis (Y_AXIS);
+ announce_element (Score_element_info (cr_text_p_, span_l));
+ }
+
+ s = get_property (span_l->span_type_str_ + "Spanner");
+ if (gh_string_p (s)) //&& ly_scm2string (s) != "hairpin")
+ {
+ new_cresc_p->set_elt_property ("spanner", s);
+ }
+
side_position (new_cresc_p).set_axis (Y_AXIS);
announce_element (Score_element_info (new_cresc_p, span_l));
}
cresc_p_ = new_cresc_p;
cresc_p_->set_bounds(LEFT,get_staff_info().musical_pcol_l ());
- if (text_p_)
+ // arrragh, brr, urg: we know how wide text is, no?
+ if (abs_text_p_)
{
index_set_cell (cresc_p_->get_elt_property ("dynamic-drul"),
LEFT, SCM_BOOL_T);
}
- if (text_p_)
+ if (abs_text_p_)
{
- typeset_element (text_p_);
- text_p_ =0;
+ typeset_element (abs_text_p_);
+ abs_text_p_ = 0;
+ }
+
+ if (cr_text_p_)
+ {
+ typeset_element (cr_text_p_);
+ cr_text_p_ = 0;
}
}
|| dynamic_cast<Note_head *> (i.elem_l_)
)
{
- if (text_p_)
- Side_position_interface (text_p_).add_support (i.elem_l_);
+ if (abs_text_p_)
+ Side_position_interface (abs_text_p_).add_support (i.elem_l_);
+
+ if (cr_text_p_) ///&& !abs_text_p_)
+ {
+ Side_position_interface (cr_text_p_).set_axis (Y_AXIS);
+ Side_position_interface (cr_text_p_).add_support (i.elem_l_);
+ }
if (to_end_cresc_p_)
Side_position_interface (to_end_cresc_p_).add_support (i.elem_l_);
--- /dev/null
+/*
+ dynamic-performer.cc -- implement Dynamic_performer
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#include "performer.hh"
+#include "command-request.hh"
+#include "musical-request.hh"
+#include "audio-item.hh"
+
+/*
+ TODO:
+ handle multiple requests
+ handle span requests (crescendo/decrescendo)
+ */
+
+/**
+ perform absolute (text) dynamics
+ */
+class Dynamic_performer : public Performer
+{
+public:
+ VIRTUAL_COPY_CONS (Translator);
+
+ Dynamic_performer ();
+ ~Dynamic_performer ();
+
+protected:
+ void do_print () const;
+ virtual bool do_try_music (Music* req_l);
+ virtual void do_process_requests ();
+ virtual void do_pre_move_processing ();
+
+private:
+ Text_script_req* text_script_req_l_;
+ Audio_dynamic* audio_p_;
+};
+
+ADD_THIS_TRANSLATOR (Dynamic_performer);
+
+Dynamic_performer::Dynamic_performer ()
+{
+ text_script_req_l_ = 0;
+ audio_p_ = 0;
+}
+
+Dynamic_performer::~Dynamic_performer ()
+{
+}
+
+void
+Dynamic_performer::do_print () const
+{
+#ifndef NPRINT
+ if (text_script_req_l_)
+ text_script_req_l_->print ();
+#endif
+}
+
+void
+Dynamic_performer::do_process_requests ()
+{
+ if (text_script_req_l_)
+ {
+
+ SCM s = scm_eval
+ (gh_list
+ (ly_symbol2scm ("dynamic-absolute-volume"),
+ ly_quote_scm (ly_str02scm (text_script_req_l_->text_str_.ch_C ())),
+ SCM_UNDEFINED));
+ int volume = gh_scm2int (ly_eval_str ("dynamic-default-volume"));
+ if (gh_number_p (s))
+ volume = gh_scm2int (s);
+
+ audio_p_ = new Audio_dynamic (volume);
+ Audio_element_info info (audio_p_, text_script_req_l_);
+ announce_element (info);
+ text_script_req_l_ = 0;
+ }
+}
+
+void
+Dynamic_performer::do_pre_move_processing ()
+{
+ if (audio_p_)
+ {
+ play_element (audio_p_);
+ audio_p_ = 0;
+ }
+}
+
+bool
+Dynamic_performer::do_try_music (Music* r)
+{
+ if (!text_script_req_l_)
+ {
+ // urg, text script, style `dynamic' is how absolute dynamics appear
+ if(Text_script_req* t = dynamic_cast <Text_script_req*> (r))
+ {
+ if (t->style_str_ == "dynamic")
+ {
+ text_script_req_l_ = t;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
Audio_item& operator=( Audio_item const&);
};
+class Audio_dynamic : public Audio_item
+{
+public:
+ Audio_dynamic (int volume);
+
+ int volume_i_;
+};
+
class Audio_key : public Audio_item
{
public:
struct All_font_metrics;
struct Articulation_req;
struct Audio_column;
+struct Audio_dynamic;
struct Audio_element;
struct Audio_element_info;
struct Audio_instrument;
struct Command_tie_engraver;
struct Crescendo ;
struct Dimension_cache;
+struct Dynamic_performer;
struct Spanner;
struct Dot_column;
struct Dots;
struct Melodic_req;
struct Midi_def;
struct Midi_duration;
+struct Midi_dynamic;
struct Midi_header;
struct Midi_item;
struct Midi_key;
struct Single_malt_grouping_item;
struct Skip_req;
struct Slur;
+struct Slur_bezier_bow;
struct Slur_engraver;
struct Spacing_spanner;
struct Span_bar;
Audio_text* audio_l_;
};
+class Midi_dynamic : public Midi_item
+{
+public:
+ Midi_dynamic (Audio_dynamic*);
+
+ virtual String str () const;
+
+ Audio_dynamic* audio_l_;
+};
+
class Midi_tempo : public Midi_item
{
public:
Array<Rod> get_rods () const;
private:
- void de_uglyfy (class Slur_bezier_bow* bb, Real default_height);
+ void de_uglyfy (Slur_bezier_bow* bb, Real default_height);
void set_extremities ();
void set_control_points ();
int cross_staff_count () const;
return i->str_.length_i () ? new Midi_instrument (i) : 0;
else if (Audio_note* i = dynamic_cast<Audio_note*> (a))
return new Midi_note (i);
+ else if (Audio_dynamic* i = dynamic_cast<Audio_dynamic*> (a))
+ return new Midi_dynamic (i);
else if (Audio_tempo* i = dynamic_cast<Audio_tempo*> (a))
return new Midi_tempo (i);
else if (Audio_time_signature* i = dynamic_cast<Audio_time_signature*> (a))
return str;
}
+Midi_dynamic::Midi_dynamic (Audio_dynamic* a)
+{
+ audio_l_ = a;
+}
+
+String
+Midi_dynamic::str () const
+{
+ Byte status_byte = (char) (0xB0 + channel_i_);
+ String str = to_str ((char)status_byte);
+
+ /*
+ Main volume controller (per channel):
+ 07 MSB
+ 27 LSB
+ */
+ str += to_str ((char)0x07);
+ str += to_str ((char)audio_l_->volume_i_);
+ return str;
+}
+
Midi_tempo::Midi_tempo (Audio_tempo* a)
{
audio_l_ = a;
--- /dev/null
+/*
+ span-dynamic-performer.cc -- implement Span_dynamic_performer
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#include "performer.hh"
+#include "command-request.hh"
+#include "musical-request.hh"
+#include "audio-item.hh"
+
+struct Audio_dynamic_tuple
+{
+ Audio_dynamic* audio_l_;
+ Moment mom_;
+};
+
+/**
+ handle perform span-dynamics
+ */
+class Span_dynamic_performer : public Performer
+{
+public:
+ VIRTUAL_COPY_CONS (Translator);
+
+ Span_dynamic_performer ();
+
+protected:
+ virtual bool do_try_music (Music* req_l);
+ virtual void acknowledge_element (Audio_element_info);
+ virtual void do_process_requests ();
+ virtual void do_pre_move_processing ();
+
+private:
+ 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_;
+};
+
+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;
+}
+
+void
+Span_dynamic_performer::acknowledge_element (Audio_element_info i)
+{
+ 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 () };
+ dynamic_tuple_arr_.push (a);
+#endif
+ }
+}
+
+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 (done_volume_drul_[STOP])
+ {
+ 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;
+ }
+ }
+ done_dynamic_tuple_arr_.clear ();
+ }
+
+ if (request_drul_[STOP])
+ {
+ done_dynamic_tuple_arr_ = dynamic_tuple_arr_;
+ 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];
+ request_drul_[STOP] = 0;
+ volume_drul_[START] = volume_drul_[STOP];
+ volume_drul_[STOP] = 0;
+ }
+}
+
+void
+Span_dynamic_performer::do_pre_move_processing ()
+{
+ if (audio_p_)
+ {
+ play_element (audio_p_);
+ audio_p_ = 0;
+ }
+}
+
+bool
+Span_dynamic_performer::do_try_music (Music* r)
+{
+ if (Span_req * s = dynamic_cast<Span_req*>(r))
+ {
+ if (s-> span_type_str_ != "crescendo"
+ && s->span_type_str_ != "decrescendo")
+ return false;
+
+ Direction d = s->span_dir_;
+
+ if (d == STOP && !request_drul_[START])
+ {
+ r->warning (_ ("No (de)crescendo to end"));
+ 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;
+}
bool
Tie_performer::do_try_music (Music *m)
{
- if (Tie_req * c = dynamic_cast<Tie_req*> (m))
+ if (!req_l_)
{
- req_l_ = c;
- return true;
+ if (Tie_req * c = dynamic_cast<Tie_req*> (m))
+ {
+ req_l_ = c;
+ return true;
+ }
}
return false;
}
+#(eval-string (ly-gulp-file "midi.scm"))
+
\midi {
\tempo 4=60;
\include "performer.ly"
crescendo_shorten = 4.0 * \staffspace;
crescendo_thickness = \stafflinethickness;
crescendo_height = 0.666 * \staffspace;
+crescendo_dash_thickness = 1.2*\stafflinethickness;
+crescendo_dash = 4.0*\staffspace;
% in internote.
restcollision_minimum_dist = 3.0;
\consists "Key_performer";
\consists "Time_signature_performer";
\consists "Tempo_performer";
+% \consists "Span_dynamic_performer";
+ dynamicStyle = #"dynamic"
};
\translator { \StaffContext }
\type "Performer_group_performer";
\name Voice;
% All notes fall to Grace if you leave Thread out (huh?)
+ \consists "Dynamic_performer"; % must come before text_engraver.
+ \consists "Span_dynamic_performer";
\consists "Grace_position_performer";
\accepts Thread;
\accepts Grace;
emptyText = \property Voice.textEmptyDimension = ##t
fatText = \property Voice.textEmptyDimension = ##f
+
decr = \spanrequest \start "decrescendo"
rc = \spanrequest \stop "crescendo"
rced = \spanrequest \stop "decrescendo"
+
+%% urg, these don't work yet.
+xcresc = {
+%\spanrequest \start "crescendo"
+\property Voice.crescendoText = "cresc."
+\property Voice.crescendoSpanner = "dashed"
+}
+
+xendcresc = {
+%\spanrequest \start "crescendo"
+\property Voice.crescendoText = ##f
+\property Voice.crescendoSpanner = ##f
+}
+
+cresc = \spanrequest \start "crescendo"
+endcresc = \spanrequest \stop "crescendo"
+
+%crescpoco = \property Voice.crescendoText = "cresc. poco a poco"
+%decresc = \property Voice.crescendoText = "decr."
+%dim = \property Voice.crescendoText = "dim."
} bind def
%
% this is for drawing slurs.
-/draw_bezier_sandwich % thickness
+/draw_bezier_sandwich % thickness controls
{
setlinewidth
moveto
stroke
} bind def
%
-/draw_dashed_slur
+/draw_dashed_line % dash thickness width
+{
+ 1 setlinecap
+ 1 setlinejoin
+ setdash
+ setlinewidth
+ 0 0 moveto
+ 0 lineto
+ stroke
+} bind def
+%
+/draw_dashed_slur % dash thickness controls
{
1 setlinecap
1 setlinejoin
(define (char i)
(string-append "\\char" (inexact->string i 10) " "))
+ (define (dashed-line thick dash w)
+ (embedded-ps ((ps-scm 'dashed-line) thick dash w)))
+
(define (decrescendo thick w h cont)
(embedded-ps ((ps-scm 'decrescendo) thick w h cont)))
(define bracket ,bracket)
(define char ,char)
(define crescendo ,crescendo)
+ (define dashed-line ,dashed-line)
(define dashed-slur ,dashed-slur)
(define decrescendo ,decrescendo)
(define end-output ,end-output)
((eq? action-name 'tuplet) tuplet)
((eq? action-name 'bracket) bracket)
((eq? action-name 'crescendo) crescendo)
+ ((eq? action-name 'dashed-line) dashed-line)
((eq? action-name 'dashed-slur) dashed-slur)
((eq? action-name 'decrescendo) decrescendo)
((eq? action-name 'end-output) end-output)
(number->string (* 10 thick)) ;UGH. 10 ?
" ] 0 draw_dashed_slur"))
+ (define (dashed-line thick dash width)
+ (string-append
+ (number->string width)
+ " "
+ (number->string thick)
+ " [ "
+ (number->string dash)
+ " "
+ (number->string dash)
+ " ] 0 draw_dashed_line"))
+
(define (decrescendo thick w h cont)
(string-append
(numbers->string (list w h (inexact->exact cont) thick))
(define crescendo ,crescendo)
(define volta ,volta)
(define bezier-sandwich ,bezier-sandwich)
+ (define dashed-line ,dashed-line)
(define dashed-slur ,dashed-slur)
(define decrescendo ,decrescendo)
(define end-output ,end-output)
((eq? action-name 'bracket) bracket)
((eq? action-name 'char) char)
((eq? action-name 'crescendo) crescendo)
+ ((eq? action-name 'dashed-line) dashed-line)
((eq? action-name 'dashed-slur) dashed-slur)
((eq? action-name 'decrescendo) decrescendo)
((eq? action-name 'experimental-on) experimental-on)
--- /dev/null
+;;; midi.scm -- scm midi variables and functions
+;;;
+;;; source file of the GNU LilyPond music typesetter
+;;;
+;;; (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
+
+
+(define absolute-volume-alist '())
+(set! absolute-volume-alist
+ (append
+ '(
+ ("sf" . 115)
+ ("fff" . 102)
+ ("ff" . 90)
+ ("f" . 77)
+ ("mf" . 64)
+ ("mp" . 51)
+ ("p" . 38)
+ ("pp" . 26)
+ ("ppp" . 13)
+ )
+ absolute-volume-alist))
+
+(define (dynamic-absolute-volume s)
+ (let ((entry (assoc s absolute-volume-alist)))
+ (if entry
+ (cdr entry))))
+
+;; 90 is supposed to be the default value
+;; urg: we should set this at start of track
+(define dynamic-default-volume 90)