remove AU GUI debugging test in which arrow keys could be used to change GUI size
[ardour.git] / gtk2_ardour / audio_streamview.cc
1 /*
2     Copyright (C) 2001, 2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cmath>
20 #include <cassert>
21 #include <utility>
22
23 #include <gtkmm.h>
24
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include "pbd/stacktrace.h"
28
29 #include "ardour/audioregion.h"
30 #include "ardour/audiofilesource.h"
31 #include "ardour/audio_track.h"
32 #include "ardour/region_factory.h"
33 #include "ardour/profile.h"
34 #include "ardour/rc_configuration.h"
35 #include "ardour/session.h"
36
37 #include "audio_streamview.h"
38 #include "audio_region_view.h"
39 #include "tape_region_view.h"
40 #include "audio_time_axis.h"
41 #include "canvas-waveview.h"
42 #include "canvas-simplerect.h"
43 #include "region_selection.h"
44 #include "selection.h"
45 #include "public_editor.h"
46 #include "ardour_ui.h"
47 #include "rgb_macros.h"
48 #include "gui_thread.h"
49 #include "utils.h"
50
51 #include "i18n.h"
52
53 using namespace std;
54 using namespace ARDOUR;
55 using namespace PBD;
56 using namespace Editing;
57
58 AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
59         : StreamView (tv)
60 {
61         color_handler ();
62         _amplitude_above_axis = 1.0;
63
64         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&AudioStreamView::parameter_changed, this, _1), gui_context());
65 }
66
67 int
68 AudioStreamView::set_amplitude_above_axis (gdouble app)
69 {
70         RegionViewList::iterator i;
71
72         if (app < 1.0) {
73                 return -1;
74         }
75
76         _amplitude_above_axis = app;
77
78         for (i = region_views.begin(); i != region_views.end(); ++i) {
79                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
80                 if (arv)
81                         arv->set_amplitude_above_axis (app);
82         }
83
84         return 0;
85 }
86
87 RegionView*
88 AudioStreamView::create_region_view (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
89 {
90         AudioRegionView *region_view = 0;
91         boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
92
93         if (region == 0) {
94                 return 0;
95         }
96
97         switch (_trackview.audio_track()->mode()) {
98
99         case NonLayered:
100         case Normal:
101                 if (recording) {
102                         region_view = new AudioRegionView (_canvas_group, _trackview, region,
103                                         _samples_per_unit, region_color, recording, TimeAxisViewItem::Visibility(
104                                                         TimeAxisViewItem::ShowFrame |
105                                                         TimeAxisViewItem::HideFrameRight |
106                                                         TimeAxisViewItem::HideFrameLeft |
107                                                         TimeAxisViewItem::HideFrameTB));
108                 } else {
109                         region_view = new AudioRegionView (_canvas_group, _trackview, region,
110                                         _samples_per_unit, region_color);
111                 }
112                 break;
113         case Destructive:
114                 region_view = new TapeAudioRegionView (_canvas_group, _trackview, region,
115                                 _samples_per_unit, region_color);
116                 break;
117         default:
118                 fatal << string_compose (_("programming error: %1"), "illegal track mode in ::add_region_view_internal") << endmsg;
119                 /*NOTREACHED*/
120
121         }
122
123         region_view->init (region_color, wait_for_waves);
124         region_view->set_amplitude_above_axis(_amplitude_above_axis);
125         region_view->set_height (child_height ());
126
127         /* if its the special single-sample length that we use for rec-regions, make it
128            insensitive to events
129         */
130
131         if (region->length() == 1) {
132                 region_view->set_sensitive (false);
133         }
134
135         region_view->set_waveform_scale (Config->get_waveform_scale ());
136         region_view->set_waveform_shape (Config->get_waveform_shape ());
137         region_view->set_waveform_visible (Config->get_show_waveforms ());
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 //      if(!recording){
152 //              for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
153 //                      if ((*i)->region() == r) {
154 //                              cerr << "audio_streamview in add_region_view_internal region found" << endl;
155                                 /* great. we already have a AudioRegionView for this Region. use it again. */
156
157 //                              (*i)->set_valid (true);
158
159                                 // this might not be necessary
160 //                              AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
161
162 //                              if (arv) {
163 //                                      arv->set_waveform_scale (_waveform_scale);
164 //                                      arv->set_waveform_shape (_waveform_shape);
165 //                              }
166
167 //                              return NULL;
168 //                      }
169 //              }
170 //      }
171
172         region_views.push_front (region_view);
173
174         if (_trackview.editor().internal_editing()) {
175                 region_view->hide_rect ();
176         } else {
177                 region_view->show_rect ();
178         }
179
180         /* catch region going away */
181
182         r->DropReferences.connect (*this, invalidator (*this), boost::bind (&AudioStreamView::remove_region_view, this, boost::weak_ptr<Region> (r)), gui_context());
183
184         RegionViewAdded (region_view);
185
186         return region_view;
187 }
188
189 void
190 AudioStreamView::redisplay_track ()
191 {
192         list<RegionView *>::iterator i;
193
194         // Flag region views as invalid and disable drawing
195         for (i = region_views.begin(); i != region_views.end(); ++i) {
196                 (*i)->set_valid (false);
197                 (*i)->enable_display (false);
198         }
199
200         // Add and display views, and flag them as valid
201         if (_trackview.is_audio_track()) {
202                 _trackview.track()->playlist()->foreach_region(
203                         sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
204                         );
205         }
206
207         // Stack regions by layer, and remove invalid regions
208         layer_regions();
209 }
210
211 void
212 AudioStreamView::set_show_waveforms (bool yn)
213 {
214         for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
215                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
216                 if (arv) {
217                         arv->set_waveform_visible (yn);
218                 }
219         }
220 }
221
222 void
223 AudioStreamView::set_waveform_shape (WaveformShape shape)
224 {
225         for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
226                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
227                 if (arv)
228                         arv->set_waveform_shape (shape);
229         }
230 }
231
232 void
233 AudioStreamView::set_waveform_scale (WaveformScale scale)
234 {
235         for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
236                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
237                 if (arv) {
238                         arv->set_waveform_scale (scale);
239                 }
240         }
241 }
242
243 void
244 AudioStreamView::setup_rec_box ()
245 {
246         //cerr << _trackview.name() << " streamview SRB region_views.size() = " << region_views.size() << endl;
247
248         if (_trackview.session()->transport_rolling()) {
249
250                 // cerr << "\trolling\n";
251
252                 if (!rec_active &&
253                     _trackview.session()->record_status() == Session::Recording &&
254                     _trackview.track()->record_enabled()) {
255                         if (_trackview.audio_track()->mode() == Normal && Config->get_show_waveforms_while_recording() && rec_regions.size() == rec_rects.size()) {
256
257                                 /* add a new region, but don't bother if they set show-waveforms-while-recording mid-record */
258
259                                 SourceList sources;
260
261                                 rec_data_ready_connections.drop_connections ();
262                                 boost::shared_ptr<AudioTrack> tr = _trackview.audio_track();
263
264                                 for (uint32_t n = 0; n < tr->n_channels().n_audio(); ++n) {
265                                         boost::shared_ptr<AudioFileSource> src = tr->write_source (n);
266                                         if (src) {
267                                                 sources.push_back (src);
268                                                 src->PeakRangeReady.connect (rec_data_ready_connections,
269                                                                              invalidator (*this),
270                                                                              boost::bind (&AudioStreamView::rec_peak_range_ready, this, _1, _2, boost::weak_ptr<Source>(src)),
271                                                                              gui_context());
272                                         }
273                                 }
274
275                                 // handle multi
276
277                                 framepos_t start = 0;
278                                 if (rec_regions.size() > 0) {
279                                         start = rec_regions.back().first->start()
280                                                         + _trackview.track()->get_captured_frames(rec_regions.size()-1);
281                                 }
282
283                                 PropertyList plist;
284
285                                 plist.add (Properties::start, start);
286                                 plist.add (Properties::length, 1);
287                                 plist.add (Properties::name, string());
288                                 plist.add (Properties::layer, 0);
289
290                                 boost::shared_ptr<AudioRegion> region (
291                                         boost::dynamic_pointer_cast<AudioRegion>(RegionFactory::create (sources, plist, false)));
292
293                                 assert(region);
294                                 region->set_position (_trackview.session()->transport_frame());
295                                 rec_regions.push_back (make_pair(region, (RegionView*) 0));
296                         }
297
298                         /* start a new rec box */
299
300                         boost::shared_ptr<AudioTrack> at;
301
302                         at = _trackview.audio_track(); /* we know what it is already */
303                         framepos_t const frame_pos = at->current_capture_start ();
304                         gdouble xstart = _trackview.editor().frame_to_pixel (frame_pos);
305                         gdouble xend;
306                         uint32_t fill_color;
307
308                         switch (_trackview.audio_track()->mode()) {
309                         case Normal:
310                         case NonLayered:
311                                 xend = xstart;
312                                 fill_color = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
313                                 break;
314
315                         case Destructive:
316                                 xend = xstart + 2;
317                                 fill_color = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
318                                 /* make the recording rect translucent to allow
319                                    the user to see the peak data coming in, etc.
320                                 */
321                                 fill_color = UINT_RGBA_CHANGE_A (fill_color, 120);
322                                 break;
323                         }
324
325                         ArdourCanvas::SimpleRect * rec_rect = new Gnome::Canvas::SimpleRect (*_canvas_group);
326                         rec_rect->property_x1() = xstart;
327                         rec_rect->property_y1() = 1.0;
328                         rec_rect->property_x2() = xend;
329                         rec_rect->property_y2() = child_height ();
330                         rec_rect->property_outline_what() = 0x0;
331                         rec_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeAxisFrame.get();
332                         rec_rect->property_fill_color_rgba() = fill_color;
333                         rec_rect->lower_to_bottom();
334
335                         RecBoxInfo recbox;
336                         recbox.rectangle = rec_rect;
337                         recbox.start = _trackview.session()->transport_frame();
338                         recbox.length = 0;
339
340                         rec_rects.push_back (recbox);
341
342                         screen_update_connection.disconnect();
343                         screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
344                                         sigc::mem_fun (*this, &AudioStreamView::update_rec_box));
345                         rec_updating = true;
346                         rec_active = true;
347
348                 } else if (rec_active &&
349                            (_trackview.session()->record_status() != Session::Recording ||
350                             !_trackview.track()->record_enabled())) {
351                         screen_update_connection.disconnect();
352                         rec_active = false;
353                         rec_updating = false;
354                 }
355
356         } else {
357
358                 // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl;
359
360                 if (!rec_rects.empty() || !rec_regions.empty()) {
361
362                         /* disconnect rapid update */
363                         screen_update_connection.disconnect();
364                         rec_data_ready_connections.drop_connections ();
365                         rec_updating = false;
366                         rec_active = false;
367
368                         /* remove temp regions */
369
370                         for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); ) {
371                                 list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp;
372
373                                 tmp = iter;
374                                 ++tmp;
375
376                                 (*iter).first->drop_references ();
377
378                                 iter = tmp;
379                         }
380
381                         rec_regions.clear();
382
383                         // cerr << "\tclear " << rec_rects.size() << " rec rects\n";
384
385                         /* transport stopped, clear boxes */
386                         for (vector<RecBoxInfo>::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) {
387                                 RecBoxInfo &rect = (*iter);
388                                 delete rect.rectangle;
389                         }
390
391                         rec_rects.clear();
392
393                 }
394         }
395 }
396
397 void
398 AudioStreamView::rec_peak_range_ready (framepos_t start, framecnt_t cnt, boost::weak_ptr<Source> weak_src)
399 {
400         ENSURE_GUI_THREAD (*this, &AudioStreamView::rec_peak_range_ready, start, cnt, weak_src)
401
402         boost::shared_ptr<Source> src (weak_src.lock());
403
404         if (!src) {
405                 return;
406         }
407
408         // this is called from the peak building thread
409
410         if (rec_data_ready_map.size() == 0 || start + cnt > last_rec_data_frame) {
411                 last_rec_data_frame = start + cnt;
412         }
413
414         rec_data_ready_map[src] = true;
415
416         if (rec_data_ready_map.size() == _trackview.track()->n_channels().n_audio()) {
417                 update_rec_regions (start, cnt);
418                 rec_data_ready_map.clear();
419         }
420 }
421
422 void
423 AudioStreamView::update_rec_regions (framepos_t start, framecnt_t cnt)
424 {
425         if (!Config->get_show_waveforms_while_recording ()) {
426                 return;
427         }
428
429         uint32_t n = 0;
430
431         for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) {
432
433                 list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp = iter;
434                 ++tmp;
435
436                 assert (n < rec_rects.size());
437
438                 if (!canvas_item_visible (rec_rects[n].rectangle)) {
439                         /* rect already hidden, this region is done */
440                         iter = tmp;
441                         continue;
442                 }
443
444                 boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(iter->first);
445
446                 if (!region) {
447                         iter = tmp;
448                         continue;
449                 }
450
451                 framecnt_t origlen = region->length();
452
453                 if (region == rec_regions.back().first && rec_active) {
454
455                         if (last_rec_data_frame > region->start()) {
456
457                                 framecnt_t nlen = last_rec_data_frame - region->start();
458
459                                 if (nlen != region->length()) {
460
461                                         region->suspend_property_changes ();
462                                         region->set_position (_trackview.track()->get_capture_start_frame(n));
463                                         region->set_length (nlen);
464                                         region->resume_property_changes ();
465
466                                         if (origlen == 1) {
467                                                 /* our special initial length */
468                                                 add_region_view_internal (region, false, true);
469                                                 setup_new_rec_layer_time (region);
470                                         }
471
472                                         check_record_layers (region, (region->position() - region->start() + start + cnt));
473
474                                         /* also update rect */
475                                         ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle;
476                                         gdouble xend = _trackview.editor().frame_to_pixel (region->position() + region->length());
477                                         rect->property_x2() = xend;
478                                 }
479
480                         } else {
481
482                                 framecnt_t nlen = _trackview.track()->get_captured_frames(n);
483
484                                 if (nlen != region->length()) {
485
486                                         if (region->source_length(0) >= region->start() + nlen) {
487
488                                                 region->suspend_property_changes ();
489                                                 region->set_position (_trackview.track()->get_capture_start_frame(n));
490                                                 region->set_length (nlen);
491                                                 region->resume_property_changes ();
492
493                                                 if (origlen == 1) {
494                                                         /* our special initial length */
495                                                         add_region_view_internal (region, false, true);
496                                                 }
497
498                                                 /* also hide rect */
499                                                 ArdourCanvas::Item * rect = rec_rects[n].rectangle;
500                                                 rect->hide();
501
502                                         }
503                                 }
504                         }
505                 }
506
507                 iter = tmp;
508         }
509 }
510
511 void
512 AudioStreamView::show_all_fades ()
513 {
514         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
515                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
516                 if (arv) {
517                         arv->set_fade_visibility (true);
518                 }
519         }
520 }
521
522 void
523 AudioStreamView::hide_all_fades ()
524 {
525         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
526                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
527                 if (arv) {
528                         arv->set_fade_visibility (false);
529                 }
530         }
531 }
532
533 void
534 AudioStreamView::hide_xfades_with (boost::shared_ptr<AudioRegion> ar)
535 {
536         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
537                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
538                 if (arv) {
539                         switch (arv->region()->coverage (ar->position(), ar->last_frame())) {
540                         case Evoral::OverlapNone:
541                                 break;
542                         default:
543                                 arv->hide_xfades ();
544                                 break;
545                         }
546                 }
547         }
548 }
549
550 void
551 AudioStreamView::color_handler ()
552 {
553         //case cAudioTrackBase:
554         if (_trackview.is_track()) {
555                 canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AudioTrackBase.get();
556         }
557
558         //case cAudioBusBase:
559         if (!_trackview.is_track()) {
560                 if (Profile->get_sae() && _trackview.route()->is_master()) {
561                         canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AudioMasterBusBase.get();
562                 } else {
563                         canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AudioBusBase.get();
564                 }
565         }
566 }
567
568 void
569 AudioStreamView::parameter_changed (string const & p)
570 {
571         if (p == "show-waveforms") {
572                 set_show_waveforms (Config->get_show_waveforms ());
573         } else if (p == "waveform-scale") {
574                 set_waveform_scale (Config->get_waveform_scale ());
575         } else if (p == "waveform-shape") {
576                 set_waveform_shape (Config->get_waveform_shape ());
577         }
578 }
579