Purify libcanvas, remove libardour dependency
[ardour.git] / libs / waveview / waveview / 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 _WAVEVIEW_WAVE_VIEW_H_
23 #define _WAVEVIEW_WAVE_VIEW_H_
24
25 #include <boost/shared_ptr.hpp>
26 #include <boost/scoped_ptr.hpp>
27
28 #include <glibmm/refptr.h>
29
30 #include "ardour/types.h"
31 #include "canvas/item.h"
32 #include "waveview/visibility.h"
33
34 namespace ARDOUR {
35         class AudioRegion;
36 }
37
38 namespace Gdk {
39         class Pixbuf;
40 }
41
42 namespace ArdourWaveView {
43
44 class WaveViewCacheGroup;
45 class WaveViewDrawRequest;
46 class WaveViewDrawRequestQueue;
47 class WaveViewImage;
48 class WaveViewProperties;
49 class WaveViewDrawingThread;
50
51 class LIBWAVEVIEW_API WaveView : public ArdourCanvas::Item, public sigc::trackable
52 {
53 public:
54         enum Shape { Normal, Rectified };
55
56         std::string debug_name () const;
57
58         /* Displays a single channel of waveform data for the given Region.
59
60            x = 0 in the waveview corresponds to the first waveform datum taken
61            from region->start() samples into the source data.
62
63            x = N in the waveview corresponds to the (N * spp)'th sample
64            measured from region->start() into the source data.
65
66            when drawing, we will map the zeroth-pixel of the waveview
67            into a window.
68
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).
74         */
75
76         WaveView (ArdourCanvas::Canvas*, boost::shared_ptr<ARDOUR::AudioRegion>);
77         WaveView (Item*, boost::shared_ptr<ARDOUR::AudioRegion>);
78         ~WaveView ();
79
80         virtual void prepare_for_render (ArdourCanvas::Rect const& window_area) const;
81
82         virtual void render (ArdourCanvas::Rect const & area, Cairo::RefPtr<Cairo::Context>) const;
83
84         void compute_bounding_box () const;
85
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);
90
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.
97          */
98         void set_start_shift (double pixels);
99
100         void set_fill_color (Gtkmm2ext::Color);
101         void set_outline_color (Gtkmm2ext::Color);
102
103         void region_resized ();
104         void gain_changed ();
105
106         void set_show_zero_line (bool);
107         bool show_zero_line () const;
108
109         void set_zero_color (Gtkmm2ext::Color);
110         void set_clip_color (Gtkmm2ext::Color);
111         void set_logscaled (bool);
112
113         void set_gradient_depth (double);
114         double gradient_depth () const;
115
116         void set_shape (Shape);
117
118         void set_always_get_image_in_thread (bool yn);
119
120         /* currently missing because we don't need them (yet):
121          * set_shape_independent();
122          * set_logscaled_independent();
123          */
124
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);
129
130         static double global_gradient_depth () { return _global_gradient_depth; }
131
132         static bool global_logscaled () { return _global_logscaled; }
133
134         static Shape global_shape () { return _global_shape; }
135
136         void set_amplitude_above_axis (double v);
137
138         double amplitude_above_axis () const;
139
140         static void set_clip_level (double dB);
141         static PBD::Signal0<void> ClipLevelChanged;
142
143         static void start_drawing_thread ();
144         static void stop_drawing_thread ();
145
146         static void set_image_cache_size (uint64_t);
147
148 #ifdef CANVAS_COMPATIBILITY
149         void*& property_gain_src () {
150                 return _foo_void;
151         }
152         void*& property_gain_function () {
153                 return _foo_void;
154         }
155
156 private:
157         void* _foo_void;
158 #endif
159
160 private:
161         friend class WaveViewThreadClient;
162         friend class WaveViewDrawingThread;
163
164         boost::shared_ptr<ARDOUR::AudioRegion> _region;
165
166         boost::scoped_ptr<WaveViewProperties> _props;
167
168         mutable boost::shared_ptr<WaveViewImage> _image;
169
170         mutable boost::shared_ptr<WaveViewCacheGroup> _cache_group;
171
172         bool _shape_independent;
173         bool _logscaled_independent;
174         bool _gradient_depth_independent;
175
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
178          * computation.
179          */
180         ARDOUR::framecnt_t region_length () const;
181
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.
185          */
186         ARDOUR::framepos_t region_end () const;
187
188         /**
189          * _image stays non-null after the first time it is set
190          */
191         bool rendered () const { return _image.get(); }
192
193         bool draw_image_in_gui_thread () const;
194
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().
197          */
198         mutable bool _draw_image_in_gui_thread;
199
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
202          * recording)
203          */
204         bool _always_draw_image_in_gui_thread;
205
206         void init();
207
208         mutable boost::shared_ptr<WaveViewDrawRequest> current_request;
209
210         PBD::ScopedConnectionList invalidation_connection;
211
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;
217
218         static PBD::Signal0<void> VisualPropertiesChanged;
219
220         void handle_visual_property_change ();
221         void handle_clip_level_change ();
222
223         struct LineTips {
224                 double top;
225                 double bot;
226                 double spread;
227                 bool clip_max;
228                 bool clip_min;
229
230                 LineTips () : top (0.0), bot (0.0), clip_max (false), clip_min (false) {}
231         };
232
233         static ArdourCanvas::Coord y_extent (double, Shape const, double const height);
234
235         static void compute_tips (ARDOUR::PeakData const& peak, LineTips& tips, double const effective_height);
236
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);
240
241         ARDOUR::framecnt_t optimal_image_width_samples () const;
242
243         void set_image (boost::shared_ptr<WaveViewImage> img) const;
244
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;
249
250         boost::shared_ptr<WaveViewDrawRequest> create_draw_request (WaveViewProperties const&) const;
251
252         void queue_draw_request (boost::shared_ptr<WaveViewDrawRequest> const&) const;
253
254         static void process_draw_request (boost::shared_ptr<WaveViewDrawRequest>);
255
256         boost::shared_ptr<WaveViewCacheGroup> get_cache_group () const;
257
258         /**
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.
262          */
263         void reset_cache_group ();
264 };
265
266 } /* namespace */
267
268 #endif