/* This file is part of LilyPond, the GNU music typesetter. Copyright (C) 2016 by Heikki Tauriainen . 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 . */ #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); }