13
0

use existing partial existing waveview images (if they exist) while waiting for the full ones

This commit is contained in:
Paul Davis 2015-06-04 17:45:58 -04:00
parent 9e44e46c4a
commit bc945bb3d3
2 changed files with 92 additions and 21 deletions

View 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;

View 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> ();