fix #5025 part 1
[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 void
772 AudioRegionView::set_samples_per_unit (gdouble spu)
773 {
774         RegionView::set_samples_per_unit (spu);
775
776         if (Config->get_show_waveforms ()) {
777                 for (uint32_t n = 0; n < waves.size(); ++n) {
778                         waves[n]->property_samples_per_unit() = spu;
779                 }
780         }
781
782         if (gain_line) {
783                 gain_line->reset ();
784         }
785
786         reset_fade_shapes ();
787 }
788
789 void
790 AudioRegionView::set_amplitude_above_axis (gdouble spp)
791 {
792         for (uint32_t n=0; n < waves.size(); ++n) {
793                 waves[n]->property_amplitude_above_axis() = spp;
794         }
795 }
796
797 void
798 AudioRegionView::compute_colors (Gdk::Color const & basic_color)
799 {
800         RegionView::compute_colors (basic_color);
801
802         /* gain color computed in envelope_active_changed() */
803
804         fade_color = UINT_RGBA_CHANGE_A (fill_color, 120);
805 }
806
807 void
808 AudioRegionView::set_colors ()
809 {
810         RegionView::set_colors();
811
812         if (gain_line) {
813                 gain_line->set_line_color (audio_region()->envelope_active() ? ARDOUR_UI::config()->canvasvar_GainLine.get() : ARDOUR_UI::config()->canvasvar_GainLineInactive.get());
814         }
815
816         for (uint32_t n=0; n < waves.size(); ++n) {
817                 if (_region->muted()) {
818                         waves[n]->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA);
819                 } else {
820                         waves[n]->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm.get();
821                 }
822
823                 waves[n]->property_clip_color() = ARDOUR_UI::config()->canvasvar_WaveFormClip.get();
824                 waves[n]->property_zero_color() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
825         }
826 }
827
828 void
829 AudioRegionView::setup_waveform_visibility ()
830 {
831         if (Config->get_show_waveforms ()) {
832                 for (uint32_t n = 0; n < waves.size(); ++n) {
833                         /* make sure the zoom level is correct, since we don't update
834                            this when waveforms are hidden.
835                         */
836                         waves[n]->property_samples_per_unit() = samples_per_unit;
837                         waves[n]->show();
838                 }
839         } else {
840                 for (uint32_t n = 0; n < waves.size(); ++n) {
841                         waves[n]->hide();
842                 }
843         }
844 }
845
846 void
847 AudioRegionView::temporarily_hide_envelope ()
848 {
849         if (gain_line) {
850                 gain_line->hide ();
851         }
852 }
853
854 void
855 AudioRegionView::unhide_envelope ()
856 {
857         update_envelope_visibility ();
858 }
859
860 void
861 AudioRegionView::update_envelope_visibility ()
862 {
863         if (!gain_line) {
864                 return;
865         }
866
867         if (Config->get_show_region_gain() || trackview.editor().current_mouse_mode() == Editing::MouseGain) {
868                 gain_line->add_visibility (AutomationLine::Line);
869         } else {
870                 gain_line->hide ();
871         }
872 }
873
874 void
875 AudioRegionView::create_waves ()
876 {
877         // cerr << "AudioRegionView::create_waves() called on " << this << endl;//DEBUG
878         RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
879
880         if (!atv.track()) {
881                 return;
882         }
883
884         ChanCount nchans = atv.track()->n_channels();
885
886         // cerr << "creating waves for " << _region->name() << " with wfd = " << wait_for_data
887         //              << " and channels = " << nchans.n_audio() << endl;
888
889         /* in tmp_waves, set up null pointers for each channel so the vector is allocated */
890         for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
891                 tmp_waves.push_back (0);
892         }
893
894         for (vector<ScopedConnection*>::iterator i = _data_ready_connections.begin(); i != _data_ready_connections.end(); ++i) {
895                 delete *i;
896         }
897
898         _data_ready_connections.clear ();
899
900         for (uint32_t i = 0; i < nchans.n_audio(); ++i) {
901                 _data_ready_connections.push_back (0);
902         }
903
904         for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
905
906                 if (n >= audio_region()->n_channels()) {
907                         break;
908                 }
909
910                 wave_caches.push_back (WaveView::create_cache ());
911
912                 // cerr << "\tchannel " << n << endl;
913
914                 if (wait_for_data) {
915                         if (audio_region()->audio_source(n)->peaks_ready (boost::bind (&AudioRegionView::peaks_ready_handler, this, n), &_data_ready_connections[n], gui_context())) {
916                                 // cerr << "\tData is ready\n";
917                                 create_one_wave (n, true);
918                         } else {
919                                 // cerr << "\tdata is not ready\n";
920                                 // we'll get a PeaksReady signal from the source in the future
921                                 // and will call create_one_wave(n) then.
922                         }
923
924                 } else {
925                         // cerr << "\tdon't delay, display today!\n";
926                         create_one_wave (n, true);
927                 }
928
929         }
930 }
931
932 void
933 AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/)
934 {
935         //cerr << "AudioRegionView::create_one_wave() called which: " << which << " this: " << this << endl;//DEBUG
936         RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
937         uint32_t nchans = atv.track()->n_channels().n_audio();
938         uint32_t n;
939         uint32_t nwaves = std::min (nchans, audio_region()->n_channels());
940         gdouble ht;
941
942         if (trackview.current_height() < NAME_HIGHLIGHT_THRESH) {
943                 ht = ((trackview.current_height()) / (double) nchans);
944         } else {
945                 ht = ((trackview.current_height() - NAME_HIGHLIGHT_SIZE) / (double) nchans);
946         }
947
948         gdouble yoff = which * ht;
949
950         WaveView *wave = new WaveView(*group);
951
952         wave->property_data_src() = (gpointer) _region.get();
953         wave->property_cache() =  wave_caches[which];
954         wave->property_cache_updater() = true;
955         wave->property_channel() =  which;
956         wave->property_length_function() = (gpointer) region_length_from_c;
957         wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c;
958         wave->property_peak_function() =  (gpointer) region_read_peaks_from_c;
959         wave->property_x() =  0.0;
960         wave->property_y() =  yoff;
961         wave->property_height() =  (double) ht;
962         wave->property_samples_per_unit() =  samples_per_unit;
963         wave->property_amplitude_above_axis() =  _amplitude_above_axis;
964
965         if (_recregion) {
966                 wave->property_wave_color() = _region->muted() ? UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_RecWaveForm.get(), MUTED_ALPHA) : ARDOUR_UI::config()->canvasvar_RecWaveForm.get();
967                 wave->property_fill_color() = ARDOUR_UI::config()->canvasvar_RecWaveFormFill.get();
968         } else {
969                 wave->property_wave_color() = _region->muted() ? UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA) : ARDOUR_UI::config()->canvasvar_WaveForm.get();
970                 wave->property_fill_color() = ARDOUR_UI::config()->canvasvar_WaveFormFill.get();
971         }
972
973         wave->property_clip_color() = ARDOUR_UI::config()->canvasvar_WaveFormClip.get();
974         wave->property_zero_color() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
975         wave->property_zero_line() = true;
976         wave->property_region_start() = _region->start();
977         wave->property_rectified() = Config->get_waveform_shape() == Rectified;
978         wave->property_logscaled() = Config->get_waveform_scale() == Logarithmic;
979
980         if (!Config->get_show_waveforms ()) {
981                 wave->hide();
982         }
983
984         /* note: calling this function is serialized by the lock
985            held in the peak building thread that signals that
986            peaks are ready for use *or* by the fact that it is
987            called one by one from the GUI thread.
988         */
989
990         if (which < nchans) {
991                 tmp_waves[which] = wave;
992         } else {
993                 /* n-channel track, >n-channel source */
994         }
995
996         /* see if we're all ready */
997
998         for (n = 0; n < nchans; ++n) {
999                 if (tmp_waves[n] == 0) {
1000                         break;
1001                 }
1002         }
1003
1004         if (n == nwaves && waves.empty()) {
1005                 /* all waves are ready */
1006                 tmp_waves.resize(nwaves);
1007
1008                 waves = tmp_waves;
1009                 tmp_waves.clear ();
1010
1011                 /* all waves created, don't hook into peaks ready anymore */
1012                 delete _data_ready_connections[which];
1013                 _data_ready_connections[which] = 0;
1014         }
1015 }
1016
1017 void
1018 AudioRegionView::peaks_ready_handler (uint32_t which)
1019 {
1020         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&AudioRegionView::create_one_wave, this, which, false));
1021         // cerr << "AudioRegionView::peaks_ready_handler() called on " << which << " this: " << this << endl;
1022 }
1023
1024 void
1025 AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
1026 {
1027         if (!gain_line) {
1028                 return;
1029         }
1030
1031         double x, y;
1032
1033         /* don't create points that can't be seen */
1034
1035         update_envelope_visibility ();
1036
1037         x = ev->button.x;
1038         y = ev->button.y;
1039
1040         item->w2i (x, y);
1041
1042         framepos_t fx = trackview.editor().pixel_to_frame (x);
1043
1044         if (fx > _region->length()) {
1045                 return;
1046         }
1047
1048         /* compute vertical fractional position */
1049
1050         y = 1.0 - (y / (_height - NAME_HIGHLIGHT_SIZE));
1051
1052         /* map using gain line */
1053
1054         gain_line->view_to_model_coord (x, y);
1055
1056         /* XXX STATEFUL: can't convert to stateful diff until we
1057            can represent automation data with it.
1058         */
1059
1060         trackview.session()->begin_reversible_command (_("add gain control point"));
1061         XMLNode &before = audio_region()->envelope()->get_state();
1062
1063         if (!audio_region()->envelope_active()) {
1064                 XMLNode &region_before = audio_region()->get_state();
1065                 audio_region()->set_envelope_active(true);
1066                 XMLNode &region_after = audio_region()->get_state();
1067                 trackview.session()->add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &region_before, &region_after));
1068         }
1069
1070         audio_region()->envelope()->add (fx, y);
1071
1072         XMLNode &after = audio_region()->envelope()->get_state();
1073         trackview.session()->add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
1074         trackview.session()->commit_reversible_command ();
1075 }
1076
1077 void
1078 AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent */*ev*/)
1079 {
1080         ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
1081         audio_region()->envelope()->erase (cp->model());
1082 }
1083
1084 void
1085 AudioRegionView::setup_waveform_shape ()
1086 {
1087         for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
1088                 (*wave)->property_rectified() = Config->get_waveform_shape() == Rectified;
1089         }
1090 }
1091
1092 void
1093 AudioRegionView::setup_waveform_scale ()
1094 {
1095         for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
1096                 (*wave)->property_logscaled() = Config->get_waveform_scale() == Logarithmic;
1097         }
1098 }
1099
1100
1101 GhostRegion*
1102 AudioRegionView::add_ghost (TimeAxisView& tv)
1103 {
1104         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&trackview);
1105         assert(rtv);
1106
1107         double unit_position = _region->position () / samples_per_unit;
1108         AudioGhostRegion* ghost = new AudioGhostRegion (tv, trackview, unit_position);
1109         uint32_t nchans;
1110
1111         nchans = rtv->track()->n_channels().n_audio();
1112
1113         for (uint32_t n = 0; n < nchans; ++n) {
1114
1115                 if (n >= audio_region()->n_channels()) {
1116                         break;
1117                 }
1118
1119                 WaveView *wave = new WaveView(*ghost->group);
1120
1121                 wave->property_data_src() = _region.get();
1122                 wave->property_cache() =  wave_caches[n];
1123                 wave->property_cache_updater() = false;
1124                 wave->property_channel() = n;
1125                 wave->property_length_function() = (gpointer)region_length_from_c;
1126                 wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c;
1127                 wave->property_peak_function() =  (gpointer) region_read_peaks_from_c;
1128                 wave->property_x() =  0.0;
1129                 wave->property_samples_per_unit() =  samples_per_unit;
1130                 wave->property_amplitude_above_axis() =  _amplitude_above_axis;
1131
1132                 wave->property_region_start() = _region->start();
1133
1134                 ghost->waves.push_back(wave);
1135         }
1136
1137         ghost->set_height ();
1138         ghost->set_duration (_region->length() / samples_per_unit);
1139         ghost->set_colors();
1140         ghosts.push_back (ghost);
1141
1142         return ghost;
1143 }
1144
1145 void
1146 AudioRegionView::entered (bool internal_editing)
1147 {
1148         trackview.editor().set_current_trimmable (_region);
1149         trackview.editor().set_current_movable (_region);
1150         
1151         if (gain_line && trackview.editor().current_mouse_mode() == Editing::MouseGain) {
1152                 gain_line->add_visibility (AutomationLine::ControlPoints);
1153         }
1154
1155         if (fade_in_handle && !internal_editing) {
1156                 fade_in_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 255);
1157                 fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 255);
1158                 fade_out_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 255);
1159                 fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 255);
1160         }
1161 }
1162
1163 void
1164 AudioRegionView::exited ()
1165 {
1166         trackview.editor().set_current_trimmable (boost::shared_ptr<Trimmable>());
1167         trackview.editor().set_current_movable (boost::shared_ptr<Movable>());
1168
1169         if (gain_line && trackview.editor().current_mouse_mode() == Editing::MouseGain) {
1170                 gain_line->remove_visibility (AutomationLine::ControlPoints);
1171         }
1172
1173         if (fade_in_handle) {
1174                 fade_in_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 0);
1175                 fade_in_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 0);
1176                 fade_out_handle->property_outline_color_rgba() = RGBA_TO_UINT (0, 0, 0, 0);
1177                 fade_out_handle->property_fill_color_rgba() = UINT_RGBA_CHANGE_A (fade_color, 0);
1178         }
1179 }
1180
1181 void
1182 AudioRegionView::envelope_active_changed ()
1183 {
1184         if (gain_line) {
1185                 gain_line->set_line_color (audio_region()->envelope_active() ? ARDOUR_UI::config()->canvasvar_GainLine.get() : ARDOUR_UI::config()->canvasvar_GainLineInactive.get());
1186         }
1187 }
1188
1189 void
1190 AudioRegionView::set_waveview_data_src()
1191 {
1192         AudioGhostRegion* agr;
1193         double unit_length= _region->length() / samples_per_unit;
1194
1195         for (uint32_t n = 0; n < waves.size(); ++n) {
1196                 // TODO: something else to let it know the channel
1197                 waves[n]->property_data_src() = _region.get();
1198         }
1199
1200         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1201
1202                 (*i)->set_duration (unit_length);
1203
1204                 if((agr = dynamic_cast<AudioGhostRegion*>(*i)) != 0) {
1205                         for (vector<WaveView*>::iterator w = agr->waves.begin(); w != agr->waves.end(); ++w) {
1206                                 (*w)->property_data_src() = _region.get();
1207                         }
1208                 }
1209         }
1210
1211 }
1212
1213 void
1214 AudioRegionView::color_handler ()
1215 {
1216         //case cMutedWaveForm:
1217         //case cWaveForm:
1218         //case cWaveFormClip:
1219         //case cZeroLine:
1220         set_colors ();
1221
1222         //case cGainLineInactive:
1223         //case cGainLine:
1224         envelope_active_changed();
1225
1226 }
1227
1228 void
1229 AudioRegionView::set_frame_color ()
1230 {
1231         if (!frame) {
1232                 return;
1233         }
1234
1235         if (_region->opaque()) {
1236                 fill_opacity = 130;
1237         } else {
1238                 fill_opacity = 0;
1239         }
1240
1241         TimeAxisViewItem::set_frame_color ();
1242
1243         uint32_t wc;
1244         uint32_t fc;
1245
1246         if (_selected) {
1247                 if (_region->muted()) {
1248                         wc = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_SelectedWaveForm.get(), MUTED_ALPHA);
1249                 } else {
1250                         wc = ARDOUR_UI::config()->canvasvar_SelectedWaveForm.get();
1251                 }
1252                 fc = ARDOUR_UI::config()->canvasvar_SelectedWaveFormFill.get();
1253         } else {
1254                 if (_recregion) {
1255                         if (_region->muted()) {
1256                                 wc = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_RecWaveForm.get(), MUTED_ALPHA);
1257                         } else {
1258                                 wc = ARDOUR_UI::config()->canvasvar_RecWaveForm.get();
1259                         }
1260                         fc = ARDOUR_UI::config()->canvasvar_RecWaveFormFill.get();
1261                 } else {
1262                         if (_region->muted()) {
1263                                 wc = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA);
1264                         } else {
1265                                 wc = ARDOUR_UI::config()->canvasvar_WaveForm.get();
1266                         }
1267                         fc = ARDOUR_UI::config()->canvasvar_WaveFormFill.get();
1268                 }
1269         }
1270
1271         for (vector<ArdourCanvas::WaveView*>::iterator w = waves.begin(); w != waves.end(); ++w) {
1272                 if (_region->muted()) {
1273                         (*w)->property_wave_color() = wc;
1274                 } else {
1275                         (*w)->property_wave_color() = wc;
1276                         (*w)->property_fill_color() = fc;
1277                 }
1278         }
1279 }
1280
1281 void
1282 AudioRegionView::set_fade_visibility (bool yn)
1283 {
1284         if (yn) {
1285                 if (fade_in_shape) {
1286                         fade_in_shape->show();
1287                 }
1288                 if (fade_out_shape) {
1289                         fade_out_shape->show ();
1290                 }
1291                 if (fade_in_handle) {
1292                         fade_in_handle->show ();
1293                 }
1294                 if (fade_out_handle) {
1295                         fade_out_handle->show ();
1296                 }
1297         } else {
1298                 if (fade_in_shape) {
1299                         fade_in_shape->hide();
1300                 }
1301                 if (fade_out_shape) {
1302                         fade_out_shape->hide ();
1303                 }
1304                 if (fade_in_handle) {
1305                         fade_in_handle->hide ();
1306                 }
1307                 if (fade_out_handle) {
1308                         fade_out_handle->hide ();
1309                 }
1310         }
1311 }
1312
1313 void
1314 AudioRegionView::update_coverage_frames (LayerDisplay d)
1315 {
1316         RegionView::update_coverage_frames (d);
1317
1318         if (fade_in_handle) {
1319                 fade_in_handle->raise_to_top ();
1320                 fade_out_handle->raise_to_top ();
1321         }
1322 }
1323
1324 void
1325 AudioRegionView::show_region_editor ()
1326 {
1327         if (editor == 0) {
1328                 editor = new AudioRegionEditor (trackview.session(), audio_region());
1329         }
1330
1331         editor->present ();
1332         editor->set_position (Gtk::WIN_POS_MOUSE);
1333         editor->show_all();
1334 }
1335
1336
1337 void
1338 AudioRegionView::show_fade_line (framepos_t pos)
1339 {
1340         fade_position_line->property_x1() = trackview.editor().frame_to_pixel (pos);
1341         fade_position_line->property_x2() = trackview.editor().frame_to_pixel (pos);
1342         fade_position_line->show ();
1343         fade_position_line->raise_to_top ();
1344 }
1345
1346 void
1347 AudioRegionView::hide_fade_line ()
1348 {
1349         fade_position_line->hide ();
1350 }
1351
1352
1353 void
1354 AudioRegionView::transients_changed ()
1355 {
1356         AnalysisFeatureList analysis_features = _region->transients();
1357
1358         while (feature_lines.size() < analysis_features.size()) {
1359
1360                 ArdourCanvas::Line* canvas_item = new ArdourCanvas::Line(*group);
1361
1362                 ArdourCanvas::Points points;
1363
1364                 points.push_back(Gnome::Art::Point(-1.0, 2.0)); // first x-coord needs to be a non-normal value
1365                 points.push_back(Gnome::Art::Point(1.0, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
1366
1367                 canvas_item->property_points() = points;
1368                 canvas_item->property_width_pixels() = 1;
1369                 canvas_item->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
1370                 canvas_item->property_first_arrowhead() = TRUE;
1371                 canvas_item->property_last_arrowhead() = TRUE;
1372                 canvas_item->property_arrow_shape_a() = 11.0;
1373                 canvas_item->property_arrow_shape_b() = 0.0;
1374                 canvas_item->property_arrow_shape_c() = 4.0;
1375
1376                 canvas_item->raise_to_top ();
1377                 canvas_item->show ();
1378
1379                 canvas_item->set_data ("regionview", this);
1380                 canvas_item->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), canvas_item, this));
1381
1382                 feature_lines.push_back (make_pair(0, canvas_item));
1383         }
1384
1385         while (feature_lines.size() > analysis_features.size()) {
1386                 ArdourCanvas::Line* line = feature_lines.back().second;
1387                 feature_lines.pop_back ();
1388                 delete line;
1389         }
1390
1391         AnalysisFeatureList::const_iterator i;
1392         list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
1393
1394         for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
1395
1396                 ArdourCanvas::Points points;
1397
1398                 float *pos = new float;
1399                 *pos = trackview.editor().frame_to_pixel (*i);
1400
1401                 points.push_back(Gnome::Art::Point(*pos, 2.0)); // first x-coord needs to be a non-normal value
1402                 points.push_back(Gnome::Art::Point(*pos, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
1403
1404                 (*l).second->property_points() = points;
1405                 (*l).second->set_data ("position", pos);
1406
1407                 (*l).first = *i;
1408         }
1409 }
1410
1411 void
1412 AudioRegionView::update_transient(float /*old_pos*/, float new_pos)
1413 {
1414         /* Find frame at old pos, calulate new frame then update region transients*/
1415         list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
1416
1417         for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
1418
1419                 /* Line has been updated in drag so we compare to new_pos */
1420
1421                 float* pos = (float*) (*l).second->get_data ("position");
1422
1423                 if (rint(new_pos) == rint(*pos)) {
1424
1425                     framepos_t old_frame = (*l).first;
1426                     framepos_t new_frame = trackview.editor().pixel_to_frame (new_pos);
1427
1428                     _region->update_transient (old_frame, new_frame);
1429
1430                     break;
1431                 }
1432         }
1433 }
1434
1435 void
1436 AudioRegionView::remove_transient(float pos)
1437 {
1438         /* Find frame at old pos, calulate new frame then update region transients*/
1439         list<std::pair<framepos_t, ArdourCanvas::Line*> >::iterator l;
1440
1441         for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
1442
1443                 /* Line has been updated in drag so we compare to new_pos */
1444                 float *line_pos = (float*) (*l).second->get_data ("position");
1445
1446                 if (rint(pos) == rint(*line_pos)) {
1447                     _region->remove_transient ((*l).first);
1448                     break;
1449                 }
1450         }
1451 }
1452
1453 void
1454 AudioRegionView::thaw_after_trim ()
1455 {
1456         RegionView::thaw_after_trim ();
1457         unhide_envelope ();
1458         drag_end ();
1459 }
1460
1461 void
1462 AudioRegionView::redraw_start_xfade ()
1463 {
1464         boost::shared_ptr<AudioRegion> ar (audio_region());
1465
1466         if (!ar->fade_in() || ar->fade_in()->empty()) {
1467                 return;
1468         }
1469
1470         if (!ar->fade_in_is_xfade()) {
1471                 if (start_xfade_in) {
1472                         start_xfade_in->hide ();
1473                         start_xfade_out->hide ();
1474                         start_xfade_rect->hide ();
1475                         _start_xfade_visible = false;
1476                 }
1477                 return;
1478         }
1479
1480         redraw_start_xfade_to (ar, ar->fade_in()->back()->when);
1481 }
1482
1483 void
1484 AudioRegionView::redraw_start_xfade_to (boost::shared_ptr<AudioRegion> ar, framecnt_t len)
1485 {
1486         int32_t const npoints = trackview.editor().frame_to_pixel (len);
1487
1488         if (npoints < 3) {
1489                 return;
1490         }
1491
1492         if (!start_xfade_in) {
1493                 start_xfade_in = new ArdourCanvas::Line (*group);
1494                 start_xfade_in->property_width_pixels() = 1;
1495                 start_xfade_in->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_GainLine.get();
1496         }
1497
1498         if (!start_xfade_out) {
1499                 start_xfade_out = new ArdourCanvas::Line (*group);
1500                 start_xfade_out->property_width_pixels() = 1;
1501                 uint32_t col = UINT_RGBA_CHANGE_A (ARDOUR_UI::config()->canvasvar_GainLine.get(), 125);
1502                 start_xfade_out->property_fill_color_rgba() = col;
1503         }
1504
1505         if (!start_xfade_rect) {
1506                 start_xfade_rect = new ArdourCanvas::SimpleRect (*group);
1507                 start_xfade_rect->property_draw() = true;
1508                 start_xfade_rect->property_fill() = true;;
1509                 start_xfade_rect->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_ActiveCrossfade.get();
1510                 start_xfade_rect->property_outline_pixels() = 0;
1511                 start_xfade_rect->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_start_xfade_event), start_xfade_rect, this));
1512                 start_xfade_rect->set_data ("regionview", this);
1513         }
1514
1515         Points* points = get_canvas_points ("xfade edit redraw", npoints);
1516         boost::scoped_array<float> vec (new float[npoints]);
1517         double effective_height = _height - NAME_HIGHLIGHT_SIZE - 1.0;
1518
1519         ar->fade_in()->curve().get_vector (0, ar->fade_in()->back()->when, vec.get(), npoints);
1520
1521         for (int i = 0, pci = 0; i < npoints; ++i) {
1522                 Gnome::Art::Point &p ((*points)[pci++]);
1523                 p.set_x (i);
1524                 p.set_y (1.0 + effective_height - (effective_height * vec.get()[i]));
1525         }
1526
1527         start_xfade_rect->property_x1() = ((*points)[0]).get_x();
1528         start_xfade_rect->property_y1() = 1.0;
1529         start_xfade_rect->property_x2() = ((*points)[npoints-1]).get_x();
1530         start_xfade_rect->property_y2() = effective_height;
1531         start_xfade_rect->show ();
1532         start_xfade_rect->raise_to_top ();
1533
1534         start_xfade_in->property_points() = *points;
1535         start_xfade_in->show ();
1536         start_xfade_in->raise_to_top ();
1537
1538         /* fade out line */
1539
1540         boost::shared_ptr<AutomationList> inverse = ar->inverse_fade_in();
1541
1542         if (!inverse) {
1543
1544                 for (int i = 0, pci = 0; i < npoints; ++i) {
1545                         Gnome::Art::Point &p ((*points)[pci++]);
1546                         p.set_x (i);
1547                         p.set_y (1.0 + effective_height - (effective_height * (1.0 - vec.get()[i])));
1548                 }
1549
1550         } else {
1551
1552                 inverse->curve().get_vector (0, inverse->back()->when, vec.get(), npoints);
1553
1554                 for (int i = 0, pci = 0; i < npoints; ++i) {
1555                         Gnome::Art::Point &p ((*points)[pci++]);
1556                         p.set_x (i);
1557                         p.set_y (1.0 + effective_height - (effective_height * vec.get()[i]));
1558                 }
1559         }
1560
1561         start_xfade_out->property_points() = *points;
1562         start_xfade_out->show ();
1563         start_xfade_out->raise_to_top ();
1564
1565         _start_xfade_visible = true;
1566
1567         delete points;
1568 }
1569
1570 void
1571 AudioRegionView::redraw_end_xfade ()
1572 {
1573         boost::shared_ptr<AudioRegion> ar (audio_region());
1574
1575         if (!ar->fade_out() || ar->fade_out()->empty()) {
1576                 return;
1577         }
1578
1579         if (!ar->fade_out_is_xfade()) {
1580                 if (end_xfade_in) {
1581                         end_xfade_in->hide ();
1582                         end_xfade_out->hide ();
1583                         end_xfade_rect->hide ();
1584                         _end_xfade_visible = false;
1585                 }
1586                 return;
1587         }
1588
1589         redraw_end_xfade_to (ar, ar->fade_out()->back()->when);
1590 }
1591
1592 void
1593 AudioRegionView::redraw_end_xfade_to (boost::shared_ptr<AudioRegion> ar, framecnt_t len)
1594 {
1595         int32_t const npoints = trackview.editor().frame_to_pixel (len);
1596
1597         if (npoints < 3) {
1598                 return;
1599         }
1600
1601         if (!end_xfade_in) {
1602                 end_xfade_in = new ArdourCanvas::Line (*group);
1603                 end_xfade_in->property_width_pixels() = 1;
1604                 end_xfade_in->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_GainLine.get();
1605         }
1606
1607         if (!end_xfade_out) {
1608                 end_xfade_out = new ArdourCanvas::Line (*group);
1609                 end_xfade_out->property_width_pixels() = 1;
1610                 uint32_t col UINT_RGBA_CHANGE_A (ARDOUR_UI::config()->canvasvar_GainLine.get(), 125);
1611                 end_xfade_out->property_fill_color_rgba() = col;
1612         }
1613
1614         if (!end_xfade_rect) {
1615                 end_xfade_rect = new ArdourCanvas::SimpleRect (*group);
1616                 end_xfade_rect->property_draw() = true;
1617                 end_xfade_rect->property_fill() = true;;
1618                 end_xfade_rect->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_ActiveCrossfade.get();
1619                 end_xfade_rect->property_outline_pixels() = 0;
1620                 end_xfade_rect->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_end_xfade_event), end_xfade_rect, this));
1621                 end_xfade_rect->set_data ("regionview", this);
1622         }
1623
1624         Points* points = get_canvas_points ("xfade edit redraw", npoints);
1625         boost::scoped_ptr<float> vec (new float[npoints]);
1626
1627         ar->fade_out()->curve().get_vector (0, ar->fade_out()->back()->when, vec.get(), npoints);
1628
1629         double rend = trackview.editor().frame_to_pixel (_region->length() - len);
1630         double effective_height = _height - NAME_HIGHLIGHT_SIZE - 1;
1631
1632         for (int i = 0, pci = 0; i < npoints; ++i) {
1633                 Gnome::Art::Point &p ((*points)[pci++]);
1634                 p.set_x (rend + i);
1635                 p.set_y (1.0 + effective_height - (effective_height * vec.get()[i]));
1636         }
1637
1638         end_xfade_rect->property_x1() = ((*points)[0]).get_x();
1639         end_xfade_rect->property_y1() = 1;
1640         end_xfade_rect->property_x2() = ((*points)[npoints-1]).get_x();
1641         end_xfade_rect->property_y2() = effective_height;
1642         end_xfade_rect->show ();
1643         end_xfade_rect->raise_to_top ();
1644
1645         end_xfade_in->property_points() = *points;
1646         end_xfade_in->show ();
1647         end_xfade_in->raise_to_top ();
1648
1649         /* fade in line */
1650
1651         boost::shared_ptr<AutomationList> inverse = ar->inverse_fade_out ();
1652
1653         if (!inverse) {
1654
1655                 for (int i = 0, pci = 0; i < npoints; ++i) {
1656                         Gnome::Art::Point &p ((*points)[pci++]);
1657                         p.set_x (rend + i);
1658                         p.set_y (1.0 + effective_height - (effective_height * (1.0 - vec.get()[i])));
1659                 }
1660
1661         } else {
1662
1663                 inverse->curve().get_vector (inverse->front()->when, inverse->back()->when, vec.get(), npoints);
1664
1665                 for (int i = 0, pci = 0; i < npoints; ++i) {
1666                         Gnome::Art::Point &p ((*points)[pci++]);
1667                         p.set_x (rend + i);
1668                         p.set_y (1.0 + effective_height - (effective_height * vec.get()[i]));
1669                 }
1670         }
1671
1672         end_xfade_out->property_points() = *points;
1673         end_xfade_out->show ();
1674         end_xfade_out->raise_to_top ();
1675
1676         _end_xfade_visible = true;
1677
1678         delete points;
1679 }
1680
1681 void
1682 AudioRegionView::hide_xfades ()
1683 {
1684         hide_start_xfade ();
1685         hide_end_xfade ();
1686 }
1687
1688 void
1689 AudioRegionView::hide_start_xfade ()
1690 {
1691         if (start_xfade_in) {
1692                 start_xfade_in->hide();
1693         }
1694         if (start_xfade_out) {
1695                 start_xfade_out->hide();
1696         }
1697         if (start_xfade_rect) {
1698                 start_xfade_rect->hide ();
1699         }
1700
1701         _start_xfade_visible = false;
1702 }
1703
1704 void
1705 AudioRegionView::hide_end_xfade ()
1706 {
1707         if (end_xfade_in) {
1708                 end_xfade_in->hide();
1709         }
1710         if (end_xfade_out) {
1711                 end_xfade_out->hide();
1712         }
1713         if (end_xfade_rect) {
1714                 end_xfade_rect->hide ();
1715         }
1716
1717         _end_xfade_visible = false;
1718 }
1719
1720 void
1721 AudioRegionView::show_start_xfade ()
1722 {
1723         if (start_xfade_in) {
1724                 start_xfade_in->show();
1725         }
1726         if (start_xfade_out) {
1727                 start_xfade_out->show();
1728         }
1729         if (start_xfade_rect) {
1730                 start_xfade_rect->show ();
1731         }
1732
1733         _start_xfade_visible = true;
1734 }
1735
1736 void
1737 AudioRegionView::show_end_xfade ()
1738 {
1739         if (end_xfade_in) {
1740                 end_xfade_in->show();
1741         }
1742         if (end_xfade_out) {
1743                 end_xfade_out->show();
1744         }
1745         if (end_xfade_rect) {
1746                 end_xfade_rect->show ();
1747         }
1748
1749         _end_xfade_visible = true;
1750 }
1751
1752 void
1753 AudioRegionView::show_xfades ()
1754 {
1755         show_start_xfade ();
1756         show_end_xfade ();
1757 }
1758
1759 void
1760 AudioRegionView::drag_start ()
1761 {
1762         TimeAxisViewItem::drag_start ();
1763         AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&trackview);
1764
1765         if (atav) {
1766                 AudioStreamView* av = atav->audio_view();
1767                 if (av) {
1768                         /* this will hide our xfades too */
1769                         _hidden_xfades = av->hide_xfades_with (audio_region());
1770                 }
1771         }
1772 }
1773
1774 void
1775 AudioRegionView::drag_end ()
1776 {
1777         TimeAxisViewItem::drag_end ();
1778
1779         for (list<AudioRegionView*>::iterator i = _hidden_xfades.first.begin(); i != _hidden_xfades.first.end(); ++i) {
1780                 (*i)->show_start_xfade ();
1781         }
1782
1783         for (list<AudioRegionView*>::iterator i = _hidden_xfades.second.begin(); i != _hidden_xfades.second.end(); ++i) {
1784                 (*i)->show_end_xfade ();
1785         }
1786         
1787         _hidden_xfades.first.clear ();
1788         _hidden_xfades.second.clear ();
1789 }
1790
1791 void
1792 AudioRegionView::parameter_changed (string const & p)
1793 {
1794         if (p == "show-waveforms") {
1795                 setup_waveform_visibility ();
1796         } else if (p == "waveform-scale") {
1797                 setup_waveform_scale ();
1798         } else if (p == "waveform-shape") {
1799                 setup_waveform_shape ();
1800         }
1801 }