Centralize Parameter scaling
This exposes an AutomationType dependent abstract version of inteface_to_internal(), internal_to_interface().
This commit is contained in:
parent
8dcc28c9ad
commit
37905d82a6
@ -55,6 +55,24 @@ struct LIBARDOUR_API ParameterDescriptor : public Evoral::ParameterDescriptor
|
||||
|
||||
ParameterDescriptor();
|
||||
|
||||
/** control-value to normalized [0..1] range
|
||||
*
|
||||
* Convert given AutomationType from lower/upper range to [0..1]
|
||||
* interface value, using settings from Evoral::ParameterDescriptor.
|
||||
*
|
||||
* default for AutomationControl::internal_to_interface ();
|
||||
*/
|
||||
float to_interface (float) const;
|
||||
|
||||
/** normalized [0..1] to control-value range
|
||||
*
|
||||
* Convert [0..1] to the control's range of this AutomationType
|
||||
* using settings from Evoral::ParameterDescriptor.
|
||||
*
|
||||
* default for AutomationControl::interface_to_internal ();
|
||||
*/
|
||||
float from_interface (float) const;
|
||||
|
||||
/** Set step, smallstep, and largestep, based on current description. */
|
||||
void update_steps();
|
||||
|
||||
|
@ -297,51 +297,25 @@ AutomationControl::commit_transaction (bool did_write)
|
||||
}
|
||||
}
|
||||
|
||||
/* take control-value and return UI range [0..1] */
|
||||
double
|
||||
AutomationControl::internal_to_interface (double val) const
|
||||
{
|
||||
if (_desc.integer_step) {
|
||||
// both upper and lower are inclusive.
|
||||
val = (val - lower()) / (1 + upper() - lower());
|
||||
} else {
|
||||
val = (val - lower()) / (upper() - lower());
|
||||
}
|
||||
|
||||
if (_desc.logarithmic) {
|
||||
if (val > 0) {
|
||||
val = pow (val, 1./2.0);
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
// XXX maybe optimize. _desc.from_interface() has
|
||||
// a switch-statement depending on AutomationType.
|
||||
return _desc.to_interface (val);
|
||||
}
|
||||
|
||||
/* map GUI range [0..1] to control-value */
|
||||
double
|
||||
AutomationControl::interface_to_internal (double val) const
|
||||
{
|
||||
if (!isfinite_local (val)) {
|
||||
assert (0);
|
||||
val = 0;
|
||||
}
|
||||
if (_desc.logarithmic) {
|
||||
if (val <= 0) {
|
||||
val = 0;
|
||||
} else {
|
||||
val = pow (val, 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (_desc.integer_step) {
|
||||
val = lower() + val * (1 + upper() - lower());
|
||||
} else {
|
||||
val = lower() + val * (upper() - lower());
|
||||
}
|
||||
|
||||
if (val < lower()) val = lower();
|
||||
if (val > upper()) val = upper();
|
||||
|
||||
return val;
|
||||
// XXX maybe optimize. see above.
|
||||
return _desc.from_interface (val);
|
||||
}
|
||||
|
||||
std::string
|
||||
|
@ -48,13 +48,12 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
|
||||
{
|
||||
ScalePoints sp;
|
||||
|
||||
/* Note: defaults in Evoral::ParameterDescriptor */
|
||||
|
||||
switch((AutomationType)parameter.type()) {
|
||||
case GainAutomation:
|
||||
upper = Config->get_max_gain();
|
||||
normal = 1.0f;
|
||||
break;
|
||||
case BusSendLevel:
|
||||
upper = Config->get_max_gain ();
|
||||
upper = Config->get_max_gain();
|
||||
normal = 1.0f;
|
||||
break;
|
||||
case BusSendEnable:
|
||||
@ -65,6 +64,7 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
|
||||
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
|
||||
@ -81,7 +81,6 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
|
||||
upper = 1.0;
|
||||
toggled = true;
|
||||
break;
|
||||
case PluginAutomation:
|
||||
case FadeInAutomation:
|
||||
case FadeOutAutomation:
|
||||
case EnvelopeAutomation:
|
||||
@ -117,8 +116,6 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
|
||||
upper = MonitorDisk; /* XXX bump when we add MonitorCue */
|
||||
break;
|
||||
case SoloIsolateAutomation:
|
||||
toggled = true;
|
||||
break;
|
||||
case SoloSafeAutomation:
|
||||
toggled = true;
|
||||
break;
|
||||
@ -253,4 +250,108 @@ ParameterDescriptor::midi_note_num (const std::string& name)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user