ardour
audio_region_view.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2001-2006 Paul Davis
3 
4  This program is free software; you can r>edistribute 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 <algorithm>
22 #include <vector>
23 
24 #include <boost/scoped_array.hpp>
25 
26 #include <gtkmm.h>
27 
28 #include <gtkmm2ext/gtk_ui.h>
29 
30 #include "ardour/playlist.h"
31 #include "ardour/audioregion.h"
32 #include "ardour/audiosource.h"
33 #include "ardour/profile.h"
34 #include "ardour/session.h"
35 
36 #include "pbd/memento_command.h"
37 #include "pbd/stacktrace.h"
38 
39 #include "evoral/Curve.hpp"
40 
41 #include "canvas/rectangle.h"
42 #include "canvas/polygon.h"
43 #include "canvas/poly_line.h"
44 #include "canvas/line.h"
45 #include "canvas/text.h"
46 #include "canvas/xfade_curve.h"
47 #include "canvas/debug.h"
48 #include "canvas/utils.h"
49 #include "canvas/colors.h"
50 
51 #include "streamview.h"
52 #include "audio_region_view.h"
53 #include "audio_time_axis.h"
54 #include "public_editor.h"
55 #include "audio_region_editor.h"
56 #include "audio_streamview.h"
57 #include "region_gain_line.h"
58 #include "control_point.h"
59 #include "ghostregion.h"
60 #include "audio_time_axis.h"
61 #include "rgb_macros.h"
62 #include "gui_thread.h"
63 #include "ardour_ui.h"
64 
65 #include "i18n.h"
66 
67 #define MUTED_ALPHA 48
68 
69 using namespace std;
70 using namespace ARDOUR;
71 using namespace PBD;
72 using namespace Editing;
73 using namespace ArdourCanvas;
74 
75 static double const handle_size = 10; /* height of fade handles */
76 
77 AudioRegionView::AudioRegionView (ArdourCanvas::Container *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu,
78  uint32_t basic_color)
79  : RegionView (parent, tv, r, spu, basic_color)
80  , sync_mark(0)
81  , fade_in_handle(0)
82  , fade_out_handle(0)
83  , fade_in_trim_handle(0)
84  , fade_out_trim_handle(0)
85  , start_xfade_curve (0)
86  , start_xfade_rect (0)
87  , _start_xfade_visible (false)
88  , end_xfade_curve (0)
89  , end_xfade_rect (0)
90  , _end_xfade_visible (false)
91  , _amplitude_above_axis(1.0)
92  , trim_fade_in_drag_active(false)
93  , trim_fade_out_drag_active(false)
94 {
95  Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&AudioRegionView::parameter_changed, this, _1), gui_context());
96 }
97 
98 AudioRegionView::AudioRegionView (ArdourCanvas::Container *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu,
99  uint32_t basic_color, bool recording, TimeAxisViewItem::Visibility visibility)
100  : RegionView (parent, tv, r, spu, basic_color, recording, visibility)
101  , sync_mark(0)
102  , fade_in_handle(0)
103  , fade_out_handle(0)
104  , fade_in_trim_handle(0)
105  , fade_out_trim_handle(0)
106  , start_xfade_curve (0)
107  , start_xfade_rect (0)
108  , _start_xfade_visible (false)
109  , end_xfade_curve (0)
110  , end_xfade_rect (0)
111  , _end_xfade_visible (false)
112  , _amplitude_above_axis(1.0)
113  , trim_fade_in_drag_active(false)
114  , trim_fade_out_drag_active(false)
115 {
116  Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&AudioRegionView::parameter_changed, this, _1), gui_context());
117 }
118 
120  : RegionView (other, boost::shared_ptr<Region> (other_region))
121  , fade_in_handle(0)
122  , fade_out_handle(0)
123  , fade_in_trim_handle(0)
124  , fade_out_trim_handle(0)
125  , start_xfade_curve (0)
126  , start_xfade_rect (0)
127  , _start_xfade_visible (false)
128  , end_xfade_curve (0)
129  , end_xfade_rect (0)
130  , _end_xfade_visible (false)
131  , _amplitude_above_axis (other._amplitude_above_axis)
132  , trim_fade_in_drag_active(false)
133  , trim_fade_out_drag_active(false)
134 {
135  init (true);
136 
137  Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&AudioRegionView::parameter_changed, this, _1), gui_context());
138 }
139 
140 void
142 {
143  // FIXME: Some redundancy here with RegionView::init. Need to figure out
144  // where order is important and where it isn't...
145 
146  RegionView::init (wfd);
147 
148  _amplitude_above_axis = 1.0;
149 
150  create_waves ();
151 
152  if (!_recregion) {
153  fade_in_handle = new ArdourCanvas::Rectangle (group);
154  CANVAS_DEBUG_NAME (fade_in_handle, string_compose ("fade in handle for %1", region()->name()));
155  fade_in_handle->set_outline_color (ArdourCanvas::rgba_to_color (0, 0, 0, 1.0));
156  fade_in_handle->set_fill_color (ARDOUR_UI::config()->color ("inactive fade handle"));
157  fade_in_handle->set_data ("regionview", this);
158  fade_in_handle->hide ();
159 
160  fade_out_handle = new ArdourCanvas::Rectangle (group);
161  CANVAS_DEBUG_NAME (fade_out_handle, string_compose ("fade out handle for %1", region()->name()));
162  fade_out_handle->set_outline_color (ArdourCanvas::rgba_to_color (0, 0, 0, 1.0));
163  fade_out_handle->set_fill_color (ARDOUR_UI::config()->color ("inactive fade handle"));
164  fade_out_handle->set_data ("regionview", this);
165  fade_out_handle->hide ();
166 
167  fade_in_trim_handle = new ArdourCanvas::Rectangle (group);
168  CANVAS_DEBUG_NAME (fade_in_handle, string_compose ("fade in trim handle for %1", region()->name()));
169  fade_in_trim_handle->set_outline_color (ArdourCanvas::rgba_to_color (0, 0, 0, 1.0));
170  fade_in_trim_handle->set_fill_color (ARDOUR_UI::config()->color ("inactive fade handle"));
171  fade_in_trim_handle->set_data ("regionview", this);
172  fade_in_trim_handle->hide ();
173 
174  fade_out_trim_handle = new ArdourCanvas::Rectangle (group);
175  CANVAS_DEBUG_NAME (fade_out_handle, string_compose ("fade out trim handle for %1", region()->name()));
176  fade_out_trim_handle->set_outline_color (ArdourCanvas::rgba_to_color (0, 0, 0, 1.0));
177  fade_out_trim_handle->set_fill_color (ARDOUR_UI::config()->color ("inactive fade handle"));
178  fade_out_trim_handle->set_data ("regionview", this);
179  fade_out_trim_handle->hide ();
180  }
181 
183 
184  if (!trackview.session()->config.get_show_region_fades()) {
185  set_fade_visibility (false);
186  }
187 
188  const string line_name = _region->name() + ":gain";
189 
190  if (!Profile->get_sae()) {
191  gain_line.reset (new AudioRegionGainLine (line_name, *this, *group, audio_region()->envelope()));
192  }
193 
195  gain_line->reset ();
196 
198 
199  region_muted ();
201 
203 
204  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
205  (*i)->set_duration (_region->length() / samples_per_pixel);
206  }
207 
208  region_locked ();
212 
214 
215  if (fade_in_handle) {
216  fade_in_handle->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this, false));
217  }
218 
219  if (fade_out_handle) {
220  fade_out_handle->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this, false));
221  }
222 
223  if (fade_in_trim_handle) {
224  fade_in_trim_handle->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_trim_handle, this, true));
225  }
226 
227  if (fade_out_trim_handle) {
228  fade_out_trim_handle->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_trim_handle, this, true));
229  }
230 
231  set_colors ();
232 
234 
235  if (frame_handle_start) {
236  frame_handle_start->raise_to_top ();
237  }
238  if (frame_handle_end) {
239  frame_handle_end->raise_to_top ();
240  }
241 
242  /* XXX sync mark drag? */
243 }
244 
246 {
247  in_destructor = true;
248 
249  RegionViewGoingAway (this); /* EMIT_SIGNAL */
250 
251  for (vector<ScopedConnection*>::iterator i = _data_ready_connections.begin(); i != _data_ready_connections.end(); ++i) {
252  delete *i;
253  }
254 
255  for (list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) {
256  delete ((*i).second);
257  }
258 
259  /* all waveviews etc will be destroyed when the group is destroyed */
260 }
261 
264 {
265  // "Guaranteed" to succeed...
267 }
268 
269 void
271 {
272  ENSURE_GUI_THREAD (*this, &AudioRegionView::region_changed, what_changed);
273 
274  RegionView::region_changed (what_changed);
275 
276  if (what_changed.contains (ARDOUR::Properties::scale_amplitude)) {
278  }
279  if (what_changed.contains (ARDOUR::Properties::fade_in)) {
280  fade_in_changed ();
281  }
282  if (what_changed.contains (ARDOUR::Properties::fade_out)) {
283  fade_out_changed ();
284  }
285  if (what_changed.contains (ARDOUR::Properties::fade_in_active)) {
287  }
288  if (what_changed.contains (ARDOUR::Properties::fade_out_active)) {
290  }
291  if (what_changed.contains (ARDOUR::Properties::envelope_active)) {
293  }
294  if (what_changed.contains (ARDOUR::Properties::valid_transients)) {
296  }
297 }
298 
299 void
301 {
303 }
304 
305 void
307 {
309 }
310 
311 void
313 {
314  if (start_xfade_rect) {
315  if (audio_region()->fade_in_active()) {
316  start_xfade_rect->set_fill (false);
317  } else {
318  start_xfade_rect->set_fill_color (ARDOUR_UI::config()->color_mod ("inactive crossfade", "inactive crossfade"));
319  start_xfade_rect->set_fill (true);
320  }
321  }
322 }
323 
324 void
326 {
327  if (end_xfade_rect) {
328  if (audio_region()->fade_out_active()) {
329  end_xfade_rect->set_fill (false);
330  } else {
331  end_xfade_rect->set_fill_color (ARDOUR_UI::config()->color_mod ("inactive crossfade", "inactive crossfade"));
332  end_xfade_rect->set_fill (true);
333  }
334  }
335 }
336 
337 
338 void
340 {
341  for (uint32_t n = 0; n < waves.size(); ++n) {
342  waves[n]->gain_changed ();
343  }
344 }
345 
346 void
348 {
349  std::string str = RegionView::make_name ();
350 
351  if (audio_region()->speed_mismatch (trackview.session()->frame_rate())) {
352  str = string ("*") + str;
353  }
354 
355  if (_region->muted()) {
356  str = string ("!") + str;
357  }
358 
359  set_item_name (str, this);
360  set_name_text (str);
361 }
362 
363 void
365 {
366  AudioGhostRegion* agr;
367 
368  RegionView::region_resized(what_changed);
369  PropertyChange interesting_stuff;
370 
371  interesting_stuff.add (ARDOUR::Properties::start);
372  interesting_stuff.add (ARDOUR::Properties::length);
373 
374  if (what_changed.contains (interesting_stuff)) {
375 
376  for (uint32_t n = 0; n < waves.size(); ++n) {
377  waves[n]->region_resized ();
378  }
379 
380  for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
381  if ((agr = dynamic_cast<AudioGhostRegion*>(*i)) != 0) {
382 
383  for (vector<WaveView*>::iterator w = agr->waves.begin(); w != agr->waves.end(); ++w) {
384  (*w)->region_resized ();
385  }
386  }
387  }
388 
389  /* hide transient lines that extend beyond the region end */
390 
391  list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
392 
393  for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
394  if (l->first > _region->length() - 1) {
395  l->second->hide();
396  } else {
397  l->second->show();
398  }
399  }
400  }
401 }
402 
403 void
405 {
407  assert(_pixel_width == pixel_width);
408 
409  if (pixel_width <= 20.0 || _height < 5.0 || !trackview.session()->config.get_show_region_fades()) {
410  if (fade_in_handle) { fade_in_handle->hide(); }
411  if (fade_out_handle) { fade_out_handle->hide(); }
412  if (fade_in_trim_handle) { fade_in_trim_handle->hide(); }
414  if (start_xfade_rect) { start_xfade_rect->set_outline (false); }
415  if (end_xfade_rect) { end_xfade_rect->set_outline (false); }
416  }
417 
418  AnalysisFeatureList analysis_features = _region->transients();
419  AnalysisFeatureList::const_iterator i;
420 
421  list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
422 
423  for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
424 
425  float x_pos = trackview.editor().sample_to_pixel (*i);
426 
427  (*l).second->set (ArdourCanvas::Duple (x_pos, 2.0),
428  ArdourCanvas::Duple (x_pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
429 
430  (*l).first = *i;
431 
432  (*l).second->set (ArdourCanvas::Duple (x_pos, 2.0),
433  ArdourCanvas::Duple (x_pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
434  }
435 
437 }
438 
439 void
441 {
444 }
445 
446 void
448 {
449  /* position of fade handle offset from the top of the region view */
450  double const handle_pos = 0.0;
451 
452  if (fade_in_handle) {
453  fade_in_handle->set_y0 (handle_pos);
454  fade_in_handle->set_y1 (handle_pos + handle_size);
455  }
456 
457  if (fade_out_handle) {
458  fade_out_handle->set_y0 (handle_pos);
459  fade_out_handle->set_y1 (handle_pos + handle_size);
460  }
461 
462  if (fade_in_trim_handle) {
464  fade_in_trim_handle->set_y1 (_height);
465  }
466 
467  if (fade_out_trim_handle) {
469  fade_out_trim_handle->set_y1 (_height);
470  }
471 }
472 
473 void
475 {
476  RegionView::set_height (height);
477 
478  uint32_t wcnt = waves.size();
479 
480  for (uint32_t n = 0; n < wcnt; ++n) {
481  gdouble ht;
482 
483  if (height < NAME_HIGHLIGHT_THRESH) {
484  ht = ((height - 2 * wcnt) / (double) wcnt);
485  } else {
486  ht = (((height - 2 * wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt);
487  }
488 
489  gdouble yoff = n * (ht + 1);
490 
491  waves[n]->set_height (ht);
492  waves[n]->set_y_position (yoff + 2);
493  }
494 
495  if (gain_line) {
496 
497  if ((height/wcnt) < NAME_HIGHLIGHT_THRESH) {
498  gain_line->hide ();
499  } else {
501  }
502 
503  gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE) - 2);
504  }
505 
507 
508  /* Update hights for any active feature lines */
509  list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
510 
511  for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
512 
513  float pos_x = trackview.editor().sample_to_pixel((*l).first);
514 
515  if (height >= NAME_HIGHLIGHT_THRESH) {
516  (*l).second->set (ArdourCanvas::Duple (pos_x, 2.0),
517  ArdourCanvas::Duple (pos_x, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
518  } else {
519  (*l).second->set (ArdourCanvas::Duple (pos_x, 2.0),
520  ArdourCanvas::Duple (pos_x, _height - 1));
521  }
522  }
523 
524  if (name_text) {
525  name_text->raise_to_top();
526  }
527 
529 }
530 
531 void
533 {
536 }
537 
538 void
540 {
542 }
543 
544 void
546 {
547  trim_fade_in_drag_active = drag_active;
548  if (fade_in_handle == 0) {
549  return;
550  }
551 
552  /* smallest size for a fade is 64 frames */
553 
554  width = std::max ((framecnt_t) 64, width);
555 
556  /* round here to prevent little visual glitches with sub-pixel placement */
557  double const pwidth = floor (width / samples_per_pixel);
558  double const handle_left = pwidth;
559 
560  /* Put the fade in handle so that its left side is at the end-of-fade line */
561  fade_in_handle->set_x0 (handle_left);
562  fade_in_handle->set_x1 (handle_left + handle_size);
563 
564  if (fade_in_trim_handle) {
565  fade_in_trim_handle->set_x0 (0);
567  }
568 
569  if (fade_in_handle->visible()) {
570  //see comment for drag_start
571  entered();
572  }
573 
574  if (pwidth < 5) {
576  return;
577  }
578 
579  if (!trackview.session()->config.get_show_region_fades()) {
580  hide_start_xfade ();
581  return;
582  }
583 
584  double effective_height;
585 
587  effective_height = _height - NAME_HIGHLIGHT_SIZE;
588  } else {
589  effective_height = _height;
590  }
591 
592  /* points *MUST* be in anti-clockwise order */
593 
594  Points points;
595  Points::size_type pi;
598  double length = list->length();
599 
600  points.assign (list->size(), Duple());
601 
602  for (x = list->begin(), pi = 0; x != list->end(); ++x, ++pi) {
603  points[pi].x = (pwidth * ((*x)->when/length));
604  points[pi].y = effective_height - ((*x)->value * (effective_height - 1.));
605  }
606 
607  /* draw the line */
608 
609  redraw_start_xfade_to (ar, width, points, effective_height, handle_left);
610 
611  /* ensure trim handle stays on top */
612  if (frame_handle_start) {
613  frame_handle_start->raise_to_top();
614  }
615 }
616 
617 void
619 {
621 }
622 
623 void
625 {
626  trim_fade_out_drag_active = drag_active;
627  if (fade_out_handle == 0) {
628  return;
629  }
630 
631  /* smallest size for a fade is 64 frames */
632 
633  width = std::max ((framecnt_t) 64, width);
634 
635 
636  double const pwidth = floor(trackview.editor().sample_to_pixel (width));
637 
638  /* the right edge should be right on the region frame is the pixel
639  * width is zero. Hence the additional + 1.0 at the end.
640  */
641 
642  double const handle_right = rint(trackview.editor().sample_to_pixel (_region->length()) - pwidth);
643  double const trim_handle_right = rint(trackview.editor().sample_to_pixel (_region->length()));
644 
645  /* Put the fade out handle so that its right side is at the end-of-fade line;
646  */
647  fade_out_handle->set_x0 (handle_right - handle_size);
648  fade_out_handle->set_x1 (handle_right);
649  if (fade_out_trim_handle) {
650  fade_out_trim_handle->set_x0 (1 + trim_handle_right - handle_size);
651  fade_out_trim_handle->set_x1 (1 + trim_handle_right);
652  }
653 
654  if (fade_out_handle->visible()) {
655  //see comment for drag_start
656  entered();
657  }
658  /* don't show shape if its too small */
659 
660  if (pwidth < 5) {
661  hide_end_xfade();
662  return;
663  }
664 
665  if (!trackview.session()->config.get_show_region_fades()) {
666  hide_end_xfade();
667  return;
668  }
669 
670  double effective_height;
671 
672  effective_height = _height;
673 
674  if (ARDOUR_UI::config()->get_show_name_highlight() && effective_height >= NAME_HIGHLIGHT_THRESH) {
675  effective_height -= NAME_HIGHLIGHT_SIZE;
676  }
677 
678  /* points *MUST* be in anti-clockwise order */
679 
680  Points points;
681  Points::size_type pi;
684  double length = list->length();
685 
686  points.assign (list->size(), Duple());
687 
688  for (x = list->begin(), pi = 0; x != list->end(); ++x, ++pi) {
689  points[pi].x = _pixel_width - pwidth + (pwidth * ((*x)->when/length));
690  points[pi].y = effective_height - ((*x)->value * (effective_height - 1.));
691  }
692 
693  /* draw the line */
694 
695  redraw_end_xfade_to (ar, width, points, effective_height, handle_right, pwidth);
696 
697  /* ensure trim handle stays on top */
698  if (frame_handle_end) {
699  frame_handle_end->raise_to_top();
700  }
701 }
702 
705 {
706  return audio_region()->fade_in()->back()->when;
707 }
708 
711 {
712  return audio_region()->fade_out()->back()->when;
713 }
714 
715 
716 void
718 {
720 
721  if (!ar->fade_in() || ar->fade_in()->empty()) {
722  return;
723  }
724 
726  reset_fade_in_shape_width (ar, ar->fade_in()->back()->when);
727 }
728 
729 void
730 AudioRegionView::redraw_start_xfade_to (boost::shared_ptr<AudioRegion> ar, framecnt_t /*width*/, Points& points, double effective_height,
731  double rect_width)
732 {
733  if (points.size() < 2) {
734  return;
735  }
736 
737  if (!start_xfade_curve) {
738  start_xfade_curve = new ArdourCanvas::XFadeCurve (group, ArdourCanvas::XFadeCurve::Start);
739  CANVAS_DEBUG_NAME (start_xfade_curve, string_compose ("xfade start out line for %1", region()->name()));
740  start_xfade_curve->set_fill_color (ARDOUR_UI::config()->color_mod ("active crossfade", "crossfade alpha"));
741  start_xfade_curve->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
742  start_xfade_curve->set_ignore_events (true);
743  }
744  if (!start_xfade_rect) {
745  start_xfade_rect = new ArdourCanvas::Rectangle (group);
746  CANVAS_DEBUG_NAME (start_xfade_rect, string_compose ("xfade start rect for %1", region()->name()));
747  start_xfade_rect->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
748  start_xfade_rect->set_fill (false);
749  start_xfade_rect->set_outline (false);
750  start_xfade_rect->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_start_xfade_event), start_xfade_rect, this));
751  start_xfade_rect->set_data ("regionview", this);
752  }
753 
754  start_xfade_rect->set (ArdourCanvas::Rect (0.0, 0.0, rect_width, effective_height));
755 
756  /* fade out line */
757 
759  Points ipoints;
760  Points::size_type npoints;
761 
762  if (!inverse) {
763 
764  /* there is no explicit inverse fade in curve, so take the
765  * regular fade in curve given to use as "points" (already a
766  * set of coordinates), and convert to the inverse shape.
767  */
768 
769  npoints = points.size();
770  ipoints.assign (npoints, Duple());
771 
772  for (Points::size_type i = 0, pci = 0; i < npoints; ++i, ++pci) {
773  ArdourCanvas::Duple &p (ipoints[pci]);
774  /* leave x-axis alone but invert with respect to y-axis */
775  p.y = effective_height - points[pci].y;
776  }
777 
778  } else {
779 
780  /* there is an explicit inverse fade in curve. Grab the points
781  and convert them into coordinates for the inverse fade in
782  line.
783  */
784 
785  npoints = inverse->size();
786  ipoints.assign (npoints, Duple());
787 
789  Points::size_type pi;
790  double length = inverse->length();
791 
792  for (x = inverse->begin(), pi = 0; x != inverse->end(); ++x, ++pi) {
793  ArdourCanvas::Duple& p (ipoints[pi]);
794  p.x = (rect_width * ((*x)->when/length));
795  p.y = effective_height - ((*x)->value * (effective_height));
796  }
797  }
798 
799  start_xfade_curve->set_inout (points, ipoints);
800 
802 }
803 
804 void
806 {
808 
809  if (!ar->fade_out() || ar->fade_out()->empty()) {
810  return;
811  }
812 
813  show_end_xfade();
814 
816 }
817 
818 void
819 AudioRegionView::redraw_end_xfade_to (boost::shared_ptr<AudioRegion> ar, framecnt_t width, Points& points, double effective_height,
820  double rect_edge, double rect_width)
821 {
822  if (points.size() < 2) {
823  return;
824  }
825 
826  if (!end_xfade_curve) {
827  end_xfade_curve = new ArdourCanvas::XFadeCurve (group, ArdourCanvas::XFadeCurve::End);
828  CANVAS_DEBUG_NAME (end_xfade_curve, string_compose ("xfade end out line for %1", region()->name()));
829  end_xfade_curve->set_fill_color (ARDOUR_UI::config()->color_mod ("active crossfade", "crossfade alpha"));
830  end_xfade_curve->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
831  end_xfade_curve->set_ignore_events (true);
832  }
833 
834  if (!end_xfade_rect) {
835  end_xfade_rect = new ArdourCanvas::Rectangle (group);
836  CANVAS_DEBUG_NAME (end_xfade_rect, string_compose ("xfade end rect for %1", region()->name()));
837  end_xfade_rect->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
838  end_xfade_rect->set_fill (false);
839  end_xfade_rect->set_outline (false);
840  end_xfade_rect->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_end_xfade_event), end_xfade_rect, this));
841  end_xfade_rect->set_data ("regionview", this);
842  }
843 
844  end_xfade_rect->set (ArdourCanvas::Rect (rect_edge, 0.0, rect_edge + rect_width, effective_height));
845 
846  /* fade in line */
847 
849  Points ipoints;
850  Points::size_type npoints;
851 
852  if (!inverse) {
853 
854  /* there is no explicit inverse fade out curve, so take the
855  * regular fade out curve given to use as "points" (already a
856  * set of coordinates), and convert to the inverse shape.
857  */
858 
859  npoints = points.size();
860  ipoints.assign (npoints, Duple());
861 
862  Points::size_type pci;
863 
864  for (pci = 0; pci < npoints; ++pci) {
865  ArdourCanvas::Duple &p (ipoints[pci]);
866  p.y = effective_height - points[pci].y;
867  }
868 
869  } else {
870 
871  /* there is an explicit inverse fade out curve. Grab the points
872  and convert them into coordinates for the inverse fade out
873  line.
874  */
875 
876  npoints = inverse->size();
877  ipoints.assign (npoints, Duple());
878 
879  const double rend = trackview.editor().sample_to_pixel (_region->length() - width);
880 
882  Points::size_type pi;
883  double length = inverse->length();
884 
885  for (x = inverse->begin(), pi = 0; x != inverse->end(); ++x, ++pi) {
886  ArdourCanvas::Duple& p (ipoints[pi]);
887  p.x = (rect_width * ((*x)->when/length)) + rend;
888  p.y = effective_height - ((*x)->value * (effective_height));
889  }
890  }
891 
892  end_xfade_curve->set_inout (ipoints, points);
893 
894  show_end_xfade();
895 }
896 
897 void
899 {
900  hide_start_xfade ();
901  hide_end_xfade ();
902 }
903 
904 void
906 {
907  if (start_xfade_curve) {
908  start_xfade_curve->hide();
909  }
910  if (start_xfade_rect) {
911  start_xfade_rect->hide ();
912  }
913 
914  _start_xfade_visible = false;
915 }
916 
917 void
919 {
920  if (end_xfade_curve) {
921  end_xfade_curve->hide();
922  }
923  if (end_xfade_rect) {
924  end_xfade_rect->hide ();
925  }
926 
927  _end_xfade_visible = false;
928 }
929 
930 void
932 {
933  if (start_xfade_curve) {
934  start_xfade_curve->show();
935  }
936  if (start_xfade_rect) {
937  start_xfade_rect->show ();
938  }
939 
940  _start_xfade_visible = true;
941 }
942 
943 void
945 {
946  if (end_xfade_curve) {
947  end_xfade_curve->show();
948  }
949  if (end_xfade_rect) {
950  end_xfade_rect->show ();
951  }
952 
953  _end_xfade_visible = true;
954 }
955 
956 void
958 {
960 
961  if (ARDOUR_UI::config()->get_show_waveforms ()) {
962  for (uint32_t n = 0; n < waves.size(); ++n) {
963  waves[n]->set_samples_per_pixel (fpp);
964  }
965  }
966 
967  if (gain_line) {
968  gain_line->reset ();
969  }
970 
972 }
973 
974 void
976 {
977  for (uint32_t n=0; n < waves.size(); ++n) {
978  waves[n]->set_amplitude_above_axis (a);
979  }
980 }
981 
982 void
984 {
986 
987  if (gain_line) {
989  ARDOUR_UI::config()->color ("gain line") :
990  ARDOUR_UI::config()->color_mod ("gain line inactive", "gain line inactive"));
991  }
992 
994 
995  if (start_xfade_curve) {
996  start_xfade_curve->set_fill_color (ARDOUR_UI::config()->color_mod ("active crossfade", "crossfade alpha"));
997  start_xfade_curve->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
998  }
999  if (end_xfade_curve) {
1000  end_xfade_curve->set_fill_color (ARDOUR_UI::config()->color_mod ("active crossfade", "crossfade alpha"));
1001  end_xfade_curve->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
1002  }
1003 
1004  if (start_xfade_rect) {
1005  start_xfade_rect->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
1006  }
1007  if (end_xfade_rect) {
1008  end_xfade_rect->set_outline_color (ARDOUR_UI::config()->color ("crossfade line"));
1009  }
1010 }
1011 
1012 void
1014 {
1015  if (ARDOUR_UI::config()->get_show_waveforms ()) {
1016  for (uint32_t n = 0; n < waves.size(); ++n) {
1017  /* make sure the zoom level is correct, since we don't update
1018  this when waveforms are hidden.
1019  */
1020  // CAIROCANVAS
1021  // waves[n]->set_samples_per_pixel (_samples_per_pixel);
1022  waves[n]->show();
1023  }
1024  } else {
1025  for (uint32_t n = 0; n < waves.size(); ++n) {
1026  waves[n]->hide();
1027  }
1028  }
1029 }
1030 
1031 void
1033 {
1034  if (gain_line) {
1035  gain_line->hide ();
1036  }
1037 }
1038 
1039 void
1041 {
1043 }
1044 
1045 void
1047 {
1048  if (!gain_line) {
1049  return;
1050  }
1051 
1052  if (ARDOUR_UI::config()->get_show_region_gain() || trackview.editor().current_mouse_mode() == Editing::MouseDraw || trackview.editor().current_mouse_mode() == Editing::MouseRange ) {
1054  gain_line->canvas_group().raise_to_top ();
1055 
1056  } else {
1058  }
1059 }
1060 
1061 void
1063 {
1064  // cerr << "AudioRegionView::create_waves() called on " << this << endl;//DEBUG
1065  RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
1066 
1067  if (!atv.track()) {
1068  return;
1069  }
1070 
1071  ChanCount nchans = atv.track()->n_channels();
1072 
1073  // cerr << "creating waves for " << _region->name() << " with wfd = " << wait_for_data
1074  // << " and channels = " << nchans.n_audio() << endl;
1075 
1076  /* in tmp_waves, set up null pointers for each channel so the vector is allocated */
1077  for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
1078  tmp_waves.push_back (0);
1079  }
1080 
1081  for (vector<ScopedConnection*>::iterator i = _data_ready_connections.begin(); i != _data_ready_connections.end(); ++i) {
1082  delete *i;
1083  }
1084 
1085  _data_ready_connections.clear ();
1086 
1087  for (uint32_t i = 0; i < nchans.n_audio(); ++i) {
1088  _data_ready_connections.push_back (0);
1089  }
1090 
1091  for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
1092 
1093  if (n >= audio_region()->n_channels()) {
1094  break;
1095  }
1096 
1097  // cerr << "\tchannel " << n << endl;
1098 
1099  if (wait_for_data) {
1100  if (audio_region()->audio_source(n)->peaks_ready (boost::bind (&AudioRegionView::peaks_ready_handler, this, n), &_data_ready_connections[n], gui_context())) {
1101  // cerr << "\tData is ready\n";
1102  create_one_wave (n, true);
1103  } else {
1104  // cerr << "\tdata is not ready\n";
1105  // we'll get a PeaksReady signal from the source in the future
1106  // and will call create_one_wave(n) then.
1107  }
1108 
1109  } else {
1110  // cerr << "\tdon't delay, display today!\n";
1111  create_one_wave (n, true);
1112  }
1113 
1114  }
1115 }
1116 
1117 void
1118 AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/)
1119 {
1120  //cerr << "AudioRegionView::create_one_wave() called which: " << which << " this: " << this << endl;//DEBUG
1121  RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
1122  uint32_t nchans = atv.track()->n_channels().n_audio();
1123  uint32_t n;
1124  uint32_t nwaves = std::min (nchans, audio_region()->n_channels());
1125  gdouble ht;
1126 
1128  ht = ((trackview.current_height()) / (double) nchans);
1129  } else {
1130  ht = ((trackview.current_height() - NAME_HIGHLIGHT_SIZE) / (double) nchans);
1131  }
1132 
1133  gdouble yoff = which * ht;
1134 
1135  WaveView *wave = new WaveView (group, audio_region ());
1136  CANVAS_DEBUG_NAME (wave, string_compose ("wave view for chn %1 of %2", which, get_item_name()));
1137 
1138  wave->set_channel (which);
1139  wave->set_y_position (yoff);
1140  wave->set_height (ht);
1141  wave->set_samples_per_pixel (samples_per_pixel);
1142  wave->set_show_zero_line (true);
1143  wave->set_clip_level (ARDOUR_UI::config()->get_waveform_clip_level ());
1144  wave->set_start_shift (1.0);
1145 
1146  wave->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_wave_view_event), wave, this));
1147 
1148  switch (ARDOUR_UI::config()->get_waveform_shape()) {
1149  case Rectified:
1150  wave->set_shape (WaveView::Rectified);
1151  break;
1152  default:
1153  wave->set_shape (WaveView::Normal);
1154  }
1155 
1156  wave->set_logscaled (ARDOUR_UI::config()->get_waveform_scale() == Logarithmic);
1157 
1158  vector<ArdourCanvas::WaveView*> v;
1159  v.push_back (wave);
1161 
1162  if (!ARDOUR_UI::config()->get_show_waveforms ()) {
1163  wave->hide();
1164  }
1165 
1166  /* note: calling this function is serialized by the lock
1167  held in the peak building thread that signals that
1168  peaks are ready for use *or* by the fact that it is
1169  called one by one from the GUI thread.
1170  */
1171 
1172  if (which < nchans) {
1173  tmp_waves[which] = wave;
1174  } else {
1175  /* n-channel track, >n-channel source */
1176  }
1177 
1178  /* see if we're all ready */
1179 
1180  for (n = 0; n < nchans; ++n) {
1181  if (tmp_waves[n] == 0) {
1182  break;
1183  }
1184  }
1185 
1186  if (n == nwaves && waves.empty()) {
1187  /* all waves are ready */
1188  tmp_waves.resize(nwaves);
1189 
1190  waves = tmp_waves;
1191  tmp_waves.clear ();
1192 
1193  /* all waves created, don't hook into peaks ready anymore */
1194  delete _data_ready_connections[which];
1195  _data_ready_connections[which] = 0;
1196  }
1197 }
1198 
1199 void
1201 {
1202  Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&AudioRegionView::create_one_wave, this, which, false));
1203  // cerr << "AudioRegionView::peaks_ready_handler() called on " << which << " this: " << this << endl;
1204 }
1205 
1206 void
1207 AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, bool with_guard_points)
1208 {
1209  if (!gain_line) {
1210  return;
1211  }
1212 
1213  double x, y;
1214 
1215  /* don't create points that can't be seen */
1216 
1218 
1219  x = ev->button.x;
1220  y = ev->button.y;
1221 
1222  item->canvas_to_item (x, y);
1223 
1225 
1226  if (fx > _region->length()) {
1227  return;
1228  }
1229 
1230  /* compute vertical fractional position */
1231 
1232  y = 1.0 - (y / (_height - NAME_HIGHLIGHT_SIZE));
1233 
1234  /* map using gain line */
1235 
1237 
1238  /* XXX STATEFUL: can't convert to stateful diff until we
1239  can represent automation data with it.
1240  */
1241 
1242  trackview.editor().begin_reversible_command (_("add gain control point"));
1243  XMLNode &before = audio_region()->envelope()->get_state();
1244 
1245  if (!audio_region()->envelope_active()) {
1246  XMLNode &region_before = audio_region()->get_state();
1248  XMLNode &region_after = audio_region()->get_state();
1249  trackview.session()->add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &region_before, &region_after));
1250  }
1251 
1252  audio_region()->envelope()->add (fx, y, with_guard_points);
1253 
1254  XMLNode &after = audio_region()->envelope()->get_state();
1255  trackview.session()->add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
1257 }
1258 
1259 void
1260 AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent* /*ev*/)
1261 {
1262  ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
1263  audio_region()->envelope()->erase (cp->model());
1264 }
1265 
1266 GhostRegion*
1268 {
1269  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&trackview);
1270  assert(rtv);
1271 
1272  double unit_position = _region->position () / samples_per_pixel;
1273  AudioGhostRegion* ghost = new AudioGhostRegion (tv, trackview, unit_position);
1274  uint32_t nchans;
1275 
1276  nchans = rtv->track()->n_channels().n_audio();
1277 
1278  for (uint32_t n = 0; n < nchans; ++n) {
1279 
1280  if (n >= audio_region()->n_channels()) {
1281  break;
1282  }
1283 
1284  WaveView *wave = new WaveView (ghost->group, audio_region());
1285  CANVAS_DEBUG_NAME (wave, string_compose ("ghost wave for %1", get_item_name()));
1286 
1287  wave->set_channel (n);
1288  wave->set_samples_per_pixel (samples_per_pixel);
1289  wave->set_amplitude_above_axis (_amplitude_above_axis);
1290 
1291  ghost->waves.push_back(wave);
1292  }
1293 
1294  ghost->set_height ();
1296  ghost->set_colors();
1297  ghosts.push_back (ghost);
1298 
1299  return ghost;
1300 }
1301 
1302 void
1304 {
1307 
1309 
1310  if ((trackview.editor().current_mouse_mode() == Editing::MouseObject)) {
1311  if (start_xfade_rect) {
1312  start_xfade_rect->set_outline (true);
1313  }
1314  if (end_xfade_rect) {
1315  end_xfade_rect->set_outline (true);
1316  }
1317  if (fade_in_handle) {
1318  fade_in_handle->show ();
1319  fade_in_handle->raise_to_top ();
1320  }
1321  if (fade_out_handle) {
1322  fade_out_handle->show ();
1323  fade_out_handle->raise_to_top ();
1324  }
1325  if (fade_in_trim_handle) {
1327  if (!ar->locked() && (ar->fade_in()->back()->when > 64 || (ar->can_trim() & Trimmable::FrontTrimEarlier))) {
1328  fade_in_trim_handle->show ();
1329  fade_in_trim_handle->raise_to_top ();
1330  } else {
1331  fade_in_trim_handle->hide ();
1332  }
1333  }
1334  if (fade_out_trim_handle) {
1336  if (!ar->locked() && (ar->fade_out()->back()->when > 64 || (ar->can_trim() & Trimmable::EndTrimLater))) {
1337  fade_out_trim_handle->show ();
1338  fade_out_trim_handle->raise_to_top ();
1339  } else {
1340  fade_out_trim_handle->hide ();
1341  }
1342  }
1343  }
1344 }
1345 
1346 void
1348 {
1351 
1352  if (gain_line) {
1354  }
1355 
1356  if (fade_in_handle) { fade_in_handle->hide(); }
1357  if (fade_out_handle) { fade_out_handle->hide(); }
1358  if (fade_in_trim_handle) { fade_in_trim_handle->hide(); }
1359  if (fade_out_trim_handle) { fade_out_trim_handle->hide(); }
1360  if (start_xfade_rect) { start_xfade_rect->set_outline (false); }
1361  if (end_xfade_rect) { end_xfade_rect->set_outline (false); }
1362 }
1363 
1364 void
1366 {
1367  if (gain_line) {
1369  ARDOUR_UI::config()->color ("gain line") :
1370  ARDOUR_UI::config()->color_mod ("gain line inactive", "gain line inactive"));
1372  }
1373 }
1374 
1375 void
1377 {
1378  //case cMutedWaveForm:
1379  //case cWaveForm:
1380  //case cWaveFormClip:
1381  //case cZeroLine:
1382  set_colors ();
1383 
1384  //case cGainLineInactive:
1385  //case cGainLine:
1387 
1388 }
1389 
1390 void
1392 {
1394 }
1395 
1396 void
1397 AudioRegionView::set_some_waveform_colors (vector<ArdourCanvas::WaveView*>& waves_to_color)
1398 {
1399  ArdourCanvas::Color fill;
1400  ArdourCanvas::Color outline;
1401  ArdourCanvas::Color clip = ARDOUR_UI::config()->color ("clipped waveform");
1402  ArdourCanvas::Color zero = ARDOUR_UI::config()->color ("zero line");
1403 
1404  if (_selected) {
1405  if (_region->muted()) {
1406  /* hide outline with zero alpha */
1407  outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->color ("selected waveform outline"), 0);
1408  fill = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->color ("selected waveform fill"), MUTED_ALPHA);
1409  } else {
1410  outline = ARDOUR_UI::config()->color ("selected waveform outline");
1411  fill = ARDOUR_UI::config()->color ("selected waveform fill");
1412  }
1413  } else {
1414  if (_recregion) {
1415  outline = ARDOUR_UI::config()->color ("recording waveform outline");
1416  fill = ARDOUR_UI::config()->color ("recording waveform fill");
1417  } else {
1418  if (_region->muted()) {
1419  /* hide outline with zero alpha */
1420  outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->color ("waveform outline"), 0);
1421  fill = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->color ("waveform fill"), MUTED_ALPHA);
1422  } else {
1423  outline = ARDOUR_UI::config()->color ("waveform outline");
1424  fill = ARDOUR_UI::config()->color ("waveform fill");
1425  }
1426  }
1427  }
1428 
1429  for (vector<ArdourCanvas::WaveView*>::iterator w = waves_to_color.begin(); w != waves_to_color.end(); ++w) {
1430  (*w)->set_fill_color (fill);
1431  (*w)->set_outline_color (outline);
1432  (*w)->set_clip_color (clip);
1433  (*w)->set_zero_color (zero);
1434  }
1435 }
1436 
1437 void
1439 {
1440  if (!frame) {
1441  return;
1442  }
1443 
1445 
1447 }
1448 
1449 void
1451 {
1452  if (yn) {
1453  if (start_xfade_curve) { start_xfade_curve->show (); }
1454  if (end_xfade_curve) { end_xfade_curve->show (); }
1455  if (start_xfade_rect) { start_xfade_rect->show (); }
1456  if (end_xfade_rect) { end_xfade_rect->show (); }
1457  } else {
1458  if (start_xfade_curve) { start_xfade_curve->hide(); }
1459  if (end_xfade_curve) { end_xfade_curve->hide(); }
1460  if (fade_in_handle) { fade_in_handle->hide(); }
1461  if (fade_out_handle) { fade_out_handle->hide(); }
1462  if (fade_in_trim_handle) { fade_in_trim_handle->hide(); }
1463  if (fade_out_trim_handle) { fade_out_trim_handle->hide(); }
1464  if (start_xfade_rect) { start_xfade_rect->hide (); }
1465  if (end_xfade_rect) { end_xfade_rect->hide (); }
1466  if (start_xfade_rect) { start_xfade_rect->set_outline (false); }
1467  if (end_xfade_rect) { end_xfade_rect->set_outline (false); }
1468  }
1469 }
1470 
1471 void
1473 {
1475 
1476  if (fade_in_handle) { fade_in_handle->raise_to_top (); }
1477  if (fade_out_handle) { fade_out_handle->raise_to_top (); }
1478  if (fade_in_trim_handle) { fade_in_trim_handle->raise_to_top (); }
1479  if (fade_out_trim_handle) { fade_out_trim_handle->raise_to_top (); }
1480 }
1481 
1482 void
1484 {
1485  if (editor == 0) {
1487  }
1488 
1489  editor->present ();
1490  editor->show_all();
1491 }
1492 
1493 void
1495 {
1496  AnalysisFeatureList analysis_features = _region->transients();
1497 
1498  while (feature_lines.size() < analysis_features.size()) {
1499 
1500  ArdourCanvas::Line* canvas_item = new ArdourCanvas::Line(group);
1501  CANVAS_DEBUG_NAME (canvas_item, string_compose ("transient group for %1", region()->name()));
1502 
1503  canvas_item->set (ArdourCanvas::Duple (-1.0, 2.0),
1504  ArdourCanvas::Duple (1.0, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
1505 
1506  canvas_item->raise_to_top ();
1507  canvas_item->show ();
1508 
1509  canvas_item->set_data ("regionview", this);
1510  canvas_item->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), canvas_item, this));
1511 
1512  feature_lines.push_back (make_pair(0, canvas_item));
1513  }
1514 
1515  while (feature_lines.size() > analysis_features.size()) {
1516  ArdourCanvas::Line* line = feature_lines.back().second;
1517  feature_lines.pop_back ();
1518  delete line;
1519  }
1520 
1521  AnalysisFeatureList::const_iterator i;
1522  list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
1523 
1524  for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
1525 
1526  float *pos = new float;
1527  *pos = trackview.editor().sample_to_pixel (*i);
1528 
1529  (*l).second->set (
1530  ArdourCanvas::Duple (*pos, 2.0),
1531  ArdourCanvas::Duple (*pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1)
1532  );
1533 
1534  (*l).second->set_data ("position", pos);
1535  (*l).first = *i;
1536  }
1537 }
1538 
1539 void
1540 AudioRegionView::update_transient(float /*old_pos*/, float new_pos)
1541 {
1542  /* Find frame at old pos, calulate new frame then update region transients*/
1543  list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
1544 
1545  for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
1546 
1547  /* Line has been updated in drag so we compare to new_pos */
1548 
1549  float* pos = (float*) (*l).second->get_data ("position");
1550 
1551  if (rint(new_pos) == rint(*pos)) {
1552 
1553  framepos_t old_frame = (*l).first;
1554  framepos_t new_frame = trackview.editor().pixel_to_sample (new_pos);
1555 
1556  _region->update_transient (old_frame, new_frame);
1557 
1558  break;
1559  }
1560  }
1561 }
1562 
1563 void
1565 {
1566  /* Find frame at old pos, calulate new frame then update region transients*/
1567  list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
1568 
1569  for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
1570 
1571  /* Line has been updated in drag so we compare to new_pos */
1572  float *line_pos = (float*) (*l).second->get_data ("position");
1573 
1574  if (rint(pos) == rint(*line_pos)) {
1575  _region->remove_transient ((*l).first);
1576  break;
1577  }
1578  }
1579 }
1580 
1581 void
1583 {
1585  unhide_envelope ();
1586  drag_end ();
1587 }
1588 
1589 
1590 void
1592 {
1593  show_start_xfade ();
1594  show_end_xfade ();
1595 }
1596 
1597 void
1599 {
1601 
1602  //we used to hide xfades here. I don't see the point with the new model, but we can re-implement if needed
1603 }
1604 
1605 void
1607 {
1609  //see comment for drag_start
1610 
1611  if (fade_in_handle && fade_in_handle->visible()) {
1612  // lenght of region or fade changed, re-check
1613  // if fade_in_trim_handle or fade_out_trim_handle should
1614  // be visible. -- If the fade_in_handle is visible
1615  // we have focus and are not in internal edit mode.
1616  entered();
1617  }
1618 }
1619 
1620 void
1622 {
1623  if (p == "show-waveforms") {
1625  }
1626 }
ArdourCanvas::Container & canvas_group() const
void set_duration(double units)
Definition: ghostregion.cc:77
ArdourCanvas::Color color(const std::string &, bool *failed=0) const
Definition: ui_config.cc:567
void reset_width_dependent_items(double pixel_width)
LIBARDOUR_API PBD::PropertyDescriptor< bool > fade_out_active
Definition: audioregion.cc:65
void peaks_ready_handler(uint32_t)
static PBD::Signal1< void, RegionView * > RegionViewGoingAway
Definition: region_view.h:100
boost::shared_ptr< AudioRegionGainLine > gain_line
void update_coverage_frames(LayerDisplay)
virtual void drag_end()
bool get_sae() const
Definition: profile.h:48
ArdourCanvas::Rectangle * fade_out_handle
fade out handle, or 0
virtual void region_resized(const PBD::PropertyChange &)
Definition: region_view.cc:405
PublicEditor & editor() const
XMLNode & get_state()
Definition: region.cc:1228
bool in_destructor
Definition: region_view.h:172
boost::shared_ptr< ARDOUR::Region > _region
Definition: region_view.h:159
static double NAME_HIGHLIGHT_THRESH
virtual Editing::MouseMode current_mouse_mode() const =0
void region_scale_amplitude_changed()
void set_envelope_active(bool yn)
Definition: audioregion.cc:404
ArdourCanvas::Rectangle * fade_out_trim_handle
fade out trim handle, or 0
void temporarily_hide_envelope()
Dangerous!
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
void view_to_model_coord(double &x, double &y) const
void reset_fade_out_shape_width(boost::shared_ptr< ARDOUR::AudioRegion > ar, framecnt_t, bool drag_active=false)
boost::shared_ptr< AutomationList > fade_in()
Definition: audioregion.h:87
void remove_gain_point_event(ArdourCanvas::Item *item, GdkEvent *event)
void add_command(Command *const cmd)
Definition: session.h:787
std::vector< ArdourCanvas::WaveView * > waves
Definition: ghostregion.h:69
boost::shared_ptr< AutomationList > fade_out()
Definition: audioregion.h:89
TimeAxisView & trackview
ArdourCanvas::Rectangle * end_xfade_rect
uint32_t n_audio() const
Definition: chan_count.h:63
virtual bool canvas_fade_in_handle_event(GdkEvent *event, ArdourCanvas::Item *, AudioRegionView *, bool)=0
Definition: Beats.hpp:239
virtual std::string get_item_name() const
virtual double sample_to_pixel(framepos_t frame) const =0
ArdourCanvas::Rectangle * fade_in_handle
fade in handle, or 0
ArdourCanvas::Text * name_text
std::string make_name() const
Definition: region_view.cc:566
SessionConfiguration config
Definition: session.h:866
void init(bool wait_for_data)
void create_one_wave(uint32_t, bool)
boost::shared_ptr< ARDOUR::AudioRegion > audio_region() const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
void set_height(double)
uint32_t current_height() const
virtual void drag_start()
framecnt_t frame_rate() const
Definition: session.h:365
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
#define invalidator(x)
Definition: gui_thread.h:40
void remove_transient(float pos)
void set_fade_visibility(bool)
static UI * instance()
Definition: gtk_ui.h:119
#define UINT_RGBA_CHANGE_A(x, a)
Definition: rgb_macros.h:64
virtual void update_coverage_frames(LayerDisplay)
Definition: region_view.cc:760
void update_transient(float old_pos, float new_pos)
void region_changed(const PBD::PropertyChange &)
void setup_fade_handle_positions()
#define _(Text)
Definition: i18n.h:11
virtual bool canvas_end_xfade_event(GdkEvent *event, ArdourCanvas::Item *, AudioRegionView *)=0
AnalysisFeatureList transients()
Definition: region.h:104
void set_samples_per_pixel(double)
virtual bool canvas_fade_out_handle_event(GdkEvent *event, ArdourCanvas::Item *, AudioRegionView *, bool)=0
boost::shared_ptr< AutomationList > envelope()
Definition: audioregion.h:91
Trimmable::CanTrim can_trim() const
Definition: region.cc:1655
double _pixel_width
Definition: region_view.h:171
int64_t framecnt_t
Definition: types.h:76
void set_item_name(std::string, void *)
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
framepos_t get_fade_out_shape_width()
virtual void exited()
boost::shared_ptr< ARDOUR::Region > region() const
Definition: region_view.h:66
std::list< framepos_t > AnalysisFeatureList
Definition: types.h:530
ArdourCanvas::XFadeCurve * start_xfade_curve
void add_gain_point_event(ArdourCanvas::Item *item, GdkEvent *event, bool with_guard_points)
virtual bool canvas_feature_line_event(GdkEvent *event, ArdourCanvas::Item *, RegionView *)=0
virtual void init(bool wait_for_data)
Definition: region_view.cc:149
std::vector< ArdourCanvas::WaveView * > tmp_waves
see ::create_waves()
double length() const
Definition: amp.h:29
boost::shared_ptr< AudioSource > audio_source(uint32_t n=0) const
ARDOUR::Session * session() const
Definition: axis_view.h:52
void set_some_waveform_colors(std::vector< ArdourCanvas::WaveView * > &waves_to_color)
bool muted() const
Definition: region.h:162
boost::shared_ptr< ARDOUR::Track > track() const
Definition: route_ui.cc:1738
virtual void begin_reversible_command(std::string cmd_name)=0
#define gui_context()
Definition: gui_thread.h:36
virtual void set_frame_color()
virtual void commit_reversible_command()=0
LIBARDOUR_API PBD::PropertyDescriptor< boost::shared_ptr< AutomationList > > fade_out
Definition: audioregion.cc:69
LIBARDOUR_API PBD::PropertyDescriptor< boost::shared_ptr< AutomationList > > fade_in
Definition: audioregion.cc:67
std::vector< PBD::ScopedConnection * > _data_ready_connections
ArdourCanvas::XFadeCurve * end_xfade_curve
virtual void thaw_after_trim()
Definition: region_view.cc:920
int64_t framepos_t
Definition: types.h:66
ArdourCanvas::Rectangle * frame_handle_start
`frame' (fade) handle for the start of the item, or 0
void redraw_start_xfade_to(boost::shared_ptr< ARDOUR::AudioRegion >, framecnt_t, ArdourCanvas::Points &, double, double)
virtual void region_muted()
Definition: region_view.cc:439
virtual void set_current_trimmable(boost::shared_ptr< ARDOUR::Trimmable >)=0
void set_amplitude_above_axis(gdouble spp)
EventList::size_type size() const
void erase(iterator)
framepos_t get_fade_in_shape_width()
virtual void reset_width_dependent_items(double pixel_width)
Definition: region_view.cc:432
PBD::Signal1< void, std::string > ParameterChanged
Definition: configuration.h:44
GhostRegion * add_ghost(TimeAxisView &)
void region_resized(const PBD::PropertyChange &)
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
void set_name_text(const std::string &)
bool _selected
Definition: selectable.h:45
framepos_t position() const
Definition: region.h:112
void call_slot(EventLoop::InvalidationRecord *, const boost::function< void()> &)
Definition: abstract_ui.cc:368
std::list< std::pair< framepos_t, ArdourCanvas::Line * > > feature_lines
static PublicEditor & instance()
virtual void remove_transient(framepos_t)
Definition: region.h:298
std::vector< ArdourCanvas::WaveView * > waves
const char * name
#define MUTED_ALPHA
bool locked() const
Definition: region.h:164
uint32_t n_channels() const
Definition: region.h:259
ChanCount n_channels()
Definition: track.cc:777
boost::shared_ptr< AutomationList > inverse_fade_in()
Definition: audioregion.h:88
ArdourCanvas::Rectangle * frame
virtual void set_height(double)
Definition: region_view.cc:730
ArdourCanvas::Rectangle * fade_in_trim_handle
fade in trim handle, or 0
Definition: xml++.h:95
std::string name() const
void reset_fade_in_shape_width(boost::shared_ptr< ARDOUR::AudioRegion > ar, framecnt_t, bool drag_active=false)
virtual bool canvas_start_xfade_event(GdkEvent *event, ArdourCanvas::Item *, AudioRegionView *)=0
static UIConfiguration * config()
Definition: ardour_ui.h:188
std::vector< GhostRegion * > ghosts
Definition: region_view.h:176
virtual void set_samples_per_pixel(double)
Definition: region_view.cc:487
ARDOUR::AutomationList::iterator model() const
Definition: control_point.h:80
Definition: debug.h:30
virtual void region_changed(const PBD::PropertyChange &)
Definition: region_view.cc:368
void region_locked()
Definition: region_view.cc:398
ArdourCanvas::Rectangle * frame_handle_end
`frame' (fade) handle for the end of the item, or 0
virtual framepos_t pixel_to_sample(double pixel) const =0
EventList::const_iterator const_iterator
Definition: ControlList.hpp:84
static double const handle_size
void unhide_envelope()
Dangerous!
ArdourCanvas::Rectangle * start_xfade_rect
ArdourCanvas::Container * group
LayerDisplay
Definition: enums.h:34
bool contains(PropertyDescriptor< T > p) const
framecnt_t length() const
Definition: region.h:114
void set_line_color(uint32_t)
void region_sync_changed()
Definition: region_view.cc:606
virtual int update_transient(framepos_t, framepos_t)
Definition: region.h:293
void redraw_end_xfade_to(boost::shared_ptr< ARDOUR::AudioRegion >, framecnt_t, ArdourCanvas::Points &, double, double, double)
ControlEvent * back()
void set_height(guint32)
bool wait_for_data
Definition: region_view.h:174
boost::shared_ptr< AutomationList > inverse_fade_out()
Definition: audioregion.h:90
LIBGTKMM2EXT_API int pixel_width(const std::string &str, Pango::FontDescription &font)
void parameter_changed(std::string const &)
virtual void add(double when, double value, bool with_guards=true, bool with_default=true)
AudioRegionView(ArdourCanvas::Container *, RouteTimeAxisView &, boost::shared_ptr< ARDOUR::AudioRegion >, double initial_samples_per_pixel, uint32_t base_color)
void remove_visibility(VisibleAspects)
virtual void entered()
virtual bool canvas_wave_view_event(GdkEvent *event, ArdourCanvas::Item *, RegionView *)=0
LIBARDOUR_API PBD::PropertyDescriptor< float > scale_amplitude
Definition: audioregion.cc:66
LIBARDOUR_API PBD::PropertyDescriptor< bool > valid_transients
Definition: region.cc:62
LIBARDOUR_API PBD::PropertyDescriptor< bool > envelope_active
Definition: audioregion.cc:61
virtual void set_current_movable(boost::shared_ptr< ARDOUR::Movable >)=0
void add(PropertyID id)
virtual void set_colors()
Definition: region_view.cc:514
LIBARDOUR_API PBD::PropertyDescriptor< bool > fade_in_active
Definition: audioregion.cc:64
LIBARDOUR_API PBD::PropertyChange bounds_change
Definition: globals.cc:150
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
RegionEditor * editor
Definition: region_view.h:164
LIBARDOUR_API PBD::PropertyDescriptor< boost::shared_ptr< AutomationList > > envelope
Definition: audioregion.cc:71
static double NAME_HIGHLIGHT_SIZE
void set_visibility(VisibleAspects)
ArdourCanvas::Container * group
Definition: ghostregion.h:55
bool empty() const
LIBARDOUR_API PBD::PropertyDescriptor< framecnt_t > length
Definition: region.cc:64
LIBARDOUR_API PBD::PropertyDescriptor< bool > color
Definition: route_group.cc:50