mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 07:45:00 +01:00
use existing partial existing waveview images (if they exist) while waiting for the full ones
This commit is contained in:
parent
9e44e46c4a
commit
bc945bb3d3
2 changed files with 92 additions and 21 deletions
|
|
@ -143,7 +143,8 @@ class LIBCANVAS_API WaveViewCache
|
||||||
Coord height,
|
Coord height,
|
||||||
float amplitude,
|
float amplitude,
|
||||||
Color fill_color,
|
Color fill_color,
|
||||||
double samples_per_pixel);
|
double samples_per_pixel,
|
||||||
|
bool& full_image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* an unsorted, unindexd collection of cache entries associated with
|
/* an unsorted, unindexd collection of cache entries associated with
|
||||||
|
|
@ -250,6 +251,8 @@ public:
|
||||||
double gradient_depth() const { return _gradient_depth; }
|
double gradient_depth() const { return _gradient_depth; }
|
||||||
void set_shape (Shape);
|
void set_shape (Shape);
|
||||||
|
|
||||||
|
void set_always_get_image_in_thread (bool yn);
|
||||||
|
|
||||||
/* currently missing because we don't need them (yet):
|
/* currently missing because we don't need them (yet):
|
||||||
set_shape_independent();
|
set_shape_independent();
|
||||||
set_logscaled_independent()
|
set_logscaled_independent()
|
||||||
|
|
@ -330,6 +333,12 @@ public:
|
||||||
*/
|
*/
|
||||||
mutable bool get_image_in_thread;
|
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
|
/** Set to true by render(). Used so that we know if the wave view
|
||||||
* has actually been displayed on screen. ::set_height() when this
|
* has actually been displayed on screen. ::set_height() when this
|
||||||
* is true does not use get_image_in_thread, because it implies
|
* is true does not use get_image_in_thread, because it implies
|
||||||
|
|
@ -351,8 +360,8 @@ public:
|
||||||
void handle_visual_property_change ();
|
void handle_visual_property_change ();
|
||||||
void handle_clip_level_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 (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) 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;
|
ArdourCanvas::Coord y_extent (double, bool) const;
|
||||||
void draw_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int n_peaks, boost::shared_ptr<WaveViewThreadRequest>) const;
|
void draw_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int n_peaks, boost::shared_ptr<WaveViewThreadRequest>) const;
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ WaveView::WaveView (Canvas* c, boost::shared_ptr<ARDOUR::AudioRegion> region)
|
||||||
, _start_shift (0.0)
|
, _start_shift (0.0)
|
||||||
, _region_start (region->start())
|
, _region_start (region->start())
|
||||||
, get_image_in_thread (false)
|
, get_image_in_thread (false)
|
||||||
|
, always_get_image_in_thread (false)
|
||||||
, rendered (false)
|
, rendered (false)
|
||||||
{
|
{
|
||||||
VisualPropertiesChanged.connect_same_thread (invalidation_connection, boost::bind (&WaveView::handle_visual_property_change, this));
|
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_amplitude (region->scale_amplitude ())
|
||||||
, _region_start (region->start())
|
, _region_start (region->start())
|
||||||
, get_image_in_thread (false)
|
, get_image_in_thread (false)
|
||||||
|
, always_get_image_in_thread (false)
|
||||||
, rendered (false)
|
, rendered (false)
|
||||||
{
|
{
|
||||||
VisualPropertiesChanged.connect_same_thread (invalidation_connection, boost::bind (&WaveView::handle_visual_property_change, this));
|
VisualPropertiesChanged.connect_same_thread (invalidation_connection, boost::bind (&WaveView::handle_visual_property_change, this));
|
||||||
|
|
@ -139,6 +141,12 @@ WaveView::image_ready ()
|
||||||
redraw ();
|
redraw ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WaveView::set_always_get_image_in_thread (bool yn)
|
||||||
|
{
|
||||||
|
always_get_image_in_thread = yn;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WaveView::handle_visual_property_change ()
|
WaveView::handle_visual_property_change ()
|
||||||
{
|
{
|
||||||
|
|
@ -714,9 +722,11 @@ WaveView::cache_request_result (boost::shared_ptr<WaveViewThreadRequest> req) co
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<WaveViewCache::Entry>
|
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;
|
boost::shared_ptr<WaveViewCache::Entry> ret;
|
||||||
|
|
||||||
|
full_image = true;
|
||||||
|
|
||||||
/* this is called from a ::render() call, when we need an image to
|
/* this is called from a ::render() call, when we need an image to
|
||||||
draw with.
|
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 */
|
/* 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);
|
boost::shared_ptr<WaveViewThreadRequest> req (new WaveViewThreadRequest);
|
||||||
|
|
||||||
|
|
@ -799,19 +809,18 @@ WaveView::get_image (framepos_t start, framepos_t end) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<WaveViewCache::Entry>
|
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) {
|
if (!images) {
|
||||||
return boost::shared_ptr<WaveViewCache::Entry>();
|
return boost::shared_ptr<WaveViewCache::Entry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return images->lookup_image (_region->audio_source (_channel), start, end, _channel,
|
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
|
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;
|
// cerr << debug_name() << " will need image spanning " << sample_start << " .. " << sample_end << " region spans " << _region_start << " .. " << region_end() << endl;
|
||||||
|
|
||||||
double image_offset;
|
double image_offset;
|
||||||
|
boost::shared_ptr<WaveViewCache::Entry> image_to_draw;
|
||||||
|
|
||||||
if (_current_image) {
|
if (_current_image) {
|
||||||
|
|
||||||
/* check it covers the right sample range */
|
/* check it covers the right sample range */
|
||||||
|
|
@ -1007,26 +1017,37 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
|
||||||
} else {
|
} else {
|
||||||
/* timestamp our continuing use of this image/cache entry */
|
/* timestamp our continuing use of this image/cache entry */
|
||||||
images->use (_region->audio_source (_channel), _current_image);
|
images->use (_region->audio_source (_channel), _current_image);
|
||||||
|
image_to_draw = _current_image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_current_image) {
|
if (!image_to_draw) {
|
||||||
|
|
||||||
/* look it up */
|
/* 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
|
/* image not currently available. A redraw will be scheduled
|
||||||
when it is ready.
|
when it is ready.
|
||||||
*/
|
*/
|
||||||
return;
|
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;
|
// 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;
|
//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
|
/* round image origin position to an exact pixel in device space to
|
||||||
* avoid blurring
|
* avoid blurring
|
||||||
|
|
@ -1053,7 +1087,13 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
|
||||||
y = round (y);
|
y = round (y);
|
||||||
context->device_to_user (x, 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 ();
|
context->fill ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1419,7 +1459,8 @@ WaveViewCache::lookup_image (boost::shared_ptr<ARDOUR::AudioSource> src,
|
||||||
Coord height,
|
Coord height,
|
||||||
float amplitude,
|
float amplitude,
|
||||||
Color fill_color,
|
Color fill_color,
|
||||||
double samples_per_pixel)
|
double samples_per_pixel,
|
||||||
|
bool& full_coverage)
|
||||||
{
|
{
|
||||||
ImageCache::iterator x;
|
ImageCache::iterator x;
|
||||||
|
|
||||||
|
|
@ -1429,7 +1470,9 @@ WaveViewCache::lookup_image (boost::shared_ptr<ARDOUR::AudioSource> src,
|
||||||
}
|
}
|
||||||
|
|
||||||
CacheLine& caches = x->second;
|
CacheLine& caches = x->second;
|
||||||
|
boost::shared_ptr<Entry> best_partial;
|
||||||
|
framecnt_t max_coverage = 0;
|
||||||
|
|
||||||
/* Find a suitable ImageSurface, if it exists.
|
/* 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) {
|
if (end <= e->end && start >= e->start) {
|
||||||
/* found an image that covers the range we need */
|
/* found an image that covers the range we need */
|
||||||
use (src, e);
|
use (src, e);
|
||||||
|
full_coverage = true;
|
||||||
return e;
|
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> ();
|
return boost::shared_ptr<Entry> ();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue