]> git.donarmstrong.com Git - lilypond.git/commitdiff
Fix #86; Fix midi dynamics coverage.
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Sun, 7 Jan 2007 01:03:30 +0000 (02:03 +0100)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Sun, 7 Jan 2007 01:03:30 +0000 (02:03 +0100)
New_dynamic_performer, unified handling of absolute and span dynamics.

input/regression/midi-absolute-volume.ly [deleted file]
input/regression/midi-dynamics.ly [new file with mode: 0644]
lily/audio-column.cc
lily/audio-item.cc
lily/dynamic-performer.cc [deleted file]
lily/include/audio-column.hh
lily/include/audio-item.hh
lily/midi-walker.cc
lily/score-performer.cc
lily/span-dynamic-performer.cc [deleted file]
ly/performer-init.ly

diff --git a/input/regression/midi-absolute-volume.ly b/input/regression/midi-absolute-volume.ly
deleted file mode 100644 (file)
index 8c3a24c..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-
-\version "2.10.0"
-\header {
-    texidoc = "@cindex Dynamic Absolute Volume
-Absolute dynamics have an effect on MIDI files.
-"
-}
-
-
-\score{
-\relative c''{
-%segfault in engraver
-a1\ppp 
-a1\pp
-a\p
-a\mp
-a\mf
-a\f
-a\ff
-a\fff
-a\sf
-}
-\layout{ ragged-right = ##t }
-
-  \midi {
-    \context {
-      \Score
-      tempoWholesPerMinute = #(ly:make-moment 60 1)
-      }
-    }
-
-
-}
-
diff --git a/input/regression/midi-dynamics.ly b/input/regression/midi-dynamics.ly
new file mode 100644 (file)
index 0000000..edff9c2
--- /dev/null
@@ -0,0 +1,24 @@
+\header {
+
+  texidoc = "Midi also handles crescendo and decrescendo, either
+  starting and ending from specified or unspecified sound level."
+
+}
+
+\version  "2.11.10"
+
+\score {
+  \relative {
+
+    \set midiMinimumVolume = #0.0
+    \set midiMaximumVolume = #1.0
+    c\ff c\pppp
+    c\ff\> c c c c\!\pppp
+
+    c\< c c c c\! \ff
+
+    c\> c c c \!  
+  } 
+  \midi {}
+  \layout{}
+}
index d0a36518a573584bcee77c14d75fa0b75a78a5c5..6365305675938e91ac6741c408af402d03469bea 100644 (file)
@@ -11,9 +11,9 @@
 #include "audio-item.hh"
 #include "performance.hh"
 
-Audio_column::Audio_column (Moment at_mom)
+Audio_column::Audio_column (Moment when)
 {
-  at_mom_ = at_mom;
+  when_ = when;
 }
 
 void
@@ -24,14 +24,14 @@ Audio_column::add_audio_item (Audio_item *l)
 }
 
 Moment
-Audio_column::at_mom () const
+Audio_column::when () const
 {
-  return at_mom_;
+  return when_;
 }
 
 void
-Audio_column::offset_at_mom (Moment m)
+Audio_column::offset_when (Moment m)
 {
-  at_mom_ += m;
+  when_ += m;
 }
 
index 4a3b9d4a41d3405d2de8e9c28f205bf23a726661..3913527ea19cea5c5c7392e3c84940975bc8aae1 100644 (file)
@@ -16,6 +16,17 @@ Audio_instrument::Audio_instrument (string instrument_string)
   str_ = instrument_string;
 }
 
+void
+Audio_item::render ()
+{
+}
+
+Audio_column *
+Audio_item::get_column () const
+{
+  return audio_column_;
+}
+
 Audio_item::Audio_item ()
 {
   audio_column_ = 0;
@@ -47,11 +58,75 @@ Audio_key::Audio_key (int acc, bool major)
   major_ = major;
 }
 
-Audio_dynamic::Audio_dynamic (Real volume)
+Audio_dynamic::Audio_dynamic ()
+{
+  volume_ = -1;
+}
+
+Audio_span_dynamic::Audio_span_dynamic ()
+{
+  grow_dir_ = CENTER;
+}
+
+void
+Audio_span_dynamic::add_absolute (Audio_dynamic *d)
+{
+  assert (d);
+  dynamics_.push_back (d);
+}
+
+static Real
+moment2real (Moment m)
+{
+  return m.main_part_.to_double ()
+    + 0.1 * m.grace_part_.to_double ();
+}
+
+void
+Audio_span_dynamic::render ()
 {
-  volume_ = volume;
+  if (dynamics_.size () <= 1)
+    return ;
+
+  assert (dynamics_[0]->volume_ >= 0);
+
+  if (dynamics_.back ()->volume_ > 0
+      && sign (dynamics_.back ()->volume_ - dynamics_[0]->volume_) != grow_dir_)
+    {
+      dynamics_.erase (dynamics_.end () - 1);
+      assert (dynamics_.back ()->volume_ < 0);
+    }
+
+  if (dynamics_.size () <= 1)
+    return ;
+
+  Real delta_v = grow_dir_ * 0.1;
+  
+  Real start_v = dynamics_[0]->volume_;
+  if (dynamics_.back ()->volume_ < 0)
+    dynamics_.back ()->volume_ = max (min (start_v + grow_dir_ * 0.25, 1.0), 0.0);
+
+  delta_v = dynamics_.back ()->volume_ - dynamics_[0]->volume_;
+
+  Moment start = dynamics_[0]->get_column ()->when ();
+
+  Real total_t = moment2real (dynamics_.back ()->get_column ()->when () - start);
+  
+  for (vsize i = 1; i < dynamics_.size(); i ++)
+    {
+      Moment dt_moment = dynamics_[i]->get_column ()->when ()
+       - start;
+
+      Real dt =  moment2real (dt_moment);
+      
+      Real v = start_v + delta_v *  (dt / total_t);
+
+      dynamics_[i]->volume_ = v;       
+    }
 }
 
+
+
 Audio_tempo::Audio_tempo (int per_minute_4)
 {
   per_minute_4_ = per_minute_4;
diff --git a/lily/dynamic-performer.cc b/lily/dynamic-performer.cc
deleted file mode 100644 (file)
index 52939ec..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
-  dynamic-performer.cc -- implement Dynamic_performer
-
-  source file of the GNU LilyPond music typesetter
-
-  (c) 2000--2006 Jan Nieuwenhuizen <janneke@gnu.org>
-*/
-
-#include "performer.hh"
-
-#include "audio-item.hh"
-#include "stream-event.hh"
-#include "translator.icc"
-
-/*
-  TODO:
-
-  handle multiple events
-
-  perform absolute (text) dynamics
-*/
-class Dynamic_performer : public Performer
-{
-public:
-  TRANSLATOR_DECLARATIONS (Dynamic_performer);
-protected:
-  void stop_translation_timestep ();
-  void process_music ();
-
-  DECLARE_TRANSLATOR_LISTENER (absolute_dynamic);
-private:
-  Stream_event *script_event_;
-  Audio_dynamic *audio_;
-};
-
-Dynamic_performer::Dynamic_performer ()
-{
-  script_event_ = 0;
-  audio_ = 0;
-}
-
-void
-Dynamic_performer::process_music ()
-{
-  if (script_event_)
-    {
-      SCM proc = get_property ("dynamicAbsoluteVolumeFunction");
-
-      SCM svolume = SCM_EOL;
-      if (ly_is_procedure (proc))
-       {
-         // urg
-         svolume = scm_call_1 (proc, script_event_->get_property ("text"));
-       }
-
-      Real volume = robust_scm2double (svolume, 0.5);
-
-      /*
-       properties override default equaliser setting
-      */
-      SCM min = get_property ("midiMinimumVolume");
-      SCM max = get_property ("midiMaximumVolume");
-      if (scm_is_number (min) || scm_is_number (max))
-       {
-         Interval iv (0, 1);
-         if (scm_is_number (min))
-           iv[MIN] = scm_to_double (min);
-         if (scm_is_number (max))
-           iv[MAX] = scm_to_double (max);
-         volume = iv[MIN] + iv.length () * volume;
-       }
-      else
-       {
-         /*
-           urg, code duplication:: staff_performer
-         */
-         SCM s = get_property ("midiInstrument");
-
-         if (!scm_is_string (s))
-           s = get_property ("instrumentName");
-
-         if (!scm_is_string (s))
-           s = scm_from_locale_string ("piano");
-
-         SCM eq = get_property ("instrumentEqualizer");
-         if (ly_is_procedure (eq))
-           s = scm_call_1 (eq, s);
-
-         if (is_number_pair (s))
-           {
-             Interval iv = ly_scm2interval (s);
-             volume = iv[MIN] + iv.length () * volume;
-           }
-       }
-
-      audio_ = new Audio_dynamic (volume);
-      Audio_element_info info (audio_, script_event_);
-      announce_element (info);
-      script_event_ = 0;
-    }
-}
-
-void
-Dynamic_performer::stop_translation_timestep ()
-{
-  if (audio_)
-    {
-      audio_ = 0;
-    }
-}
-
-IMPLEMENT_TRANSLATOR_LISTENER (Dynamic_performer, absolute_dynamic);
-void
-Dynamic_performer::listen_absolute_dynamic (Stream_event *r)
-{
-  if (!script_event_)
-    script_event_ = r;
-}
-
-ADD_TRANSLATOR (Dynamic_performer,
-               /* doc */                "",
-               /* create */ "",
-
-               /* read */
-               "dynamicAbsoluteVolumeFunction "
-               "instrumentEqualizer "
-               "midiMaximumVolume "
-               "midiMinimumVolume "
-               "midiInstrument "
-               ,
-               /*writes*/"");
index 1cc827a2767fff90abde602dbaf450f40af3f493..1d0fb5ca18d6fb3e64268225393488682de0d569 100644 (file)
 class Audio_column : public Audio_element
 {
 public:
-  Audio_column (Moment at_mom);
+  Audio_column (Moment when);
 
   void add_audio_item (Audio_item *i);
-  Moment at_mom () const;
+  Moment when () const;
 
   vector<Audio_item*> audio_items_;
 
 protected:
-  void offset_at_mom (Moment m);
+  void offset_when (Moment m);
   friend class Score_performer;
 
 private:
   Audio_column (Audio_column const &);
 
-  Moment at_mom_;
+  Moment when_;
 };
 
 #endif // AUDIO_COLUMN_HH
index e6f0c9ad91615b9d93a46f5e6977f4067a031468..d450582febb95d48e1b9a5723db9f01c70978207 100644 (file)
@@ -21,7 +21,10 @@ class Audio_item : public Audio_element
 public:
   Audio_item ();
   Audio_column *audio_column_;
+  Audio_column *get_column () const;
 
+  virtual void render ();
+  
 private:
   Audio_item (Audio_item const &);
   Audio_item &operator = (Audio_item const &);
@@ -30,11 +33,24 @@ private:
 class Audio_dynamic : public Audio_item
 {
 public:
-  Audio_dynamic (Real volume);
+  Audio_dynamic ();
 
   Real volume_;
 };
 
+class Audio_span_dynamic : public Audio_element
+{
+public:
+  Direction grow_dir_;
+  vector<Audio_dynamic*> dynamics_;
+
+
+  virtual void render ();
+  void add_absolute (Audio_dynamic*);
+  Audio_span_dynamic ();
+};
+
+
 class Audio_key : public Audio_item
 {
 public:
index c2aaa085b14d5ee5eab73e2f722524db7f535d2e..8a315d6f2cd828aa6e2bed921aba05a13b474f99 100644 (file)
@@ -57,7 +57,7 @@ void
 Midi_walker::do_start_note (Midi_note *note)
 {
   Audio_item *ptr = (*items_)[index_];
-  Moment stop_mom = note->get_length () + ptr->audio_column_->at_mom ();
+  Moment stop_mom = note->get_length () + ptr->audio_column_->when ();
 
   bool play_start = true;
   for (vsize i = 0; i < stop_note_queue.size (); i++)
@@ -93,7 +93,7 @@ Midi_walker::do_start_note (Midi_note *note)
       stop_note_queue.insert (e);
 
       if (play_start)
-       output_event (ptr->audio_column_->at_mom (), note);
+       output_event (ptr->audio_column_->when (), note);
     }
 }
 
@@ -142,7 +142,7 @@ void
 Midi_walker::process ()
 {
   Audio_item *audio = (*items_)[index_];
-  do_stop_notes (audio->audio_column_->at_mom ());
+  do_stop_notes (audio->audio_column_->when ());
 
   if (Midi_item *midi = Midi_item::get_midi (audio))
     {
@@ -156,7 +156,7 @@ Midi_walker::process ()
            do_start_note (note);
        }
       else
-       output_event (audio->audio_column_->at_mom (), midi);
+       output_event (audio->audio_column_->when (), midi);
     }
 }
 
index 73f79add862ba55bdd66b589d80eede1d5238532..0dfea54c6e16a689dcfb579ec6c754ab8f3e4d76 100644 (file)
@@ -113,7 +113,7 @@ Score_performer::one_time_step (SCM)
     {
       if (!skipping_)
         {
-         skip_start_mom_ = audio_column_->at_mom ();
+         skip_start_mom_ = audio_column_->when ();
          skipping_ = true;
         }
     }
@@ -121,11 +121,11 @@ Score_performer::one_time_step (SCM)
     {
       if (skipping_)
         {
-         offset_mom_ -= audio_column_->at_mom () - skip_start_mom_;
+         offset_mom_ -= audio_column_->when () - skip_start_mom_;
          skipping_ = false;
        }
 
-      audio_column_->offset_at_mom (offset_mom_);
+      audio_column_->offset_when (offset_mom_);
       precomputed_recurse_over_translators (context (), PROCESS_MUSIC, UP);
       do_announces ();
     }
diff --git a/lily/span-dynamic-performer.cc b/lily/span-dynamic-performer.cc
deleted file mode 100644 (file)
index e5938f0..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
-  span-dynamic-performer.cc -- implement Span_dynamic_performer
-
-  source file of the GNU LilyPond music typesetter
-
-  (c) 2000--2006 Jan Nieuwenhuizen <janneke@gnu.org>
-*/
-
-#include "performer.hh"
-
-#include "audio-item.hh"
-#include "international.hh"
-#include "stream-event.hh"
-
-#include "translator.icc"
-
-/*
-  TODO: fold this into 1 engraver: \< and \> should also stop when
-  absdyn is encountered.
-*/
-struct Audio_dynamic_tuple
-{
-  Audio_dynamic *audio_;
-  Moment mom_;
-};
-
-/**
-   perform span-dynamics
-*/
-class Span_dynamic_performer : public Performer
-{
-public:
-  TRANSLATOR_DECLARATIONS (Span_dynamic_performer);
-
-protected:
-  virtual void acknowledge_audio_element (Audio_element_info);
-  void process_music ();
-  void stop_translation_timestep ();
-
-  DECLARE_TRANSLATOR_LISTENER (decrescendo);
-  DECLARE_TRANSLATOR_LISTENER (crescendo);
-private:
-  Audio_dynamic *audio_;
-  Real last_volume_;
-  Stream_event *span_start_event_;
-  Drul_array<Stream_event *> span_events_;
-  vector<Audio_dynamic_tuple> dynamic_tuples_;
-  vector<Audio_dynamic_tuple> finished_dynamic_tuples_;
-  Direction dir_;
-  Direction finished_dir_;
-};
-
-Span_dynamic_performer::Span_dynamic_performer ()
-{
-  span_events_[START] = 0;
-  span_events_[STOP] = 0;
-  span_start_event_ = 0;
-  audio_ = 0;
-  last_volume_ = 0;
-}
-
-void
-Span_dynamic_performer::acknowledge_audio_element (Audio_element_info i)
-{
-  if (Audio_dynamic *d = dynamic_cast<Audio_dynamic *> (i.elem_))
-    last_volume_ = d->volume_;
-}
-
-void
-Span_dynamic_performer::process_music ()
-{
-  if (span_start_event_ || span_events_[START])
-    {
-      audio_ = new Audio_dynamic (0);
-      Audio_element_info info (audio_, span_events_[START]
-                              ? span_events_[START]
-                              : span_events_[STOP]);
-      announce_element (info);
-      Audio_dynamic_tuple a = { audio_, now_mom () };
-      dynamic_tuples_.push_back (a);
-    }
-
-  if (span_events_[STOP])
-    {
-      if (!span_start_event_)
-       {
-         span_events_[STOP]->origin ()->warning (_ ("cannot find start of (de)crescendo"));
-         span_events_[STOP] = 0;
-       }
-      else
-       {
-         finished_dir_ = dir_;
-         finished_dynamic_tuples_ = dynamic_tuples_;
-       }
-      dynamic_tuples_.clear ();
-      span_start_event_ = 0;
-    }
-
-  if (span_events_[START])
-    {
-      dir_ = (span_events_[START]->in_event_class ("crescendo-event"))
-       ? RIGHT : LEFT;
-      span_start_event_ = span_events_[START];
-
-      dynamic_tuples_.clear ();
-      Audio_dynamic_tuple a = { audio_, now_mom () };
-      dynamic_tuples_.push_back (a);
-    }
-
-  if (span_events_[STOP])
-    finished_dynamic_tuples_.back ().audio_->volume_ = last_volume_;
-
-  if (span_events_[START])
-    dynamic_tuples_[0].audio_->volume_ = last_volume_;
-
-  span_events_[START] = 0;
-  span_events_[STOP] = 0;
-}
-
-void
-Span_dynamic_performer::stop_translation_timestep ()
-{
-  if (finished_dynamic_tuples_.size () > 1)
-    {
-      Real start_volume = finished_dynamic_tuples_[0].audio_->volume_;
-      Real dv = finished_dynamic_tuples_.back ().audio_->volume_
-       - start_volume;
-      /*
-       urg.
-       Catch and fix the case of:
-
-       |                         |
-       x|                        x|
-       f cresc.  -- -- -- -- --  pp
-
-       Actually, we should provide a non-displayed dynamic/volume setting,
-       to set volume to 'ff' just before the pp.
-      */
-      if (!dv || sign (dv) != finished_dir_)
-       {
-         // urg.  20%: about two volume steps
-         dv = (Real)finished_dir_ * 0.2;
-         if (!start_volume)
-           start_volume = finished_dynamic_tuples_.back ().audio_->volume_
-             - dv;
-       }
-      Moment start_mom = finished_dynamic_tuples_[0].mom_;
-      Moment dt = finished_dynamic_tuples_.back ().mom_ - start_mom;
-      for (vsize i = 0; i < finished_dynamic_tuples_.size (); i++)
-       {
-         Audio_dynamic_tuple *a = &finished_dynamic_tuples_[i];
-         Real volume = start_volume + dv * (Real) (a->mom_ - start_mom).main_part_
-           / (Real)dt.main_part_;
-         a->audio_->volume_ = volume;
-       }
-      finished_dynamic_tuples_.clear ();
-    }
-
-  if (audio_)
-    {
-      audio_ = 0;
-    }
-
-  span_events_[STOP] = 0;
-  span_events_[START] = 0;
-}
-
-IMPLEMENT_TRANSLATOR_LISTENER (Span_dynamic_performer, decrescendo);
-void
-Span_dynamic_performer::listen_decrescendo (Stream_event *r)
-{
-  Direction d = to_dir (r->get_property ("span-direction"));
-  span_events_[d] = r;
-}
-
-IMPLEMENT_TRANSLATOR_LISTENER (Span_dynamic_performer, crescendo);
-void
-Span_dynamic_performer::listen_crescendo (Stream_event *r)
-{
-  Direction d = to_dir (r->get_property ("span-direction"));
-  span_events_[d] = r;
-}
-
-ADD_TRANSLATOR (Span_dynamic_performer,
-               "", "",
-               "", "");
index 24f0da2b81b567496217cbce4f1b29c883a3bf0c..23e96dae3ce98fa4b10b86c3052dc5f6793aea06 100644 (file)
@@ -30,9 +30,7 @@
 \context {
     \type "Performer_group"
     \name Voice
-    % The order of the dynamic performers is significant: absolute dynamic events must override crescendo events in midi.
-    \consists "Span_dynamic_performer"
-    \consists "Dynamic_performer"
+    \consists "New_dynamic_performer"    
     \consists "Tie_performer"
     \consists "Piano_pedal_performer"
     \consists "Note_performer"