changes to waveform clipping display
authorPaul Davis <paul@linuxaudiosystems.com>
Sat, 29 Jun 2013 00:21:30 +0000 (20:21 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Sat, 29 Jun 2013 00:21:30 +0000 (20:21 -0400)
   * clip level is now -0.9dbFS
   * display of clipping is optional (see Theme Manager window)
   * clipping is based on disk data, unscaled by region gain

gtk2_ardour/ardour3_ui_default.conf
gtk2_ardour/audio_region_view.cc
gtk2_ardour/audio_region_view.h
gtk2_ardour/theme_manager.cc
gtk2_ardour/theme_manager.h
gtk2_ardour/ui_config_vars.h
libs/canvas/canvas/wave_view.h
libs/canvas/wave_view.cc

index e6c4367e800f8f89b064d9175a7f15e0a9f4625e..88970cbbd71d99c920a4d5364fa4b5bf20f719a1 100644 (file)
     <Option name="video timeline bar" value="303030ff"/>
     <Option name="region base" value="99a7b5a0"/>
     <Option name="region area covered by another region" value="505050b0"/>
-    <Option name="waveform fill" value="3d4753dc"/>
+    <Option name="waveform fill" value="ffffffff"/>
     <Option name="clipped waveform" value="ff0000e5"/>
     <Option name="waveform fill" value="bde7b9dc"/>
     <Option name="zero line" value="b5b5b525"/>
index 71f9466b0045a78f3a70b9b5858be026f8ca0ec7..0159022f87c0276999dc3f8783a2f1e69153bbbc 100644 (file)
@@ -233,7 +233,6 @@ AudioRegionView::init (Gdk::Color const & basic_color, bool wfd)
 
        setup_waveform_visibility ();
        setup_waveform_shape ();
-       setup_waveform_scale ();
 
        if (frame_handle_start) {
                frame_handle_start->raise_to_top ();
@@ -1323,6 +1322,12 @@ AudioRegionView::setup_waveform_scale ()
        WaveView::set_global_logscaled (Config->get_waveform_scale() == Logarithmic);
 }
 
+void
+AudioRegionView::setup_waveform_clipping ()
+{
+       WaveView::set_global_show_waveform_clipping (ARDOUR_UI::config()->get_show_waveform_clipping());
+}
+
 GhostRegion*
 AudioRegionView::add_ghost (TimeAxisView& tv)
 {
@@ -1433,46 +1438,38 @@ AudioRegionView::set_one_waveform_color (ArdourCanvas::WaveView* wave)
 {
        ArdourCanvas::Color fill;
        ArdourCanvas::Color outline;
+       
+       if (_selected) {
+               if (_region->muted()) {
+                       outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm(), MUTED_ALPHA);
+               } else {
+                       outline = ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm();
+               }
+               fill = ARDOUR_UI::config()->get_canvasvar_SelectedWaveFormFill();
+       } else {
+               if (_recregion) {
+                       outline = ARDOUR_UI::config()->get_canvasvar_RecWaveForm();
+                       fill = ARDOUR_UI::config()->get_canvasvar_RecWaveFormFill();
+               } else {
+                       if (_region->muted()) {
+                               outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_WaveForm(), MUTED_ALPHA);
+                       } else {
+                               outline = ARDOUR_UI::config()->get_canvasvar_WaveForm();
+                       }
+                       fill = ARDOUR_UI::config()->get_canvasvar_WaveFormFill();
+               }
+       }
 
        if (ARDOUR_UI::config()->get_color_regions_using_track_color()) {
 
-               /* wave color is a saturated, whiter version of the frame's
-                * fill color 
+               /* just use a slightly transparent version of the selected
+                * color so that some of the track color bleeds through
                 */
 
-               ArdourCanvas::Color c = frame->fill_color ();
-               double h, s, v;
-               ArdourCanvas::color_to_hsv (c, h, s, v);
-               
-               /* full saturate */
-               s = 0.45;
-               /* head towards white */
-               v = 0.97;
+               double r, g, b, a;
+               ArdourCanvas::color_to_rgba (fill, r, g, b, a);
+               fill = ArdourCanvas::rgba_to_color (r, g, b, 0.85); /* magic number, not user controllable */
                
-               fill = ArdourCanvas::hsv_to_color (h, s, v, _region->muted() ? MUTED_ALPHA : 1.0);
-               
-       } else {
-
-               if (_selected) {
-                       if (_region->muted()) {
-                               outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm(), MUTED_ALPHA);
-                       } else {
-                               outline = ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm();
-                       }
-                       fill = ARDOUR_UI::config()->get_canvasvar_SelectedWaveFormFill();
-               } else {
-                       if (_recregion) {
-                               outline = ARDOUR_UI::config()->get_canvasvar_RecWaveForm();
-                               fill = ARDOUR_UI::config()->get_canvasvar_RecWaveFormFill();
-                       } else {
-                               if (_region->muted()) {
-                                       outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_WaveForm(), MUTED_ALPHA);
-                               } else {
-                                       outline = ARDOUR_UI::config()->get_canvasvar_WaveForm();
-                               }
-                               fill = ARDOUR_UI::config()->get_canvasvar_WaveFormFill();
-                       }
-               }
        }
                
        wave->set_fill_color (fill);
@@ -1688,5 +1685,7 @@ AudioRegionView::parameter_changed (string const & p)
                setup_waveform_scale ();
        } else if (p == "waveform-shape") {
                setup_waveform_shape ();
+       } else if (p == "show-waveform-clipping") {
+               setup_waveform_clipping ();
        }
 }
index 02de3edbb1e43deb5d4891375923e2d3849d497a..353d0dc93777aeccf0b58d2c123df5b81dfc622b 100644 (file)
@@ -208,6 +208,7 @@ private:
        void setup_waveform_visibility ();
        void setup_waveform_shape ();
        void setup_waveform_scale ();
+       void setup_waveform_clipping ();
 
        /** A ScopedConnection for each PeaksReady callback (one per channel).  Each member
         *  may be 0 if no connection exists.
index ff37c315cf60a490be2dbb5df86b1e7bc84f550e..3514d918bd051e360a07743eefe69de04ff9a754 100644 (file)
@@ -60,6 +60,7 @@ ThemeManager::ThemeManager()
        , reset_button (_("Restore Defaults"))
        , flat_buttons (_("Draw \"flat\" buttons"))
        , region_color_button (_("Color regions using their track's color"))
+       , show_clipping_button (_("Show waveform clipping"))
        , waveform_gradient_depth (0, 1.0, 0.05)
        , waveform_gradient_depth_label (_("Waveforms color gradient depth"))
        , timeline_item_gradient_depth (0, 1.0, 0.05)
@@ -104,6 +105,7 @@ ThemeManager::ThemeManager()
 #endif
        vbox->pack_start (flat_buttons, PACK_SHRINK);
        vbox->pack_start (region_color_button, PACK_SHRINK);
+       vbox->pack_start (show_clipping_button, PACK_SHRINK);
 
        Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox());
        hbox->set_spacing (6);
@@ -133,6 +135,7 @@ ThemeManager::ThemeManager()
 
        flat_buttons.set_active (ARDOUR_UI::config()->get_flat_buttons());
        region_color_button.set_active (ARDOUR_UI::config()->get_color_regions_using_track_color());
+       show_clipping_button.set_active (ARDOUR_UI::config()->get_show_waveform_clipping());
 
        color_dialog.get_ok_button()->signal_clicked().connect (sigc::bind (sigc::mem_fun (color_dialog, &Gtk::Dialog::response), RESPONSE_ACCEPT));
        color_dialog.get_cancel_button()->signal_clicked().connect (sigc::bind (sigc::mem_fun (color_dialog, &Gtk::Dialog::response), RESPONSE_CANCEL));
@@ -141,6 +144,7 @@ ThemeManager::ThemeManager()
        reset_button.signal_clicked().connect (sigc::mem_fun (*this, &ThemeManager::reset_canvas_colors));
        flat_buttons.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_flat_buttons_toggled));
        region_color_button.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_region_color_toggled));
+       show_clipping_button.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_show_clip_toggled));
        waveform_gradient_depth.signal_value_changed().connect (sigc::mem_fun (*this, &ThemeManager::on_waveform_gradient_depth_change));
        timeline_item_gradient_depth.signal_value_changed().connect (sigc::mem_fun (*this, &ThemeManager::on_timeline_item_gradient_depth_change));
        all_dialogs.signal_toggled().connect (sigc::mem_fun (*this, &ThemeManager::on_all_dialogs_toggled));
@@ -292,6 +296,13 @@ ThemeManager::on_region_color_toggled ()
        ARDOUR_UI::config()->set_dirty ();
 }
 
+void
+ThemeManager::on_show_clip_toggled ()
+{
+       ARDOUR_UI::config()->set_show_waveform_clipping (show_clipping_button.get_active());
+       ARDOUR_UI::config()->set_dirty ();
+}
+
 void
 ThemeManager::on_all_dialogs_toggled ()
 {
index c0d6cf8f743ec30f2a16a495fe4926711a43aa3b..7c8d81fef9d9ec0a61687920b548b34669348c88 100644 (file)
@@ -45,6 +45,7 @@ class ThemeManager : public ArdourWindow
        void on_light_theme_button_toggled ();
        void on_flat_buttons_toggled ();
         void on_region_color_toggled ();
+        void on_show_clip_toggled ();
         void on_waveform_gradient_depth_change ();
         void on_timeline_item_gradient_depth_change ();
        void on_all_dialogs_toggled ();
@@ -75,6 +76,7 @@ class ThemeManager : public ArdourWindow
        Gtk::Button reset_button;
        Gtk::CheckButton flat_buttons;
        Gtk::CheckButton region_color_button;
+       Gtk::CheckButton show_clipping_button;
         Gtk::HScale waveform_gradient_depth;
         Gtk::Label waveform_gradient_depth_label;
         Gtk::HScale timeline_item_gradient_depth;
index 84f293649fffd6e60b604bb6c2494b4048c56545..18bda554574bcf98727e7d4d55453746b616837a 100644 (file)
@@ -23,4 +23,5 @@ UI_CONFIG_VARIABLE(float, waveform_gradient_depth, "waveform-gradient-depth", 0.
 UI_CONFIG_VARIABLE(float, timeline_item_gradient_depth, "timeline-item-gradient-depth", 1.3)
 UI_CONFIG_VARIABLE(bool, all_floating_windows_are_dialogs, "all-floating-windows-are-dialogs", false)
 UI_CONFIG_VARIABLE (bool, color_regions_using_track_color, "color-regions-using-track-color", false)
+UI_CONFIG_VARIABLE (bool, show_waveform_clipping, "show-waveform-clipping", true)
 
index 250eeb3b942965d7fe8bda77173d101b1709a566..fc39d7e555484f413de73f0bf165b553f7e6f2af 100644 (file)
@@ -106,6 +106,7 @@ public:
         static void set_global_gradient_depth (double);
         static void set_global_logscaled (bool);
         static void set_global_shape (Shape);
+        static void set_global_show_waveform_clipping (bool);
     
         static double  global_gradient_depth()  { return _global_gradient_depth; }
         static bool    global_logscaled()  { return _global_logscaled; }
@@ -161,6 +162,7 @@ private:
         static double _global_gradient_depth;
         static bool   _global_logscaled;
         static Shape  _global_shape;
+        static bool   _global_show_waveform_clipping;
 
         static PBD::Signal0<void> VisualPropertiesChanged;
 
index ce5c87ccfd12e90e213f1c9e86a2ec5906115aba..4ea9ff9fd31fe6c60349b4030981f40fe5a7d6b5 100644 (file)
@@ -44,6 +44,7 @@ using namespace ArdourCanvas;
 double WaveView::_global_gradient_depth = 0.6;
 bool WaveView::_global_logscaled = false;
 WaveView::Shape WaveView::_global_shape = WaveView::Normal;
+bool WaveView::_global_show_waveform_clipping = true;
 
 PBD::Signal0<void> WaveView::VisualPropertiesChanged;
 
@@ -177,7 +178,18 @@ WaveView::draw_image (PeakData* _peaks, int n_peaks) const
        Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create (_image);
 
        boost::scoped_array<LineTips> tips (new LineTips[n_peaks]);
-       const double clip_level = 1.0;
+
+       /* Clip level nominally set to -0.9dBFS to account for inter-sample
+          interpolation possibly clipping (value may be too low).
+
+          We adjust by the region's own gain (but note: not by any gain
+          automation or its gain envelope) so that clip indicators are closer
+          to providing data about on-disk data. This multiplication is
+          needed because the data we get from AudioRegion::read_peaks()
+          has been scaled by scale_amplitude() already.
+       */
+
+       const double clip_level = 0.98853 * _region->scale_amplitude();
 
        if (_shape == WaveView::Rectified) {
 
@@ -328,40 +340,43 @@ WaveView::draw_image (PeakData* _peaks, int n_peaks) const
         * modelled on pyramix, except that we add clipping indicators.
         */
 
-       context->set_source_rgba (0, 0, 0, 1.0);
-
-       /* the height of the clip-indicator should be at most 7 pixels,
-          or 5% of the height of the waveview item.
-       */
-       const double clip_height = min (7.0, ceil (_height * 0.05));
-
-       for (int i = 0; i < n_peaks; ++i) {
-               context->move_to (i, tips[i].top);
-
-               bool show_top_clip = (_shape == WaveView::Rectified && (tips[i].clip_max || tips[i].clip_min)) ||
-                       tips[i].clip_max;
-
-               if (show_top_clip) {
-                       context->set_source_rgba (1.0, 0, 0, 1.0);
-                       context->rel_line_to (0, clip_height);
-                       context->stroke ();
-                       context->set_source_rgba (0.0, 0, 0, 1.0);
-               } else {
-                       context->rel_line_to (0, 1.0);
-                       context->stroke ();
-               }
-
-               if (_shape != WaveView::Rectified) {
-                       context->move_to (i, tips[i].bot);
-                       if (tips[i].clip_min) {
+       if (_global_show_waveform_clipping) {
+               
+               context->set_source_rgba (0, 0, 0, 1.0);
+               
+               /* the height of the clip-indicator should be at most 7 pixels,
+                  or 5% of the height of the waveview item.
+               */
+               const double clip_height = min (7.0, ceil (_height * 0.05));
+               
+               for (int i = 0; i < n_peaks; ++i) {
+                       context->move_to (i, tips[i].top);
+                       
+                       bool show_top_clip = (_shape == WaveView::Rectified && (tips[i].clip_max || tips[i].clip_min)) ||
+                               tips[i].clip_max;
+                       
+                       if (show_top_clip) {
                                context->set_source_rgba (1.0, 0, 0, 1.0);
-                               context->rel_line_to (0, -clip_height);
+                               context->rel_line_to (0, clip_height);
                                context->stroke ();
                                context->set_source_rgba (0.0, 0, 0, 1.0);
                        } else {
-                               context->rel_line_to (0, -1.0);
+                               context->rel_line_to (0, 1.0);
                                context->stroke ();
                        }
+
+                       if (_shape != WaveView::Rectified) {
+                               context->move_to (i, tips[i].bot);
+                               if (tips[i].clip_min) {
+                                       context->set_source_rgba (1.0, 0, 0, 1.0);
+                                       context->rel_line_to (0, -clip_height);
+                                       context->stroke ();
+                                       context->set_source_rgba (0.0, 0, 0, 1.0);
+                               } else {
+                                       context->rel_line_to (0, -1.0);
+                                       context->stroke ();
+                               }
+                       }
                }
        }
 
@@ -662,3 +677,12 @@ WaveView::set_global_gradient_depth (double depth)
                VisualPropertiesChanged (); /* EMIT SIGNAL */
        }
 }
+
+void
+WaveView::set_global_show_waveform_clipping (bool yn)
+{
+       if (_global_show_waveform_clipping != yn) {
+               _global_show_waveform_clipping = yn;
+               VisualPropertiesChanged (); /* EMIT SIGNAL */
+       }
+}