675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <algorithm>
#include <boost/algorithm/string.hpp>
#include "pbd/control_math.h"
lower = 0.0;
normal = 0.0;
upper = 127.0;
+ print_fmt = "%.0f";
break;
case MidiPitchBenderAutomation:
lower = 0.0;
normal = 8192.0;
upper = 16383.0;
+ print_fmt = "%.0f";
break;
case PhaseAutomation:
toggled = true;
+ scale_points = boost::shared_ptr<ScalePoints>(new ScalePoints());
+ scale_points->insert (std::make_pair (_("Normal"), 0));
+ scale_points->insert (std::make_pair (_("Invert"), 1));
break;
case MonitoringAutomation:
enumeration = true;
integer_step = true;
lower = MonitorAuto;
upper = MonitorDisk; /* XXX bump when we add MonitorCue */
+ scale_points = boost::shared_ptr<ScalePoints>(new ScalePoints());
+ scale_points->insert (std::make_pair (_("Auto"), MonitorAuto));
+ scale_points->insert (std::make_pair (_("Input"), MonitorInput));
+ scale_points->insert (std::make_pair (_("Disk"), MonitorDisk));
break;
case SoloIsolateAutomation:
case SoloSafeAutomation:
void
ParameterDescriptor::update_steps()
{
+ /* sanitize flags */
+ if (toggled || enumeration) {
+ logarithmic = false;
+ }
+ if (logarithmic && sr_dependent && upper > lower && lower == 0) {
+ /* work-around for plugins with a log-scale control 0..SR; log (0) is not defined */
+ lower = upper / 1000.f;
+ }
+ if (logarithmic && (upper <= lower || lower * upper <= 0)) {
+ /* log-scale params need upper > lower and both values need the same sign */
+ logarithmic = false;
+ }
+ if (rangesteps < 2) {
+ rangesteps = 0;
+ }
+ if (enumeration) {
+ /* enums need scale-points.
+ * The GUI is more restrictive, a dropdown is displayed
+ * IIF scale_points.size() == (1 + upper - lower)
+ */
+ if (!scale_points || scale_points->empty ()) {
+ enumeration = false;
+ }
+ }
+ if (integer_step) {
+ if (lower >= upper) {
+ integer_step = false;
+ }
+ }
+
+ /* upper == lower does not make any sense */
+ if (lower == upper) {
+ upper = lower + 0.01; // add some arbitrary value
+ }
+
+ /* set steps */
+
if (unit == ParameterDescriptor::MIDI_NOTE) {
step = smallstep = 1; // semitone
largestep = 12; // octave
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.
+ } else if (logarithmic) {
+ /* ignore logscale rangesteps. {small|large}steps are used with the spinbox.
+ * gtk-spinbox shows the internal (not interface) value and up/down
+ * arrows linearly increase.
+ * The AutomationController uses internal_to_interface():
+ * ui-step [0..1] -> log (1 + largestep / lower) / log (upper / lower)
+ * so we use a step that's a multiple of "lower" for the interface step:
+ * log (1 + x) / log (upper / lower)
*/
+ smallstep = step = lower / 11;
+ largestep = lower / 3;
+ /* NOTE: the actual value does use rangesteps via
+ * logscale_to_position_with_steps(), position_to_logscale_with_steps()
+ * when it is converted.
+ */
+ } else if (rangesteps > 1) {
const float delta = upper - lower;
-
- /* 30 happens to be the total number of steps for a fader with default
- max gain of 2.0 (6 dB), so we use 30 here too for consistency. */
- step = smallstep = (delta / 300.0f);
- largestep = (delta / 30.0f);
-
- if (logarithmic) {
- /* Steps are linear, but we map them with pow like values (in
- internal_to_interface). Thus, they are applied exponentially,
- which means too few steps. So, divide to get roughly the
- desired number of steps (30). This is not mathematically
- precise but seems to be about right for the controls I tried.
- If you're reading this, you've probably found a case where that
- isn't true, and somebody needs to sit down with a piece of paper
- and actually do the math. */
- smallstep = smallstep / logf(30.0f);
- step = step / logf(30.0f);
- largestep = largestep / logf(30.0f);
- } else if (integer_step) {
- smallstep = 1.0;
- step = std::max(1.f, rintf (step));
- largestep = std::max(1.f, rintf (largestep));
+ if (integer_step) {
+ smallstep = step = 1.0;
+ largestep = std::max(1.f, rintf (delta / (rangesteps - 1.f)));
+ } else {
+ step = smallstep = delta / (rangesteps - 1.f);
+ largestep = std::min ((delta / 4.0f), 10.f * smallstep);
+ }
+ } else {
+ const float delta = upper - lower;
+ /* 30 steps between min/max (300 for fine-grained) */
+ if (integer_step) {
+ smallstep = step = 1.0;
+ largestep = std::max(1.f, rintf (delta / 30.f));
+ } else {
+ step = smallstep = (delta / 300.0f);
+ largestep = (delta / 30.0f);
}
}
}
break;
case PanAzimuthAutomation:
case PanElevationAutomation:
- val = 1.f - val;
+ val = val;
break;
case PanWidthAutomation:
val = .5f + val * .5f;
break;
case PanAzimuthAutomation:
case PanElevationAutomation:
- val = 1.f - val;
+ val = val;
break;
case PanWidthAutomation:
val = 2.f * val - 1.f;
* 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);
+ 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 = round (val * (rangesteps - 1.f)) / (rangesteps - 1.f); // XXX
val = val * (upper - lower) + lower;
} else {
val = val * (upper - lower) + lower;
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());
+
+ if (prev) {
+ if (it == avail.begin()) {
+ return rv;
+ }
+ return *(--it);
+ } else {
+ if (++it == avail.end()) {
+ return rv;
+ }
+ return *(it);
+ }
+}
+
} // namespace ARDOUR