+ParameterDescriptor::NameNumMap
+ParameterDescriptor::build_midi_name2num()
+{
+ NameNumMap name2num;
+ for (uint8_t num = 0; num < 128; num++) {
+ name2num[normalize_note_name(midi_note_name(num))] = num;
+ }
+ return name2num;
+}
+
+uint8_t
+ParameterDescriptor::midi_note_num (const std::string& name)
+{
+ static NameNumMap name2num = build_midi_name2num();
+
+ uint8_t num = -1; // -1 (or 255) is returned in case of failure
+
+ NameNumMap::const_iterator it = name2num.find(normalize_note_name(name));
+ if (it != name2num.end())
+ num = it->second;
+
+ return num;
+}
+
+float
+ParameterDescriptor::to_interface (float val) const
+{
+ val = std::min (upper, std::max (lower, val));
+ switch(type) {
+ case GainAutomation:
+ case BusSendLevel:
+ case EnvelopeAutomation:
+ val = gain_to_slider_position_with_max (val, upper);
+ break;
+ case TrimAutomation:
+ {
+ const float lower_db = accurate_coefficient_to_dB (lower);
+ const float range_db = accurate_coefficient_to_dB (upper) - lower_db;
+ val = (accurate_coefficient_to_dB (val) - lower_db) / range_db;
+ }
+ break;
+ case PanAzimuthAutomation:
+ case PanElevationAutomation:
+ val = val;
+ break;
+ case PanWidthAutomation:
+ val = .5f + val * .5f;
+ break;
+ default:
+ if (logarithmic) {
+ if (rangesteps > 1) {
+ val = logscale_to_position_with_steps (val, lower, upper, rangesteps);
+ } else {
+ val = logscale_to_position (val, lower, upper);
+ }
+ } else if (toggled) {
+ return (val - lower) / (upper - lower) >= 0.5f ? 1.f : 0.f;
+ } else if (integer_step) {
+ /* evenly-divide steps. lower,upper inclusive
+ * e.g. 5 integers 0,1,2,3,4 are mapped to a fader
+ * [0.0 ... 0.2 | 0.2 ... 0.4 | 0.4 ... 0.6 | 0.6 ... 0.8 | 0.8 ... 1.0]
+ * 0 1 2 3 4
+ * 0.1 0.3 0.5 0.7 0.9
+ */
+ val = (val + .5f - lower) / (1.f + upper - lower);
+ } else {
+ val = (val - lower) / (upper - lower);
+ }
+ break;
+ }
+ val = std::max (0.f, std::min (1.f, val));
+ return val;
+}
+
+float
+ParameterDescriptor::from_interface (float val) const
+{
+ val = std::max (0.f, std::min (1.f, val));
+
+ switch(type) {
+ case GainAutomation:
+ case EnvelopeAutomation:
+ case BusSendLevel:
+ val = slider_position_to_gain_with_max (val, upper);
+ break;
+ case TrimAutomation:
+ {
+ const float lower_db = accurate_coefficient_to_dB (lower);
+ const float range_db = accurate_coefficient_to_dB (upper) - lower_db;
+ val = dB_to_coefficient (lower_db + val * range_db);
+ }
+ break;
+ case PanAzimuthAutomation:
+ case PanElevationAutomation:
+ val = val;
+ break;
+ case PanWidthAutomation:
+ val = 2.f * val - 1.f;
+ break;
+ default:
+ if (logarithmic) {
+ assert (!toggled && !integer_step); // update_steps() should prevent that.
+ if (rangesteps > 1) {
+ val = position_to_logscale_with_steps (val, lower, upper, rangesteps);
+ } else {
+ val = position_to_logscale (val, lower, upper);
+ }
+ } else if (toggled) {
+ val = val > 0 ? upper : lower;
+ } else if (integer_step) {
+ /* upper and lower are inclusive. use evenly-divided steps
+ * e.g. 5 integers 0,1,2,3,4 are mapped to a fader
+ * [0.0 .. 0.2 | 0.2 .. 0.4 | 0.4 .. 0.6 | 0.6 .. 0.8 | 0.8 .. 1.0]
+ */
+ val = floor (lower + val * (1.f + upper - lower));
+ } else if (rangesteps > 1) {
+ /* similar to above, but for float controls */
+ val = floor (val * (rangesteps - 1.f)) / (rangesteps - 1.f); // XXX
+ val = val * (upper - lower) + lower;
+ } else {
+ val = val * (upper - lower) + lower;
+ }
+ break;
+ }
+ val = std::min (upper, std::max (lower, val));
+ return val;
+}
+
+bool
+ParameterDescriptor::is_linear () const
+{
+ if (logarithmic) {
+ return false;
+ }
+ switch(type) {
+ case GainAutomation:
+ case EnvelopeAutomation:
+ case BusSendLevel:
+ return false;
+ default:
+ break;
+ }
+ return true;
+}
+
+float
+ParameterDescriptor::compute_delta (float from, float to) const
+{
+ if (is_linear ()) {
+ return to - from;
+ }
+ if (from == 0) {
+ return 0;
+ }
+ return to / from;
+}
+
+float
+ParameterDescriptor::apply_delta (float val, float delta) const
+{
+ if (is_linear ()) {
+ return val + delta;
+ } else {
+ return val * delta;
+ }
+}
+
+float
+ParameterDescriptor::step_enum (float val, bool prev) const
+{
+ if (!enumeration) {
+ return val;
+ }
+ assert (scale_points && !scale_points->empty ());
+ float rv = scale_points->begin()->second;
+ float delta = fabsf (val - rv);
+ std::vector<float> avail;
+
+ for (ScalePoints::const_iterator i = scale_points->begin (); i != scale_points->end (); ++i) {
+ float s = i->second;
+ avail.push_back (s);
+ if (fabsf (val - s) < delta) {
+ rv = s;
+ delta = fabsf (val - s);
+ }
+ }
+ /* ScalePoints map is sorted by text string */
+ std::sort (avail.begin (), avail.end ());
+ std::vector<float>::const_iterator it = std::find (avail.begin (), avail.end (), rv);
+ assert (it != avail.end());