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 __CANVAS_WAVE_VIEW_H__
23 #define __CANVAS_WAVE_VIEW_H__
25 #include <boost/shared_ptr.hpp>
26 #include <boost/scoped_ptr.hpp>
28 #include "ardour/types.h"
30 #include <glibmm/refptr.h>
32 #include "canvas/visibility.h"
33 #include "canvas/item.h"
45 namespace ArdourCanvas {
47 class WaveViewCacheGroup;
48 class WaveViewDrawRequest;
49 class WaveViewDrawRequestQueue;
51 class WaveViewProperties;
52 class WaveViewDrawingThread;
54 class LIBCANVAS_API WaveView : public Item, public sigc::trackable
57 enum Shape { Normal, Rectified };
59 std::string debug_name () const;
61 /* Displays a single channel of waveform data for the given Region.
63 x = 0 in the waveview corresponds to the first waveform datum taken
64 from region->start() samples into the source data.
66 x = N in the waveview corresponds to the (N * spp)'th sample
67 measured from region->start() into the source data.
69 when drawing, we will map the zeroth-pixel of the waveview
72 The waveview itself contains a set of pre-rendered Cairo::ImageSurfaces
73 that cache sections of the display. This is filled on-demand and
74 never cleared until something explicitly marks the cache invalid
75 (such as a change in samples_per_pixel, the log scaling, rectified or
76 other view parameters).
79 WaveView (Canvas*, boost::shared_ptr<ARDOUR::AudioRegion>);
80 WaveView (Item*, boost::shared_ptr<ARDOUR::AudioRegion>);
83 virtual void prepare_for_render (Rect const& window_area) const;
85 virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const;
87 void compute_bounding_box () const;
89 void set_samples_per_pixel (double);
90 void set_height (Distance);
91 void set_channel (int);
92 void set_region_start (ARDOUR::frameoffset_t);
94 /** Change the first position drawn by @param pixels.
95 * @param pixels must be positive. This is used by
96 * AudioRegionViews in Ardour to avoid drawing the
97 * first pixel of a waveform, and exists in case
98 * there are uses for WaveView where we do not
99 * want this behaviour.
101 void set_start_shift (double pixels);
103 void set_fill_color (Gtkmm2ext::Color);
104 void set_outline_color (Gtkmm2ext::Color);
106 void region_resized ();
107 void gain_changed ();
109 void set_show_zero_line (bool);
110 bool show_zero_line () const;
112 void set_zero_color (Gtkmm2ext::Color);
113 void set_clip_color (Gtkmm2ext::Color);
114 void set_logscaled (bool);
116 void set_gradient_depth (double);
117 double gradient_depth () const;
119 void set_shape (Shape);
121 void set_always_get_image_in_thread (bool yn);
123 /* currently missing because we don't need them (yet):
124 * set_shape_independent();
125 * set_logscaled_independent();
128 static void set_global_gradient_depth (double);
129 static void set_global_logscaled (bool);
130 static void set_global_shape (Shape);
131 static void set_global_show_waveform_clipping (bool);
133 static double global_gradient_depth () { return _global_gradient_depth; }
135 static bool global_logscaled () { return _global_logscaled; }
137 static Shape global_shape () { return _global_shape; }
139 void set_amplitude_above_axis (double v);
141 double amplitude_above_axis () const;
143 static void set_clip_level (double dB);
144 static PBD::Signal0<void> ClipLevelChanged;
146 static void start_drawing_thread ();
147 static void stop_drawing_thread ();
149 static void set_image_cache_size (uint64_t);
151 #ifdef CANVAS_COMPATIBILITY
152 void*& property_gain_src () {
155 void*& property_gain_function () {
164 friend class ::WaveViewTest;
165 friend class WaveViewThreadClient;
166 friend class WaveViewDrawingThread;
168 boost::shared_ptr<ARDOUR::AudioRegion> _region;
170 boost::scoped_ptr<WaveViewProperties> _props;
172 mutable boost::shared_ptr<WaveViewImage> _image;
174 mutable boost::shared_ptr<WaveViewCacheGroup> _cache_group;
176 bool _shape_independent;
177 bool _logscaled_independent;
178 bool _gradient_depth_independent;
180 /** Under almost conditions, this is going to return _region->length(),
181 * but if region_start has been reset, then we need to use this modified
184 ARDOUR::framecnt_t region_length () const;
186 /** Under almost conditions, this is going to return _region->start() +
187 * _region->length(), but if region_start has been reset, then we need to use
188 * this modified computation.
190 ARDOUR::framepos_t region_end () const;
193 * _image stays non-null after the first time it is set
195 bool rendered () const { return _image.get(); }
197 bool draw_image_in_gui_thread () const;
199 /** If true, calls to render() will render a missing wave image in the GUI
200 * thread. Generally set to false, but true after a call to set_height().
202 mutable bool _draw_image_in_gui_thread;
204 /** If true, calls to render() will render a missing wave image in the GUI
205 * thread. Set true for waveviews we expect to keep updating (e.g. while
208 bool _always_draw_image_in_gui_thread;
212 mutable boost::shared_ptr<WaveViewDrawRequest> current_request;
214 PBD::ScopedConnectionList invalidation_connection;
216 static double _global_gradient_depth;
217 static bool _global_logscaled;
218 static Shape _global_shape;
219 static bool _global_show_waveform_clipping;
220 static double _global_clip_level;
222 static PBD::Signal0<void> VisualPropertiesChanged;
224 void handle_visual_property_change ();
225 void handle_clip_level_change ();
234 LineTips () : top (0.0), bot (0.0), clip_max (false), clip_min (false) {}
237 static ArdourCanvas::Coord y_extent (double, Shape const, double const height);
239 static void compute_tips (ARDOUR::PeakData const& peak, LineTips& tips, double const effective_height);
241 static void draw_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int n_peaks,
242 boost::shared_ptr<WaveViewDrawRequest>);
243 static void draw_absent_image (Cairo::RefPtr<Cairo::ImageSurface>&, ARDOUR::PeakData*, int);
245 ARDOUR::framecnt_t optimal_image_width_samples () const;
247 void set_image (boost::shared_ptr<WaveViewImage> img) const;
249 // @return true if item area intersects with draw area
250 bool get_item_and_draw_rect_in_window_coords (Rect const& canvas_rect, Rect& item_area,
251 Rect& draw_rect) const;
253 boost::shared_ptr<WaveViewDrawRequest> create_draw_request (WaveViewProperties const&) const;
255 void queue_draw_request (boost::shared_ptr<WaveViewDrawRequest> const&) const;
257 static void process_draw_request (boost::shared_ptr<WaveViewDrawRequest>);
259 boost::shared_ptr<WaveViewCacheGroup> get_cache_group () const;
262 * Notify the Cache that we are dropping our reference to the
263 * CacheGroup so it can also do so if it is the only reference holder
264 * of the cache group.
266 void reset_cache_group ();
269 } // namespace ArdourCanvas
271 #endif // __CANVAS_WAVE_VIEW_H__