]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/midi-cc-announcer.cc
Imported Upstream version 2.19.47
[lilypond.git] / lily / midi-cc-announcer.cc
diff --git a/lily/midi-cc-announcer.cc b/lily/midi-cc-announcer.cc
new file mode 100644 (file)
index 0000000..7fb4ed6
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2016 by Heikki Tauriainen <g034737@welho.com>.
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audio-item.hh"
+#include "input.hh"
+#include "international.hh"
+#include "libc-extension.hh"
+#include "midi-cc-announcer.hh"
+
+/*
+  Context properties for setting MIDI controls.  Each MIDI control
+  specification has the following components:
+    1. The name of the LilyPond context property used to change the value of
+       the MIDI control.
+    2. The lower bound for the numeric range of the LilyPond context property.
+    3. The upper bound for the numeric range of the LilyPond context property.
+    4. The MIDI control number for setting the most significant 7 bits of the
+       control value.
+    5. The MIDI control number for setting the least significant 7 bits of the
+       control value, if the control supports 14-bit ("fine") resolution.  If
+       the control supports only 7-bit ("coarse") resolution, the LSB control
+       number should be negative.
+*/
+const Midi_control_change_announcer::Control_spec
+Midi_control_change_announcer::controls_[]
+=
+{
+  { "midiBalance", -1.0, 1.0, 8, 40 },
+  { "midiPanPosition", -1.0, 1.0, 10, 42 },
+  { "midiExpression", 0.0, 1.0, 11, 43 },
+  { "midiReverbLevel", 0.0, 1.0, 91, -1 },
+  { "midiChorusLevel", 0.0, 1.0, 93, -1 },
+  // This element should be kept last in the array.
+  { 0, 0.0, 0.0, 0, 0 }
+};
+
+Midi_control_change_announcer::Midi_control_change_announcer (Input *origin)
+  : origin_ (origin)
+{
+}
+
+Midi_control_change_announcer::~Midi_control_change_announcer ()
+{
+}
+
+void Midi_control_change_announcer::announce_control_changes ()
+{
+  for (const Control_spec *spec = controls_; spec->context_property_name_;
+       ++spec)
+    {
+      SCM value = get_property_value (spec->context_property_name_);
+      if (!scm_is_number (value))
+        continue;
+      Real val = scm_to_double (value);
+      if (val >= spec->range_min_ && val <= spec->range_max_)
+        {
+          // Normalize the value to the 0.0 to 1.0 range.
+          val = ((val - spec->range_min_)
+                 / (spec->range_max_ - spec->range_min_));
+          // Transform the normalized context property value into a 14-bit or
+          // a 7-bit (non-negative) integer depending on the MIDI control's
+          // resolution.  For directional value changes, #CENTER will
+          // correspond to 0.5 exactly, and my_round rounds upwards when in
+          // case of doubt.  That means that center position will round to
+          // 0x40 or 0x2000 by a hair's breadth.
+          const Real full_fine_scale = 0x3FFF;
+          const Real full_coarse_scale = 0x7F;
+          const bool fine_resolution = (spec->lsb_control_number_ >= 0);
+          const int v = (int) (my_round (val * (fine_resolution
+                                                ? full_fine_scale
+                                                : full_coarse_scale)));
+          // Announce a control change for the most significant 7 bits of the
+          // control value (and, if the control supports fine resolution, for
+          // the least significant 7 bits as well).
+          do_announce (new Audio_control_change (spec->msb_control_number_,
+                                                 fine_resolution
+                                                 ? (v >> 7) : v));
+          if (fine_resolution)
+            do_announce (new Audio_control_change (spec->lsb_control_number_,
+                                                   v & 0x7F));
+        }
+      else
+        warn (_f ("ignoring out-of-range value change for MIDI property `%s'",
+                  spec->context_property_name_));
+    }
+}
+
+void Midi_control_change_announcer::warn (const string &message)
+{
+  if (origin_)
+    origin_->warning (message);
+  else
+    warning (message);
+}