2 Copyright (C) 2011-2013 Paul Davis
3 Copyright (C) 2017 Tim Mayberry
4 Author: Carl Hetherington <cth@carlh.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #ifndef _WAVEVIEW_WAVE_VIEW_H_
23 #define _WAVEVIEW_WAVE_VIEW_H_
25 #include <boost/shared_ptr.hpp>
26 #include <boost/scoped_ptr.hpp>
28 #include <glibmm/refptr.h>
30 #include "ardour/types.h"
31 #include "canvas/item.h"
32 #include "waveview/visibility.h"
42 namespace ArdourWaveView {
44 class WaveViewCacheGroup;
45 class WaveViewDrawRequest;
46 class WaveViewDrawRequestQueue;
48 class WaveViewProperties;
49 class WaveViewDrawingThread;
51 class LIBWAVEVIEW_API WaveView : public ArdourCanvas::Item, public sigc::trackable
54 enum Shape { Normal, Rectified };
56 std::string debug_name () const;
58 /* Displays a single channel of waveform data for the given Region.
60 x = 0 in the waveview corresponds to the first waveform datum taken
61 from region->start() samples into the source data.
63 x = N in the waveview corresponds to the (N * spp)'th sample
64 measured from region->start() into the source data.
66 when drawing, we will map the zeroth-pixel of the waveview
69 The waveview itself contains a set of pre-rendered Cairo::ImageSurfaces
70 that cache sections of the display. This is filled on-demand and
71 never cleared until something explicitly marks the cache invalid
72 (such as a change in samples_per_pixel, the log scaling, rectified or
73 other view parameters).
76 WaveView (ArdourCanvas::Canvas*, boost::shared_ptr<ARDOUR::AudioRegion>);
77 WaveView (Item*, boost::shared_ptr<ARDOUR::AudioRegion>);
80 virtual void prepare_for_render (ArdourCanvas::Rect const& window_area) const;
82 virtual void render (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context>) const;
84 void compute_bounding_box () const;
86 void set_samples_per_pixel (double);
87 void set_height (ArdourCanvas::Distance);
88 void set_channel (int);
89 void set_region_start (ARDOUR::frameoffset_t);
91 /** Change the first position drawn by @param pixels.
92 * @param pixels must be positive. This is used by
93 * AudioRegionViews in Ardour to avoid drawing the
94 * first pixel of a waveform, and exists in case
95 * there are uses for WaveView where we do not
96 * want this behaviour.
98 void set_start_shift (double pixels);
100 void set_fill_color (Gtkmm2ext::Color);
101 void set_outline_color (Gtkmm2ext::Color);
103 void region_resized ();
104 void gain_changed ();
106 void set_show_zero_line (bool);
107 bool show_zero_line () const;
109 void set_zero_color (Gtkmm2ext::Color);
110 void set_clip_color (Gtkmm2ext::Color);
111 void set_logscaled (bool);
113 void set_gradient_depth (double);
114 double gradient_depth () const;
116 void set_shape (Shape);
118 void set_always_get_image_in_thread (bool yn);
120 /* currently missing because we don't need them (yet):
121 * set_shape_independent();
122 * set_logscaled_independent();
125 static void set_global_gradient_depth (double);
126 static void set_global_logscaled (bool);
127 static void set_global_shape (Shape);
128 static void set_global_show_waveform_clipping (bool);
130 static double global_gradient_depth () { return _global_gradient_depth; }
132 static bool global_logscaled () { return _global_logscaled; }
134 static Shape global_shape () { return _global_shape; }
136 void set_amplitude_above_axis (double v);
138 double amplitude_above_axis () const;
140 static void set_clip_level (double dB);
141 static PBD::Signal0<void> ClipLevelChanged;
143 static void start_drawing_thread ();
144 static void stop_drawing_thread ();
146 static void set_image_cache_size (uint64_t);
148 #ifdef CANVAS_COMPATIBILITY
149 void*& property_gain_src () {
152 void*& property_gain_function () {
161 friend class WaveViewThreadClient;
162 friend class WaveViewDrawingThread;
164 boost::shared_ptr<ARDOUR::AudioRegion> _region;
166 boost::scoped_ptr<WaveViewProperties> _props;
168 mutable boost::shared_ptr<WaveViewImage> _image;
170 mutable boost::shared_ptr<WaveViewCacheGroup> _cache_group;
172 bool _shape_independent;
173 bool _logscaled_independent;
174 bool _gradient_depth_independent;
176 /** Under almost conditions, this is going to return _region->length(),
177 * but if region_start has been reset, then we need to use this modified
180 ARDOUR::framecnt_t region_length () const;
182 /** Under almost conditions, this is going to return _region->start() +
183 * _region->length(), but if region_start has been reset, then we need to use
184 * this modified computation.
186 ARDOUR::framepos_t region_end () const;
189 * _image stays non-null after the first time it is set
191 bool rendered () const { return _image.get(); }
193 bool draw_image_in_gui_thread () const;
195 /** If true, calls to render() will render a missing wave image in the GUI
196 * thread. Generally set to false, but true after a call to set_height().
198 mutable bool _draw_image_in_gui_thread;
200 /** If true, calls to render() will render a missing wave image in the GUI
201 * thread. Set true for waveviews we expect to keep updating (e.g. while
204 bool _always_draw_image_in_gui_thread;
208 mutable boost::shared_ptr<WaveViewDrawRequest> current_request;
210 PBD::ScopedConnectionList invalidation_connection;
212 static double _global_gradient_depth;
213 static bool _global_logscaled;
214 static Shape _global_shape;
215 static bool _global_show_waveform_clipping;
216 static double _global_clip_level;
218 static PBD::Signal0<void> VisualPropertiesChanged;
220 void handle_visual_property_change ();
221 void handle_clip_level_change ();
230 LineTips () : top (0.0), bot (0.0), clip_max (false), clip_min (false) {}
233 static ArdourCanvas::Coord y_extent (double, Shape const, double const height);
235 static void compute_tips (ARDOUR::PeakData const& peak, LineTips& tips, double const effective_height);
237 static void draw_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int n_peaks,
238 boost::shared_ptr<WaveViewDrawRequest>);
239 static void draw_absent_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int);
241 ARDOUR::framecnt_t optimal_image_width_samples () const;
243 void set_image (boost::shared_ptr<WaveViewImage> img) const;
245 // @return true if item area intersects with draw area
246 bool get_item_and_draw_rect_in_window_coords (ArdourCanvas::Rect const& canvas_rect,
247 ArdourCanvas::Rect& item_area,
248 ArdourCanvas::Rect& draw_rect) const;
250 boost::shared_ptr<WaveViewDrawRequest> create_draw_request (WaveViewProperties const&) const;
252 void queue_draw_request (boost::shared_ptr<WaveViewDrawRequest> const&) const;
254 static void process_draw_request (boost::shared_ptr<WaveViewDrawRequest>);
256 boost::shared_ptr<WaveViewCacheGroup> get_cache_group () const;
259 * Notify the Cache that we are dropping our reference to the
260 * CacheGroup so it can also do so if it is the only reference holder
261 * of the cache group.
263 void reset_cache_group ();