Merge branch 'waveview_hacks' of https://github.com/nmains/ardour into cairocanvas

This commit is contained in:
Paul Davis 2014-07-18 10:46:22 -04:00
commit 5424119b55
3 changed files with 150 additions and 120 deletions

View file

@ -32,7 +32,7 @@ using namespace ARDOUR;
using namespace PBD; using namespace PBD;
MissingFileDialog::MissingFileDialog (Session* s, const std::string& path, DataType type) MissingFileDialog::MissingFileDialog (Session* s, const std::string& path, DataType type)
: ArdourDialog (_("Missing File!"), true, false) : ArdourDialog (_("Missing File"), true, false)
, filetype (type) , filetype (type)
, chooser (_("Select a folder to search"), FILE_CHOOSER_ACTION_SELECT_FOLDER) , chooser (_("Select a folder to search"), FILE_CHOOSER_ACTION_SELECT_FOLDER)
, use_chosen (_("Add chosen folder to search path, and try again")) , use_chosen (_("Add chosen folder to search path, and try again"))
@ -66,7 +66,7 @@ MissingFileDialog::MissingFileDialog (Session* s, const std::string& path, DataT
oss << *i << endl; oss << *i << endl;
} }
msg.set_justify (JUSTIFY_CENTER); msg.set_justify (JUSTIFY_LEFT);
msg.set_markup (string_compose (_("%1 cannot find the %2 file\n\n<i>%3</i>\n\nin any of these folders:\n\n\ msg.set_markup (string_compose (_("%1 cannot find the %2 file\n\n<i>%3</i>\n\nin any of these folders:\n\n\
<tt>%4</tt>\n\n"), PROGRAM_NAME, typestr, Glib::Markup::escape_text(path), Glib::Markup::escape_text (oss.str()))); <tt>%4</tt>\n\n"), PROGRAM_NAME, typestr, Glib::Markup::escape_text(path), Glib::Markup::escape_text (oss.str())));

View file

@ -59,19 +59,19 @@ public:
Coord height; Coord height;
float amplitude; float amplitude;
Color fill_color; Color fill_color;
Color outline_color;
framepos_t start; framepos_t start;
framepos_t end; framepos_t end;
Cairo::RefPtr<Cairo::ImageSurface> image; Cairo::RefPtr<Cairo::ImageSurface> image;
CacheEntry() :
channel (0), height (0), amplitude(0), fill_color (0), CacheEntry(int chan, Coord hght, float amp, Color fcl, framepos_t strt, framepos_t ed, Cairo::RefPtr<Cairo::ImageSurface> img) :
outline_color (0), start (0), end (0), image (0) {}
CacheEntry(int chan, Coord hght, float amp, Color fcol, Color ocol, channel (chan), height (hght), amplitude (amp), fill_color (fcl),
framepos_t strt, framepos_t ed, Cairo::RefPtr<Cairo::ImageSurface> img) : start (strt), end (ed), image (img) {}
channel (chan), height (hght), amplitude (amp), fill_color (fcol),
outline_color (ocol), start (strt), end (ed), image (img) {}
}; };
/* final ImageSurface rendered with colours */
Cairo::RefPtr<Cairo::ImageSurface> _image;
/* Displays a single channel of waveform data for the given Region. /* Displays a single channel of waveform data for the given Region.
x = 0 in the waveview corresponds to the first waveform datum taken x = 0 in the waveview corresponds to the first waveform datum taken

View file

@ -226,8 +226,7 @@ WaveView::invalidate_image_cache ()
if (_channel != caches[i].channel if (_channel != caches[i].channel
|| _height != caches[i].height || _height != caches[i].height
|| _region_amplitude != caches[i].amplitude || _region_amplitude != caches[i].amplitude
|| _fill_color != caches[i].fill_color || _fill_color != caches[i].fill_color) {
|| _outline_color != caches[i].outline_color) {
continue; continue;
} }
@ -266,8 +265,7 @@ WaveView::consolidate_image_cache () const
if (_channel != caches[i].channel if (_channel != caches[i].channel
|| _height != caches[i].height || _height != caches[i].height
|| _region_amplitude != caches[i].amplitude || _region_amplitude != caches[i].amplitude
|| _fill_color != caches[i].fill_color || _fill_color != caches[i].fill_color) {
|| _outline_color != caches[i].outline_color) {
other_entries++; other_entries++;
continue; continue;
@ -281,8 +279,7 @@ WaveView::consolidate_image_cache () const
if (i == j || _channel != caches[j].channel if (i == j || _channel != caches[j].channel
|| _height != caches[i].height || _height != caches[i].height
|| _region_amplitude != caches[i].amplitude || _region_amplitude != caches[i].amplitude
|| _fill_color != caches[i].fill_color || _fill_color != caches[i].fill_color) {
|| _outline_color != caches[i].outline_color) {
continue; continue;
} }
@ -358,10 +355,32 @@ struct LineTips {
LineTips() : top (0.0), bot (0.0), clip_max (false), clip_min (false) {} LineTips() : top (0.0), bot (0.0), clip_max (false), clip_min (false) {}
}; };
struct ImageSet {
Cairo::RefPtr<Cairo::ImageSurface> wave;
Cairo::RefPtr<Cairo::ImageSurface> outline;
Cairo::RefPtr<Cairo::ImageSurface> clip;
Cairo::RefPtr<Cairo::ImageSurface> zero;
ImageSet() :
wave (0), outline (0), clip (0), zero (0) {}
};
void void
WaveView::draw_image (Cairo::RefPtr<Cairo::ImageSurface>& image, PeakData* _peaks, int n_peaks) const WaveView::draw_image (Cairo::RefPtr<Cairo::ImageSurface>& image, PeakData* _peaks, int n_peaks) const
{ {
Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create (image);
ImageSet images;
images.wave = Cairo::ImageSurface::create (Cairo::FORMAT_A8, n_peaks, _height);
images.outline = Cairo::ImageSurface::create (Cairo::FORMAT_A8, n_peaks, _height);
images.clip = Cairo::ImageSurface::create (Cairo::FORMAT_A8, n_peaks, _height);
images.zero = Cairo::ImageSurface::create (Cairo::FORMAT_A8, n_peaks, _height);
Cairo::RefPtr<Cairo::Context> wave_context = Cairo::Context::create (images.wave);
Cairo::RefPtr<Cairo::Context> outline_context = Cairo::Context::create (images.outline);
Cairo::RefPtr<Cairo::Context> clip_context = Cairo::Context::create (images.clip);
Cairo::RefPtr<Cairo::Context> zero_context = Cairo::Context::create (images.zero);
boost::scoped_array<LineTips> tips (new LineTips[n_peaks]); boost::scoped_array<LineTips> tips (new LineTips[n_peaks]);
/* Clip level nominally set to -0.9dBFS to account for inter-sample /* Clip level nominally set to -0.9dBFS to account for inter-sample
@ -470,47 +489,26 @@ WaveView::draw_image (Cairo::RefPtr<Cairo::ImageSurface>& image, PeakData* _peak
} }
} }
Color alpha_one = rgba_to_color (0, 0, 0, 1.0);
if (gradient_depth() != 0.0) { set_source_rgba (wave_context, alpha_one);
set_source_rgba (outline_context, alpha_one);
Cairo::RefPtr<Cairo::LinearGradient> gradient (Cairo::LinearGradient::create (0, 0, 0, _height)); set_source_rgba (clip_context, alpha_one);
set_source_rgba (zero_context, alpha_one);
double stops[3];
double r, g, b, a;
if (_shape == Rectified) {
stops[0] = 0.1;
stops[0] = 0.3;
stops[0] = 0.9;
} else {
stops[0] = 0.1;
stops[1] = 0.5;
stops[2] = 0.9;
}
color_to_rgba (_fill_color, r, g, b, a);
gradient->add_color_stop_rgba (stops[0], r, g, b, a);
gradient->add_color_stop_rgba (stops[2], r, g, b, a);
/* generate a new color for the middle of the gradient */
double h, s, v;
color_to_hsv (_fill_color, h, s, v);
/* change v towards white */
v *= 1.0 - gradient_depth();
Color center = hsv_to_color (h, s, v, a);
color_to_rgba (center, r, g, b, a);
gradient->add_color_stop_rgba (stops[1], r, g, b, a);
context->set_source (gradient);
} else {
set_source_rgba (context, _fill_color);
}
/* ensure single-pixel lines */ /* ensure single-pixel lines */
context->set_line_width (0.5); wave_context->set_line_width (0.5);
context->translate (0.5, 0.0); wave_context->translate (0.5, 0.0);
outline_context->set_line_width (0.5);
outline_context->translate (0.5, 0.0);
clip_context->set_line_width (0.5);
clip_context->translate (0.5, 0.0);
zero_context->set_line_width (0.5);
zero_context->translate (0.5, 0.0);
/* the height of the clip-indicator should be at most 7 pixels, /* the height of the clip-indicator should be at most 7 pixels,
* or 5% of the height of the waveview item. * or 5% of the height of the waveview item.
@ -524,6 +522,9 @@ WaveView::draw_image (Cairo::RefPtr<Cairo::ImageSurface>& image, PeakData* _peak
pixel. This makes the rendering less efficient but it is the only pixel. This makes the rendering less efficient but it is the only
way I can see to do this correctly. way I can see to do this correctly.
To avoid constant source swapping and stroking, we draw the components separately
onto four alpha only image surfaces for use as a mask.
With only 1 pixel of spread between the top and bottom of the line, With only 1 pixel of spread between the top and bottom of the line,
we just draw the upper outline/clip indicator. we just draw the upper outline/clip indicator.
@ -547,103 +548,132 @@ WaveView::draw_image (Cairo::RefPtr<Cairo::ImageSurface>& image, PeakData* _peak
/* waveform line */ /* waveform line */
if (tips[i].spread >= 2.0) { if (tips[i].spread >= 2.0) {
context->move_to (i, tips[i].top); wave_context->move_to (i, tips[i].top);
context->line_to (i, tips[i].bot); wave_context->line_to (i, tips[i].bot);
} }
}
context->stroke ();
/* outline/clip indicators */
set_source_rgba (context, _outline_color);
for (int i = 0; i < n_peaks; ++i) {
context->move_to (i, tips[i].top);
if (_global_show_waveform_clipping && (tips[i].clip_max || tips[i].clip_min)) { if (_global_show_waveform_clipping && (tips[i].clip_max || tips[i].clip_min)) {
clip_context->move_to (i, tips[i].top);
/* clip-indicating upper terminal line */ /* clip-indicating upper terminal line */
set_source_rgba (context, _clip_color); clip_context->rel_line_to (0, min (clip_height, floor (tips[i].spread)));
context->rel_line_to (0, min (clip_height, floor (tips[i].spread)));
context->stroke ();
set_source_rgba (context, _outline_color);
} else { } else {
outline_context->move_to (i, tips[i].top);
/* normal upper terminal dot */ /* normal upper terminal dot */
context->rel_line_to (0, 1.0); outline_context->rel_line_to (0, 1.0);
context->stroke ();
} }
} }
wave_context->stroke ();
clip_context->stroke ();
outline_context->stroke ();
} else { } else {
/* Note the use of cairo save/restore pairs to retain the drawing
context for the waveform lines, which is already set
correctly when we reach here.
*/
for (int i = 0; i < n_peaks; ++i) { for (int i = 0; i < n_peaks; ++i) {
/* waveform line */ /* waveform line */
if (tips[i].spread >= 3.0) { if (tips[i].spread >= 3.0) {
context->move_to (i, tips[i].top); wave_context->move_to (i, tips[i].top);
context->line_to (i, tips[i].bot); wave_context->line_to (i, tips[i].bot);
context->stroke ();
} }
/* zero line */ /* zero line */
if (tips[i].spread >= 5.0 && show_zero_line()) { if (tips[i].spread >= 5.0 && show_zero_line()) {
context->save (); zero_context->move_to (i, _height/2.0);
set_source_rgba (context, _zero_color); zero_context->rel_line_to (0, 0.5);
context->move_to (i, _height/2.0);
context->rel_line_to (0, 0.5);
context->stroke ();
context->restore ();
} }
context->save ();
/* upper outline/clip indicator */ /* upper outline/clip indicator */
context->move_to (i, tips[i].top); if (_global_show_waveform_clipping && tips[i].clip_max) {
if (_global_show_waveform_clipping && ((_shape == WaveView::Rectified && (tips[i].clip_max || tips[i].clip_min)) || tips[i].clip_max)) { clip_context->move_to (i, tips[i].top);
/* clip-indicating upper terminal line */ /* clip-indicating upper terminal line */
set_source_rgba (context, _clip_color); clip_context->rel_line_to (0, min (clip_height, floor (tips[i].spread)));
context->rel_line_to (0, min (clip_height, floor (tips[i].spread)));
context->stroke ();
} else { } else {
outline_context->move_to (i, tips[i].top);
/* normal upper terminal dot */ /* normal upper terminal dot */
set_source_rgba (context, _outline_color); outline_context->rel_line_to (0, 1.0);
context->rel_line_to (0, 1.0);
context->stroke ();
} }
context->restore ();
if (tips[i].spread >= 2.0) { if (tips[i].spread >= 2.0) {
/* lower outline/clip indicator */ /* lower outline/clip indicator */
context->save (); if (_global_show_waveform_clipping && tips[i].clip_min) {
context->move_to (i, tips[i].bot); clip_context->move_to (i, tips[i].bot);
if (_global_show_waveform_clipping && _shape != WaveView::Rectified && tips[i].clip_min) {
/* clip-indicating lower terminal line */ /* clip-indicating lower terminal line */
set_source_rgba (context, _clip_color); clip_context->rel_line_to (0, -(min (clip_height, floor (tips[i].spread))));
context->rel_line_to (0, -(min (clip_height, floor (tips[i].spread))));
context->stroke ();
} else { } else {
outline_context->move_to (i, tips[i].bot);
/* normal lower terminal dot */ /* normal lower terminal dot */
set_source_rgba (context, _outline_color); outline_context->rel_line_to (0, -1.0);
context->rel_line_to (0, -1.0); }
context->stroke (); }
} }
context->restore (); wave_context->stroke ();
outline_context->stroke ();
clip_context->stroke ();
zero_context->stroke ();
} }
Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create (image);
/* Here we set a source colour and use the various components as a mask. */
if (gradient_depth() != 0.0) {
Cairo::RefPtr<Cairo::LinearGradient> gradient (Cairo::LinearGradient::create (0, 0, 0, _height));
double stops[3];
double r, g, b, a;
if (_shape == Rectified) {
stops[0] = 0.1;
stops[1] = 0.3;
stops[2] = 0.9;
} else {
stops[0] = 0.1;
stops[1] = 0.5;
stops[2] = 0.9;
} }
color_to_rgba (_fill_color, r, g, b, a);
gradient->add_color_stop_rgba (stops[1], r, g, b, a);
/* generate a new color for the middle of the gradient */
double h, s, v;
color_to_hsv (_fill_color, h, s, v);
/* change v towards white */
v *= 1.0 - gradient_depth();
Color center = hsv_to_color (h, s, v, a);
color_to_rgba (center, r, g, b, a);
gradient->add_color_stop_rgba (stops[0], r, g, b, a);
gradient->add_color_stop_rgba (stops[2], r, g, b, a);
context->set_source (gradient);
} else {
set_source_rgba (context, _fill_color);
} }
context->mask (images.wave, 0, 0);
context->fill ();
set_source_rgba (context, _outline_color);
context->mask (images.outline, 0, 0);
context->fill ();
set_source_rgba (context, _clip_color);
context->mask (images.clip, 0, 0);
context->fill ();
set_source_rgba (context, _zero_color);
context->mask (images.zero, 0, 0);
context->fill ();
} }
void void
@ -663,8 +693,7 @@ WaveView::get_image (Cairo::RefPtr<Cairo::ImageSurface>& image, framepos_t start
if (_channel != caches[i].channel if (_channel != caches[i].channel
|| _height != caches[i].height || _height != caches[i].height
|| _region_amplitude != caches[i].amplitude || _region_amplitude != caches[i].amplitude
|| _fill_color != caches[i].fill_color || _fill_color != caches[i].fill_color) {
|| _outline_color != caches[i].outline_color) {
continue; continue;
} }
@ -673,7 +702,7 @@ WaveView::get_image (Cairo::RefPtr<Cairo::ImageSurface>& image, framepos_t start
framepos_t segment_end = caches[i].end; framepos_t segment_end = caches[i].end;
if (end <= segment_end && start >= segment_start) { if (end <= segment_end && start >= segment_start) {
image_offset = (segment_start - _region->start()) / _samples_per_pixel; image_offset = (segment_start - _region_start) / _samples_per_pixel;
image = caches[i].image; image = caches[i].image;
return; return;
@ -704,11 +733,11 @@ WaveView::get_image (Cairo::RefPtr<Cairo::ImageSurface>& image, framepos_t start
_channel, _channel,
_samples_per_pixel); _samples_per_pixel);
image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, ((double)(sample_end - sample_start)) / _samples_per_pixel, _height); image = Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, n_peaks, _height);
draw_image (image, peaks.get(), n_peaks); draw_image (image, peaks.get(), n_peaks);
_image_cache[_region->audio_source ()].push_back (CacheEntry (_channel, _height, _region_amplitude, _fill_color, _outline_color, sample_start, sample_end, image)); _image_cache[_region->audio_source ()].push_back (CacheEntry (_channel, _height, _region_amplitude, _fill_color, sample_start, sample_end, image));
image_offset = (sample_start - _region->start()) / _samples_per_pixel; image_offset = (sample_start - _region->start()) / _samples_per_pixel;
@ -784,6 +813,7 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
context->set_source (image, x, y); context->set_source (image, x, y);
context->fill (); context->fill ();
} }
void void