X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fparameter_descriptor.cc;h=7ed0c785126d6a9808182a37aa3123e1aaaa48ae;hb=37905d82a611a09342faf52d01378c9b4e86a2ac;hp=9a6f5506dc81c7aef3a760b2d52e023963b00bb4;hpb=46c83693284ece4a732d26e62113ea4ac584d539;p=ardour.git diff --git a/libs/ardour/parameter_descriptor.cc b/libs/ardour/parameter_descriptor.cc index 9a6f5506dc..7ed0c78512 100644 --- a/libs/ardour/parameter_descriptor.cc +++ b/libs/ardour/parameter_descriptor.cc @@ -17,6 +17,10 @@ 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + +#include "pbd/control_math.h" + #include "ardour/amp.h" #include "ardour/dB.h" #include "ardour/parameter_descriptor.h" @@ -24,6 +28,8 @@ #include "ardour/types.h" #include "ardour/utils.h" +#include "pbd/i18n.h" + namespace ARDOUR { ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter) @@ -37,21 +43,28 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter) , largestep(0) , integer_step(parameter.type() >= MidiCCAutomation && parameter.type() <= MidiChannelPressureAutomation) - , logarithmic(false) , sr_dependent(false) - , min_unbound(0) - , max_unbound(0) , enumeration(false) { + ScalePoints sp; + + /* Note: defaults in Evoral::ParameterDescriptor */ + switch((AutomationType)parameter.type()) { case GainAutomation: + case BusSendLevel: upper = Config->get_max_gain(); normal = 1.0f; break; + case BusSendEnable: + normal = 1.0f; + toggled = true; + break; case TrimAutomation: upper = 10; // +20dB lower = .1; // -20dB normal = 1.0f; + logarithmic = true; break; case PanAzimuthAutomation: normal = 0.5f; // there really is no _normal but this works for stereo, sort of @@ -63,11 +76,11 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter) normal = 0.0f; break; case RecEnableAutomation: + case RecSafeAutomation: lower = 0.0; upper = 1.0; toggled = true; break; - case PluginAutomation: case FadeInAutomation: case FadeOutAutomation: case EnvelopeAutomation: @@ -83,6 +96,7 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter) case MidiCCAutomation: case MidiPgmChangeAutomation: case MidiChannelPressureAutomation: + case MidiNotePressureAutomation: lower = 0.0; normal = 0.0; upper = 127.0; @@ -92,6 +106,19 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter) normal = 8192.0; upper = 16383.0; break; + case PhaseAutomation: + toggled = true; + break; + case MonitoringAutomation: + enumeration = true; + integer_step = true; + lower = MonitorAuto; + upper = MonitorDisk; /* XXX bump when we add MonitorCue */ + break; + case SoloIsolateAutomation: + case SoloSafeAutomation: + toggled = true; + break; default: break; } @@ -103,15 +130,13 @@ ParameterDescriptor::ParameterDescriptor() : Evoral::ParameterDescriptor() , key((uint32_t)-1) , datatype(Variant::NOTHING) + , type(NullAutomation) , unit(NONE) , step(0) , smallstep(0) , largestep(0) , integer_step(false) - , logarithmic(false) , sr_dependent(false) - , min_unbound(0) - , max_unbound(0) , enumeration(false) {} @@ -125,10 +150,13 @@ ParameterDescriptor::update_steps() /* dB_coeff_step gives a step normalized for [0, max_gain]. This is like "slider position", so we convert from "slider position" to gain to have the correct unit here. */ - largestep = slider_position_to_gain(dB_coeff_step(upper)); - step = slider_position_to_gain(largestep / 10.0); + largestep = position_to_gain (dB_coeff_step(upper)); + step = position_to_gain (largestep / 10.0); smallstep = step; } else { + /* note that LV2Plugin::get_parameter_descriptor () + * overrides this is lv2:rangeStep is set for a port. + */ const float delta = upper - lower; /* 30 happens to be the total number of steps for a fader with default @@ -150,10 +178,180 @@ ParameterDescriptor::update_steps() largestep = largestep / logf(30.0f); } else if (integer_step) { smallstep = 1.0; - step = std::max(1.0, rint(step)); - largestep = std::max(1.0, rint(largestep)); + step = std::max(1.f, rintf (step)); + largestep = std::max(1.f, rintf (largestep)); } } } +std::string +ParameterDescriptor::midi_note_name (const uint8_t b, bool translate) +{ + char buf[16]; + if (b > 127) { + snprintf(buf, sizeof(buf), "%d", b); + return buf; + } + + static const char* en_notes[] = { + "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" + }; + + static const char* notes[] = { + S_("Note|C"), + S_("Note|C#"), + S_("Note|D"), + S_("Note|D#"), + S_("Note|E"), + S_("Note|F"), + S_("Note|F#"), + S_("Note|G"), + S_("Note|G#"), + S_("Note|A"), + S_("Note|A#"), + S_("Note|B") + }; + + /* MIDI note 0 is in octave -1 (in scientific pitch notation) */ + const int octave = b / 12 - 1; + const size_t p = b % 12; + snprintf (buf, sizeof (buf), "%s%d", translate ? notes[p] : en_notes[p], octave); + return buf; +} + +std::string +ParameterDescriptor::normalize_note_name(const std::string& name) +{ + // Remove whitespaces and convert to lower case for a more resilient parser + return boost::to_lower_copy(boost::erase_all_copy(name, " ")); +}; + +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 = 1.f - 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 = 1.f - 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 = round (lower + val * (1.f + upper - lower) - .5f); + } 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; +} + } // namespace ARDOUR