Clean up library inheritance (colors.h, utils.h)
[ardour.git] / libs / canvas / canvas / wave_view.h
1 /*
2     Copyright (C) 2011-2013 Paul Davis
3     Copyright (C) 2017 Tim Mayberry
4     Author: Carl Hetherington <cth@carlh.net>
5
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.
10
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.
15
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.
19
20 */
21
22 #ifndef __CANVAS_WAVE_VIEW_H__
23 #define __CANVAS_WAVE_VIEW_H__
24
25 #include <boost/shared_ptr.hpp>
26 #include <boost/scoped_ptr.hpp>
27
28 #include "ardour/types.h"
29
30 #include <glibmm/refptr.h>
31
32 #include "canvas/visibility.h"
33 #include "canvas/item.h"
34
35 namespace ARDOUR {
36         class AudioRegion;
37 }
38
39 namespace Gdk {
40         class Pixbuf;
41 }
42
43 class WaveViewTest;
44
45 namespace ArdourCanvas {
46
47 class WaveViewCacheGroup;
48 class WaveViewDrawRequest;
49 class WaveViewDrawRequestQueue;
50 class WaveViewImage;
51 class WaveViewProperties;
52 class WaveViewDrawingThread;
53
54 class LIBCANVAS_API WaveView : public Item, public sigc::trackable
55 {
56 public:
57         enum Shape { Normal, Rectified };
58
59         std::string debug_name () const;
60
61         /* Displays a single channel of waveform data for the given Region.
62
63            x = 0 in the waveview corresponds to the first waveform datum taken
64            from region->start() samples into the source data.
65
66            x = N in the waveview corresponds to the (N * spp)'th sample
67            measured from region->start() into the source data.
68
69            when drawing, we will map the zeroth-pixel of the waveview
70            into a window.
71
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).
77         */
78
79         WaveView (Canvas*, boost::shared_ptr<ARDOUR::AudioRegion>);
80         WaveView (Item*, boost::shared_ptr<ARDOUR::AudioRegion>);
81         ~WaveView ();
82
83         virtual void prepare_for_render (Rect const& window_area) const;
84
85         virtual void render (Rect const & area, Cairo::RefPtr<Cairo::Context>) const;
86
87         void compute_bounding_box () const;
88
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);
93
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.
100          */
101         void set_start_shift (double pixels);
102
103         void set_fill_color (Gtkmm2ext::Color);
104         void set_outline_color (Gtkmm2ext::Color);
105
106         void region_resized ();
107         void gain_changed ();
108
109         void set_show_zero_line (bool);
110         bool show_zero_line () const;
111
112         void set_zero_color (Gtkmm2ext::Color);
113         void set_clip_color (Gtkmm2ext::Color);
114         void set_logscaled (bool);
115
116         void set_gradient_depth (double);
117         double gradient_depth () const;
118
119         void set_shape (Shape);
120
121         void set_always_get_image_in_thread (bool yn);
122
123         /* currently missing because we don't need them (yet):
124          * set_shape_independent();
125          * set_logscaled_independent();
126          */
127
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);
132
133         static double global_gradient_depth () { return _global_gradient_depth; }
134
135         static bool global_logscaled () { return _global_logscaled; }
136
137         static Shape global_shape () { return _global_shape; }
138
139         void set_amplitude_above_axis (double v);
140
141         double amplitude_above_axis () const;
142
143         static void set_clip_level (double dB);
144         static PBD::Signal0<void> ClipLevelChanged;
145
146         static void start_drawing_thread ();
147         static void stop_drawing_thread ();
148
149         static void set_image_cache_size (uint64_t);
150
151 #ifdef CANVAS_COMPATIBILITY
152         void*& property_gain_src () {
153                 return _foo_void;
154         }
155         void*& property_gain_function () {
156                 return _foo_void;
157         }
158
159 private:
160         void* _foo_void;
161 #endif
162
163 private:
164         friend class ::WaveViewTest;
165         friend class WaveViewThreadClient;
166         friend class WaveViewDrawingThread;
167
168         boost::shared_ptr<ARDOUR::AudioRegion> _region;
169
170         boost::scoped_ptr<WaveViewProperties> _props;
171
172         mutable boost::shared_ptr<WaveViewImage> _image;
173
174         mutable boost::shared_ptr<WaveViewCacheGroup> _cache_group;
175
176         bool _shape_independent;
177         bool _logscaled_independent;
178         bool _gradient_depth_independent;
179
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
182          * computation.
183          */
184         ARDOUR::framecnt_t region_length () const;
185
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.
189          */
190         ARDOUR::framepos_t region_end () const;
191
192         /**
193          * _image stays non-null after the first time it is set
194          */
195         bool rendered () const { return _image.get(); }
196
197         bool draw_image_in_gui_thread () const;
198
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().
201          */
202         mutable bool _draw_image_in_gui_thread;
203
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
206          * recording)
207          */
208         bool _always_draw_image_in_gui_thread;
209
210         void init();
211
212         mutable boost::shared_ptr<WaveViewDrawRequest> current_request;
213
214         PBD::ScopedConnectionList invalidation_connection;
215
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;
221
222         static PBD::Signal0<void> VisualPropertiesChanged;
223
224         void handle_visual_property_change ();
225         void handle_clip_level_change ();
226
227         struct LineTips {
228                 double top;
229                 double bot;
230                 double spread;
231                 bool clip_max;
232                 bool clip_min;
233
234                 LineTips () : top (0.0), bot (0.0), clip_max (false), clip_min (false) {}
235         };
236
237         static ArdourCanvas::Coord y_extent (double, Shape const, double const height);
238
239         static void compute_tips (ARDOUR::PeakData const& peak, LineTips& tips, double const effective_height);
240
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);
244
245         ARDOUR::framecnt_t optimal_image_width_samples () const;
246
247         void set_image (boost::shared_ptr<WaveViewImage> img) const;
248
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;
252
253         boost::shared_ptr<WaveViewDrawRequest> create_draw_request (WaveViewProperties const&) const;
254
255         void queue_draw_request (boost::shared_ptr<WaveViewDrawRequest> const&) const;
256
257         static void process_draw_request (boost::shared_ptr<WaveViewDrawRequest>);
258
259         boost::shared_ptr<WaveViewCacheGroup> get_cache_group () const;
260
261         /**
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.
265          */
266         void reset_cache_group ();
267 };
268
269 } // namespace ArdourCanvas
270
271 #endif // __CANVAS_WAVE_VIEW_H__