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