use mpeg4 for internal video format (not mjpeg)
[ardour.git] / gtk2_ardour / automation_line.cc
index d5ed529ad882adca59efd0bfd8fb0746b0ea46e9..069a82315508f8af9b5394d92ba1e54428b900b8 100644 (file)
@@ -105,7 +105,7 @@ AutomationLine::AutomationLine (const string&                              name,
        terminal_points_can_slide = true;
        _height = 0;
 
-       group = new ArdourCanvas::Container (&parent);
+       group = new ArdourCanvas::Container (&parent, ArdourCanvas::Duple(0, 1.5));
        CANVAS_DEBUG_NAME (group, "region gain envelope group");
 
        line = new ArdourCanvas::PolyLine (group);
@@ -119,6 +119,7 @@ AutomationLine::AutomationLine (const string&                              name,
        trackview.session()->register_with_memento_command_factory(alist->id(), this);
 
        if (alist->parameter().type() == GainAutomation ||
+           alist->parameter().type() == TrimAutomation ||
            alist->parameter().type() == EnvelopeAutomation ||
            desc.unit == ParameterDescriptor::DB) {
                set_uses_gain_mapping (true);
@@ -289,16 +290,16 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y)
 
        cp.move_to (x, y, ControlPoint::Full);
 
+       alist->freeze ();
+       sync_model_with_view_point (cp);
+       alist->thaw ();
+
        reset_line_coords (cp);
 
        if (line_points.size() > 1) {
                line->set_steps (line_points, is_stepped());
        }
 
-       alist->freeze ();
-       sync_model_with_view_point (cp);
-       alist->thaw ();
-
        update_pending = false;
 
        trackview.editor().session()->add_command (
@@ -317,14 +318,17 @@ AutomationLine::reset_line_coords (ControlPoint& cp)
        }
 }
 
-void
+bool
 AutomationLine::sync_model_with_view_points (list<ControlPoint*> cp)
 {
        update_pending = true;
 
+       bool moved = false;
        for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) {
-               sync_model_with_view_point (**i);
+               moved = sync_model_with_view_point (**i) || moved;
        }
+
+       return moved;
 }
 
 string
@@ -372,10 +376,16 @@ AutomationLine::fraction_to_string (double fraction) const
 {
        if (_uses_gain_mapping) {
                char buf[32];
-               if (fraction == 0.0) {
-                       snprintf (buf, sizeof (buf), "-inf");
+               if (_desc.type == GainAutomation || _desc.type == EnvelopeAutomation || _desc.lower == 0) {
+                       if (fraction == 0.0) {
+                               snprintf (buf, sizeof (buf), "-inf");
+                       } else {
+                               snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (slider_position_to_gain_with_max (fraction, _desc.upper)));
+                       }
                } else {
-                       snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (slider_position_to_gain_with_max (fraction, Config->get_max_gain())));
+                       const double lower_db = accurate_coefficient_to_dB (_desc.lower);
+                       const double range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
+                       snprintf (buf, sizeof (buf), "%.1f", lower_db + fraction * range_db);
                }
                return buf;
        } else {
@@ -743,13 +753,13 @@ AutomationLine::end_drag (bool with_push, uint32_t final_index)
        }
 
        alist->freeze ();
-       sync_model_with_view_points (_drag_points);
+       bool moved = sync_model_with_view_points (_drag_points);
 
        if (with_push) {
                ControlPoint* p;
                uint32_t i = final_index;
                while ((p = nth (i)) != 0 && p->can_slide()) {
-                       sync_model_with_view_point (*p);
+                       moved = sync_model_with_view_point (*p) || moved;
                        ++i;
                }
        }
@@ -758,6 +768,12 @@ AutomationLine::end_drag (bool with_push, uint32_t final_index)
 
        update_pending = false;
 
+       if (moved) {
+               /* A point has moved as a result of sync (clamped to integer or boolean
+                  value), update line accordingly. */
+               line->set_steps (line_points, is_stepped());
+       }
+
        trackview.editor().session()->add_command (
                new MementoCommand<AutomationList>(memento_command_binder (), 0, &alist->get_state()));
 
@@ -767,7 +783,7 @@ AutomationLine::end_drag (bool with_push, uint32_t final_index)
        contiguous_points.clear ();
 }
 
-void
+bool
 AutomationLine::sync_model_with_view_point (ControlPoint& cp)
 {
        /* find out where the visual control point is.
@@ -792,6 +808,17 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp)
        view_to_model_coord_y (view_y);
 
        alist->modify (cp.model(), view_x, view_y);
+
+       /* convert back from model to view y for clamping position (for integer/boolean/etc) */
+       model_to_view_coord_y (view_y);
+       const double point_y = _height - (view_y * _height);
+       if (point_y != cp.get_y()) {
+               cp.move_to (cp.get_x(), point_y, ControlPoint::Full);
+               reset_line_coords (cp);
+               return true;
+       }
+
+       return false;
 }
 
 bool
@@ -1165,12 +1192,22 @@ AutomationLine::view_to_model_coord (double& x, double& y) const
 void
 AutomationLine::view_to_model_coord_y (double& y) const
 {
-       /* TODO: This should be more generic (use ParameterDescriptor) */
-       if (alist->parameter().type() == GainAutomation ||
-           alist->parameter().type() == EnvelopeAutomation) {
-               y = slider_position_to_gain_with_max (y, Config->get_max_gain());
+       /* TODO: This should be more generic (use ParameterDescriptor)
+        * or better yet:  Controllable -> set_interface();
+        */
+       if (   alist->parameter().type() == GainAutomation
+           || alist->parameter().type() == EnvelopeAutomation
+           || (_desc.unit == ParameterDescriptor::DB && _desc.lower == 0.)) {
+               y = slider_position_to_gain_with_max (y, _desc.upper);
+               y = max ((double)_desc.lower, y);
+               y = min ((double)_desc.upper, y);
+       } else if (alist->parameter().type() == TrimAutomation
+                  || (_desc.unit == ParameterDescriptor::DB && _desc.lower > 0 && _desc.upper > _desc.lower)) {
+               const double lower_db = accurate_coefficient_to_dB (_desc.lower);
+               const double range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
                y = max (0.0, y);
-               y = min (2.0, y);
+               y = min (1.0, y);
+               y = dB_to_coefficient (lower_db + y * range_db);
        } else if (alist->parameter().type() == PanAzimuthAutomation ||
                   alist->parameter().type() == PanElevationAutomation) {
                y = 1.0 - y;
@@ -1178,8 +1215,10 @@ AutomationLine::view_to_model_coord_y (double& y) const
                y = 2.0 * y - 1.0;
        } else {
                y = y * (double)(alist->get_max_y() - alist->get_min_y()) + alist->get_min_y();
-               if (_desc.toggled || _desc.integer_step) {
+               if (_desc.integer_step) {
                        y = round(y);
+               } else if (_desc.toggled) {
+                       y = (y > 0.5) ? 1.0 : 0.0;
                }
        }
 }
@@ -1188,9 +1227,15 @@ void
 AutomationLine::model_to_view_coord_y (double& y) const
 {
        /* TODO: This should be more generic (use ParameterDescriptor) */
-       if (alist->parameter().type() == GainAutomation ||
-           alist->parameter().type() == EnvelopeAutomation) {
+       if (   alist->parameter().type() == GainAutomation
+           || alist->parameter().type() == EnvelopeAutomation
+           || (_desc.unit == ParameterDescriptor::DB && _desc.lower == 0.)) {
                y = gain_to_slider_position_with_max (y, Config->get_max_gain());
+       } else if (alist->parameter().type() == TrimAutomation
+                  || (_desc.unit == ParameterDescriptor::DB && _desc.lower > 0 && _desc.upper > _desc.lower)) {
+               const double lower_db = accurate_coefficient_to_dB (_desc.lower);
+               const double range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
+               y = (accurate_coefficient_to_dB (y) - lower_db) / range_db;
        } else if (alist->parameter().type() == PanAzimuthAutomation ||
                   alist->parameter().type() == PanElevationAutomation) {
                y = 1.0 - y;