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