Fix DSP load sorting with inactive plugins
[ardour.git] / gtk2_ardour / audio_streamview.cc
1 /*
2  * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
3  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
4  * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2007 Doug McLain <doug@nostar.net>
6  * Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
7  * Copyright (C) 2015-2016 Nick Mainsbridge <mainsbridge@gmail.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include <cmath>
25 #include <cassert>
26 #include <utility>
27
28 #include <gtkmm.h>
29
30 #include <gtkmm2ext/gtk_ui.h>
31
32 #include "pbd/stacktrace.h"
33
34 #include "ardour/audioregion.h"
35 #include "ardour/audiofilesource.h"
36 #include "ardour/audio_track.h"
37 #include "ardour/record_enable_control.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/profile.h"
40 #include "ardour/rc_configuration.h"
41 #include "ardour/session.h"
42
43 #include "canvas/rectangle.h"
44
45 #include "audio_streamview.h"
46 #include "audio_region_view.h"
47 #include "tape_region_view.h"
48 #include "audio_time_axis.h"
49 #include "region_selection.h"
50 #include "region_gain_line.h"
51 #include "selection.h"
52 #include "public_editor.h"
53 #include "rgb_macros.h"
54 #include "gui_thread.h"
55 #include "ui_config.h"
56
57 #include "pbd/i18n.h"
58
59 using namespace std;
60 using namespace ARDOUR;
61 using namespace PBD;
62 using namespace Editing;
63
64 AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
65         : StreamView (tv)
66 {
67         color_handler ();
68         _amplitude_above_axis = 1.0;
69 }
70
71 int
72 AudioStreamView::set_amplitude_above_axis (gdouble app)
73 {
74         RegionViewList::iterator i;
75
76         if (app < 1.0) {
77                 return -1;
78         }
79
80         _amplitude_above_axis = app;
81
82         for (i = region_views.begin(); i != region_views.end(); ++i) {
83                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
84                 if (arv)
85                         arv->set_amplitude_above_axis (app);
86         }
87
88         return 0;
89 }
90
91 RegionView*
92 AudioStreamView::create_region_view (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
93 {
94         AudioRegionView *region_view = 0;
95         boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
96
97         if (region == 0) {
98                 return 0;
99         }
100
101         switch (_trackview.audio_track()->mode()) {
102
103         case NonLayered:
104         case Normal:
105                 if (recording) {
106                         region_view = new AudioRegionView (_canvas_group, _trackview, region,
107                                                            _samples_per_pixel, region_color, recording, TimeAxisViewItem::Visibility(
108                                                                    TimeAxisViewItem::ShowFrame |
109                                                                    TimeAxisViewItem::HideFrameRight |
110                                                                    TimeAxisViewItem::HideFrameLeft |
111                                                                    TimeAxisViewItem::HideFrameTB));
112                 } else {
113                         region_view = new AudioRegionView (_canvas_group, _trackview, region,
114                                         _samples_per_pixel, region_color);
115                 }
116                 break;
117         case Destructive:
118                 region_view = new TapeAudioRegionView (_canvas_group, _trackview, region,
119                                                        _samples_per_pixel, region_color);
120                 break;
121         default:
122                 fatal << string_compose (_("programming error: %1"), "illegal track mode in ::create_region_view()") << endmsg;
123                 abort(); /*NOTREACHED*/
124
125         }
126
127         region_view->init (wait_for_waves);
128         region_view->set_amplitude_above_axis(_amplitude_above_axis);
129         region_view->set_height (child_height ());
130
131         /* if its the special single-sample length that we use for rec-regions, make it
132            insensitive to events
133         */
134
135         if (region->length() == 1) {
136                 region_view->set_sensitive (false);
137         }
138
139         return region_view;
140 }
141
142 RegionView*
143 AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
144 {
145         RegionView *region_view = create_region_view (r, wait_for_waves, recording);
146
147         if (region_view == 0) {
148                 return 0;
149         }
150
151         region_views.push_front (region_view);
152
153         /* catch region going away */
154
155         r->DropReferences.connect (*this, invalidator (*this), boost::bind (&AudioStreamView::remove_region_view, this, boost::weak_ptr<Region> (r)), gui_context());
156
157         RegionViewAdded (region_view);
158
159         return region_view;
160 }
161
162 void
163 AudioStreamView::redisplay_track ()
164 {
165         list<RegionView *>::iterator i;
166
167         // Flag region views as invalid and disable drawing
168         for (i = region_views.begin(); i != region_views.end(); ++i) {
169                 (*i)->set_valid (false);
170                 (*i)->enable_display (false);
171         }
172
173         // Add and display views, and flag them as valid
174         if (_trackview.is_audio_track()) {
175                 _trackview.track()->playlist()->foreach_region(
176                         sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
177                         );
178         }
179
180         // Stack regions by layer, and remove invalid regions
181         layer_regions();
182 }
183
184 void
185 AudioStreamView::setup_rec_box ()
186 {
187         //cerr << _trackview.name() << " streamview SRB region_views.size() = " << region_views.size() << endl;
188
189         if (!_trackview.session()->transport_stopped()) {
190
191                 // cerr << "\trolling\n";
192
193                 if (!rec_active &&
194                     _trackview.session()->record_status() == Session::Recording &&
195                     _trackview.track()->rec_enable_control()->get_value()) {
196                         if (_trackview.audio_track()->mode() == Normal && UIConfiguration::instance().get_show_waveforms_while_recording() && rec_regions.size() == rec_rects.size()) {
197
198                                 /* add a new region, but don't bother if they set show-waveforms-while-recording mid-record */
199
200                                 SourceList sources;
201
202                                 rec_data_ready_connections.drop_connections ();
203                                 boost::shared_ptr<AudioTrack> tr = _trackview.audio_track();
204
205                                 for (uint32_t n = 0; n < tr->n_channels().n_audio(); ++n) {
206                                         boost::shared_ptr<AudioFileSource> src = tr->write_source (n);
207                                         if (src) {
208                                                 sources.push_back (src);
209                                                 src->PeakRangeReady.connect (rec_data_ready_connections,
210                                                                              invalidator (*this),
211                                                                              boost::bind (&AudioStreamView::rec_peak_range_ready, this, _1, _2, boost::weak_ptr<Source>(src)),
212                                                                              gui_context());
213                                         }
214                                 }
215
216                                 // handle multi
217
218                                 samplepos_t start = 0;
219                                 if (rec_regions.size() > 0) {
220                                         start = rec_regions.back().first->start()
221                                                         + _trackview.track()->get_captured_samples(rec_regions.size()-1);
222                                 }
223
224                                 PropertyList plist;
225
226                                 plist.add (Properties::start, start);
227                                 plist.add (Properties::length, 1);
228                                 plist.add (Properties::name, string());
229                                 plist.add (Properties::layer, 0);
230
231                                 boost::shared_ptr<AudioRegion> region (
232                                         boost::dynamic_pointer_cast<AudioRegion>(RegionFactory::create (sources, plist, false)));
233
234                                 assert(region);
235                                 region->set_position (_trackview.session()->transport_sample());
236                                 rec_regions.push_back (make_pair(region, (RegionView*) 0));
237                         }
238
239                         /* start a new rec box */
240
241                         boost::shared_ptr<AudioTrack> at = _trackview.audio_track();
242                         samplepos_t const sample_pos = at->current_capture_start ();
243                         double     const width     = ((at->mode() == Destructive) ? 2 : 0);
244
245                         create_rec_box(sample_pos, width);
246
247                 } else if (rec_active &&
248                            (_trackview.session()->record_status() != Session::Recording ||
249                             !_trackview.track()->rec_enable_control()->get_value())) {
250                         screen_update_connection.disconnect();
251                         rec_active = false;
252                         rec_updating = false;
253                 }
254
255         } else {
256
257                 // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl;
258
259                 if (!rec_rects.empty() || !rec_regions.empty()) {
260
261                         /* disconnect rapid update */
262                         screen_update_connection.disconnect();
263                         rec_data_ready_connections.drop_connections ();
264                         rec_updating = false;
265                         rec_active = false;
266
267                         /* remove temp regions */
268
269                         for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); ) {
270                                 list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp;
271
272                                 tmp = iter;
273                                 ++tmp;
274
275                                 (*iter).first->drop_references ();
276
277                                 iter = tmp;
278                         }
279
280                         rec_regions.clear();
281
282                         // cerr << "\tclear " << rec_rects.size() << " rec rects\n";
283
284                         /* transport stopped, clear boxes */
285                         for (vector<RecBoxInfo>::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) {
286                                 RecBoxInfo &rect = (*iter);
287                                 delete rect.rectangle;
288                         }
289
290                         rec_rects.clear();
291
292                 }
293         }
294 }
295
296 void
297 AudioStreamView::rec_peak_range_ready (samplepos_t start, samplecnt_t cnt, boost::weak_ptr<Source> weak_src)
298 {
299         ENSURE_GUI_THREAD (*this, &AudioStreamView::rec_peak_range_ready, start, cnt, weak_src)
300
301         boost::shared_ptr<Source> src (weak_src.lock());
302
303         if (!src) {
304                 return;
305         }
306
307         // this is called from the peak building thread
308
309         if (rec_data_ready_map.size() == 0 || start + cnt > last_rec_data_sample) {
310                 last_rec_data_sample = start + cnt;
311         }
312
313         rec_data_ready_map[src] = true;
314
315         if (rec_data_ready_map.size() == _trackview.track()->n_channels().n_audio()) {
316                 update_rec_regions (start, cnt);
317                 rec_data_ready_map.clear();
318         }
319 }
320
321 void
322 AudioStreamView::update_rec_regions (samplepos_t start, samplecnt_t cnt)
323 {
324         if (!UIConfiguration::instance().get_show_waveforms_while_recording ()) {
325                 return;
326         }
327
328         uint32_t n = 0;
329
330         for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) {
331
332                 list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp = iter;
333                 ++tmp;
334
335                 assert (n < rec_rects.size());
336
337                 if (!rec_rects[n].rectangle->visible()) {
338                         /* rect already hidden, this region is done */
339                         iter = tmp;
340                         continue;
341                 }
342
343                 boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(iter->first);
344
345                 if (!region) {
346                         iter = tmp;
347                         continue;
348                 }
349
350                 samplecnt_t origlen = region->length();
351
352                 if (region == rec_regions.back().first && rec_active) {
353
354                         if (last_rec_data_sample > region->start()) {
355
356                                 samplecnt_t nlen = last_rec_data_sample - region->start();
357
358                                 if (nlen != region->length()) {
359
360                                         region->suspend_property_changes ();
361                                         /* set non-musical position / length */
362                                         region->set_position (_trackview.track()->get_capture_start_sample(n));
363                                         region->set_length (nlen, 0);
364                                         region->resume_property_changes ();
365
366                                         if (origlen == 1) {
367                                                 /* our special initial length */
368                                                 add_region_view_internal (region, false, true);
369                                                 setup_new_rec_layer_time (region);
370                                         }
371
372                                         check_record_layers (region, (region->position() - region->start() + start + cnt));
373
374                                         /* also update rect */
375                                         ArdourCanvas::Rectangle * rect = rec_rects[n].rectangle;
376                                         gdouble xend = _trackview.editor().sample_to_pixel (region->position() + region->length());
377                                         rect->set_x1 (xend);
378                                 }
379
380                         } else {
381
382                                 samplecnt_t nlen = _trackview.track()->get_captured_samples(n);
383
384                                 if (nlen != region->length()) {
385
386                                         if (region->source_length(0) >= region->start() + nlen) {
387
388                                                 region->suspend_property_changes ();
389                                                 region->set_position (_trackview.track()->get_capture_start_sample(n));
390                                                 region->set_length (nlen, 0);
391                                                 region->resume_property_changes ();
392
393                                                 if (origlen == 1) {
394                                                         /* our special initial length */
395                                                         add_region_view_internal (region, false, true);
396                                                 }
397
398                                                 /* also hide rect */
399                                                 ArdourCanvas::Item * rect = rec_rects[n].rectangle;
400                                                 rect->hide();
401
402                                         }
403                                 }
404                         }
405                 }
406
407                 iter = tmp;
408         }
409 }
410
411 void
412 AudioStreamView::show_all_fades ()
413 {
414         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
415                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
416                 if (arv) {
417                         arv->set_fade_visibility (true);
418                 }
419         }
420 }
421
422 void
423 AudioStreamView::hide_all_fades ()
424 {
425         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
426                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
427                 if (arv) {
428                         arv->set_fade_visibility (false);
429                 }
430         }
431 }
432
433 /** Hide xfades for regions that overlap ar.
434  *  @return Pair of lists; first is the AudioRegionViews that start xfades were hidden for,
435  *  second is the AudioRegionViews that end xfades were hidden for.
436  */
437 pair<list<AudioRegionView*>, list<AudioRegionView*> >
438 AudioStreamView::hide_xfades_with (boost::shared_ptr<AudioRegion> ar)
439 {
440         list<AudioRegionView*> start_hidden;
441         list<AudioRegionView*> end_hidden;
442
443         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
444                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
445                 if (arv) {
446                         switch (arv->region()->coverage (ar->position(), ar->last_sample())) {
447                         case Evoral::OverlapNone:
448                                 break;
449                         default:
450                                 if (arv->start_xfade_visible ()) {
451                                         start_hidden.push_back (arv);
452                                 }
453                                 if (arv->end_xfade_visible ()) {
454                                         end_hidden.push_back (arv);
455                                 }
456                                 arv->hide_xfades ();
457                                 break;
458                         }
459                 }
460         }
461
462         return make_pair (start_hidden, end_hidden);
463 }
464
465 void
466 AudioStreamView::color_handler ()
467 {
468         //case cAudioTrackBase:
469         if (_trackview.is_track()) {
470                 canvas_rect->set_fill_color (UIConfiguration::instance().color_mod ("audio track base", "audio track base"));
471         }
472
473         //case cAudioBusBase:
474         if (!_trackview.is_track()) {
475                 canvas_rect->set_fill_color (UIConfiguration::instance().color_mod ("audio bus base", "audio bus base"));
476         }
477 }
478
479 void
480 AudioStreamView::set_selected_points (PointSelection& points)
481 {
482         for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
483                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
484                 if (arv && arv->get_gain_line ()) {
485                         arv->get_gain_line ()->set_selected_points (points);
486                 }
487         }
488 }