use existing partial existing waveview images (if they exist) while waiting for the...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 4 Jun 2015 21:45:58 +0000 (17:45 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 4 Jun 2015 22:22:55 +0000 (18:22 -0400)
libs/canvas/canvas/wave_view.h
libs/canvas/wave_view.cc

index 9a4cbafa7c439a6fc44d67a092c3c5f0c9158f1a..9f87855e5412788183c92fb0d8285cb6ffa8332a 100644 (file)
@@ -143,7 +143,8 @@ class LIBCANVAS_API WaveViewCache
                                                Coord height,
                                                float amplitude,
                                                Color fill_color,
-                                               double samples_per_pixel);
+                                               double samples_per_pixel,
+                                               bool& full_image);
 
   private:
         /* an unsorted, unindexd collection of cache entries associated with
@@ -250,6 +251,8 @@ public:
         double gradient_depth() const { return _gradient_depth; }
         void set_shape (Shape);
 
+        void set_always_get_image_in_thread (bool yn);
+        
         /* currently missing because we don't need them (yet):
           set_shape_independent();
           set_logscaled_independent()
@@ -330,6 +333,12 @@ public:
        */
        mutable bool get_image_in_thread;
 
+       /** If true, calls to get_image() will render a missing wave image
+          in the calling thread. Set true for waveviews we expect to 
+          keep updating (e.g. while recording)
+       */
+       bool always_get_image_in_thread;
+       
        /** Set to true by render(). Used so that we know if the wave view
         * has actually been displayed on screen. ::set_height() when this
         * is true does not use get_image_in_thread, because it implies
@@ -351,8 +360,8 @@ public:
         void handle_visual_property_change ();
         void handle_clip_level_change ();
 
-        boost::shared_ptr<WaveViewCache::Entry> get_image (framepos_t start, framepos_t end) const;
-        boost::shared_ptr<WaveViewCache::Entry> get_image_from_cache (framepos_t start, framepos_t end) const;
+        boost::shared_ptr<WaveViewCache::Entry> get_image (framepos_t start, framepos_t end, bool& full_image) const;
+        boost::shared_ptr<WaveViewCache::Entry> get_image_from_cache (framepos_t start, framepos_t end, bool& full_image) const;
        
         ArdourCanvas::Coord y_extent (double, bool) const;
         void draw_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int n_peaks, boost::shared_ptr<WaveViewThreadRequest>) const;
index a756cfe430a1547ff9c414ac9d7144bc7694f419..fc7a7e868fdf3c0b58c066de9bfc1fcdcfb01a99 100644 (file)
@@ -87,6 +87,7 @@ WaveView::WaveView (Canvas* c, boost::shared_ptr<ARDOUR::AudioRegion> region)
        , _start_shift (0.0)
        , _region_start (region->start())
        , get_image_in_thread (false)
+       , always_get_image_in_thread (false)
        , rendered (false)
 {
        VisualPropertiesChanged.connect_same_thread (invalidation_connection, boost::bind (&WaveView::handle_visual_property_change, this));
@@ -114,6 +115,7 @@ WaveView::WaveView (Item* parent, boost::shared_ptr<ARDOUR::AudioRegion> region)
        , _region_amplitude (region->scale_amplitude ())
        , _region_start (region->start())
        , get_image_in_thread (false)
+       , always_get_image_in_thread (false)
        , rendered (false)
 {
        VisualPropertiesChanged.connect_same_thread (invalidation_connection, boost::bind (&WaveView::handle_visual_property_change, this));
@@ -139,6 +141,12 @@ WaveView::image_ready ()
        redraw ();
 }
 
+void
+WaveView::set_always_get_image_in_thread (bool yn)
+{
+       always_get_image_in_thread = yn;
+}
+
 void
 WaveView::handle_visual_property_change ()
 {
@@ -714,9 +722,11 @@ WaveView::cache_request_result (boost::shared_ptr<WaveViewThreadRequest> req) co
 }
 
 boost::shared_ptr<WaveViewCache::Entry>
-WaveView::get_image (framepos_t start, framepos_t end) const
+WaveView::get_image (framepos_t start, framepos_t end, bool& full_image) const
 {
        boost::shared_ptr<WaveViewCache::Entry> ret;
+
+       full_image = true;
        
        /* this is called from a ::render() call, when we need an image to
           draw with.
@@ -759,13 +769,13 @@ WaveView::get_image (framepos_t start, framepos_t end) const
 
                /* no current image draw request, so look in the cache */
                
-               ret = get_image_from_cache (start, end);
+               ret = get_image_from_cache (start, end, full_image);
 
        }
 
-       if (!ret) {
+       if (!ret || !full_image) {
 
-               if (get_image_in_thread) {
+               if (get_image_in_thread || always_get_image_in_thread) {
 
                        boost::shared_ptr<WaveViewThreadRequest> req (new WaveViewThreadRequest);
 
@@ -799,19 +809,18 @@ WaveView::get_image (framepos_t start, framepos_t end) const
                }
        }
 
-       
        return ret;
 }
 
 boost::shared_ptr<WaveViewCache::Entry>
-WaveView::get_image_from_cache (framepos_t start, framepos_t end) const
+WaveView::get_image_from_cache (framepos_t start, framepos_t end, bool& full) const
 {
        if (!images) {
                return boost::shared_ptr<WaveViewCache::Entry>();
        }
 
        return images->lookup_image (_region->audio_source (_channel), start, end, _channel,
-                                    _height, _region_amplitude, _fill_color, _samples_per_pixel);
+                                    _height, _region_amplitude, _fill_color, _samples_per_pixel, full);
 }
 
 void
@@ -996,7 +1005,8 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
        // cerr << debug_name() << " will need image spanning " << sample_start << " .. " << sample_end << " region spans " << _region_start << " .. " << region_end() << endl;
 
        double image_offset;
-
+       boost::shared_ptr<WaveViewCache::Entry> image_to_draw;
+       
        if (_current_image) {
 
                /* check it covers the right sample range */
@@ -1007,26 +1017,37 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
                } else {
                        /* timestamp our continuing use of this image/cache entry */
                        images->use (_region->audio_source (_channel), _current_image);
+                       image_to_draw = _current_image;
                }
        }
 
-       if (!_current_image) {
+       if (!image_to_draw) {
 
                /* look it up */
-               
-               _current_image = get_image (sample_start, sample_end);
 
-               if (!_current_image) {
+               bool full_image;
+               image_to_draw = get_image (sample_start, sample_end, full_image);
+               
+               if (!image_to_draw) {
                        /* image not currently available. A redraw will be scheduled
                           when it is ready.
                        */
                        return;
                }
+
+               if (full_image) {
+                       /* found an image that covers our entire sample range,
+                        * so keep a reference to it.
+                        */
+                       _current_image = image_to_draw;
+               }
        }
 
-       /* fix up offset: returned value is the first sample of the returned image */
+       /* compute the first pixel of the image that should be used when we
+        * render the specified range. 
+        */
 
-       image_offset = (_current_image->start - _region_start) / _samples_per_pixel;
+       image_offset = (image_to_draw->start - _region_start) / _samples_per_pixel;
        
        // cerr << "Offset into image to place at zero: " << image_offset << endl;
 
@@ -1040,7 +1061,20 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
                //image_offset += _start_shift;
        }
        
-       context->rectangle (draw_start, draw.y0, draw_end - draw_start, draw.height());
+       /* the image may only be a best-effort ... it may not span the entire
+        * range requested, though it is guaranteed to cover the start. So
+        * determine how many pixels we can actually draw.
+        */
+
+       double draw_width;
+       
+       if (image_to_draw != _current_image) {
+               draw_width = min ((double) image_to_draw->image->get_width() - image_offset, (draw_end - draw_start));
+       } else {
+               draw_width = draw_end - draw_start;
+       }
+
+       context->rectangle (draw_start, draw.y0, draw_width, draw.height());
 
        /* round image origin position to an exact pixel in device space to
         * avoid blurring
@@ -1053,7 +1087,13 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
        y = round (y);
        context->device_to_user (x, y);
 
-       context->set_source (_current_image->image, x, y);
+       /* the coordinates specify where in "user coordinates" (i.e. what we
+        * generally call "canvas coordinates" in this code) the image origin
+        * will appear. So specifying (10,10) will put the upper left corner of
+        * the image at (10,10) in user space.
+        */
+       
+       context->set_source (image_to_draw->image, x, y);
        context->fill ();
 
 }
@@ -1419,7 +1459,8 @@ WaveViewCache::lookup_image (boost::shared_ptr<ARDOUR::AudioSource> src,
                              Coord height,
                              float amplitude,
                              Color fill_color,
-                             double samples_per_pixel)
+                             double samples_per_pixel,
+                             bool& full_coverage)
 {
        ImageCache::iterator x;
        
@@ -1429,7 +1470,9 @@ WaveViewCache::lookup_image (boost::shared_ptr<ARDOUR::AudioSource> src,
        }
 
        CacheLine& caches = x->second;
-
+       boost::shared_ptr<Entry> best_partial;
+       framecnt_t max_coverage = 0;
+       
        /* Find a suitable ImageSurface, if it exists.
        */
 
@@ -1448,8 +1491,27 @@ WaveViewCache::lookup_image (boost::shared_ptr<ARDOUR::AudioSource> src,
                if (end <= e->end && start >= e->start) {
                        /* found an image that covers the range we need */
                        use (src, e);
+                       full_coverage = true;
                        return e;
                }
+
+               if (start >= e->start) {
+                       /* found an image that covers the start, but not the
+                        * end. See if it is longer than any other similar
+                        * partial image that we've found so far.
+                        */
+
+                       if ((e->end - e->start) > max_coverage) {
+                               best_partial = e;
+                               max_coverage = e->end - e->start;
+                       }
+               }
+       }
+
+       if (best_partial) {
+               use (src, best_partial);
+               full_coverage = false;
+               return best_partial;
        }
 
        return boost::shared_ptr<Entry> ();