beat slicing patch #1 from lincoln spiteri
[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 <gtkmm.h>
24
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include "ardour/playlist.h"
28 #include "ardour/audioregion.h"
29 #include "ardour/audiosource.h"
30 #include "ardour/profile.h"
31 #include "ardour/session.h"
32
33 #include "pbd/memento_command.h"
34 #include "pbd/stacktrace.h"
35
36 #include "evoral/Curve.hpp"
37
38 #include "streamview.h"
39 #include "audio_region_view.h"
40 #include "audio_time_axis.h"
41 #include "simplerect.h"
42 #include "simpleline.h"
43 #include "waveview.h"
44 #include "public_editor.h"
45 #include "audio_region_editor.h"
46 #include "region_gain_line.h"
47 #include "control_point.h"
48 #include "ghostregion.h"
49 #include "audio_time_axis.h"
50 #include "utils.h"
51 #include "rgb_macros.h"
52 #include "gui_thread.h"
53 #include "ardour_ui.h"
54
55 #include "i18n.h"
56
57 #define MUTED_ALPHA 10
58
59 using namespace std;
60 using namespace ARDOUR;
61 using namespace PBD;
62 using namespace Editing;
63 using namespace ArdourCanvas;
64
65 static const int32_t sync_mark_width = 9;
66
67 AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu,
68                                   Gdk::Color const & basic_color)
69         : RegionView (parent, tv, r, spu, basic_color)
70         , sync_mark(0)
71         , zero_line(0)
72         , fade_in_shape(0)
73         , fade_out_shape(0)
74         , fade_in_handle(0)
75         , fade_out_handle(0)
76         , gain_line(0)
77         , _amplitude_above_axis(1.0)
78         , _flags(0)
79         , fade_color(0)
80 {
81 }
82
83
84 AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu,
85                                   Gdk::Color const & basic_color, bool recording, TimeAxisViewItem::Visibility visibility)
86         : RegionView (parent, tv, r, spu, basic_color, recording, visibility)
87         , sync_mark(0)
88         , zero_line(0)
89         , fade_in_shape(0)
90         , fade_out_shape(0)
91         , fade_in_handle(0)
92         , fade_out_handle(0)
93         , gain_line(0)
94         , _amplitude_above_axis(1.0)
95         , _flags(0)
96         , fade_color(0)
97 {
98 }
99
100
101 AudioRegionView::AudioRegionView (const AudioRegionView& other)
102         : sigc::trackable(other)
103         , RegionView (other)
104         , zero_line(0)
105         , fade_in_shape(0)
106         , fade_out_shape(0)
107         , fade_in_handle(0)
108         , fade_out_handle(0)
109         , gain_line(0)
110         , _amplitude_above_axis(1.0)
111         , _flags(0)
112         , fade_color(0)
113 {
114         Gdk::Color c;
115         int r,g,b,a;
116
117         UINT_TO_RGBA (other.fill_color, &r, &g, &b, &a);
118         c.set_rgb_p (r/255.0, g/255.0, b/255.0);
119
120         init (c, false);
121 }
122
123 AudioRegionView::AudioRegionView (const AudioRegionView& other, boost::shared_ptr<AudioRegion> other_region)
124         : RegionView (other, boost::shared_ptr<Region> (other_region))
125         , zero_line(0)
126         , fade_in_shape(0)
127         , fade_out_shape(0)
128         , fade_in_handle(0)
129         , fade_out_handle(0)
130         , gain_line(0)
131         , _amplitude_above_axis(1.0)
132         , _flags(0)
133         , fade_color(0)
134 {
135         Gdk::Color c;
136         int r,g,b,a;
137
138         UINT_TO_RGBA (other.fill_color, &r, &g, &b, &a);
139         c.set_rgb_p (r/255.0, g/255.0, b/255.0);
140
141         init (c, true);
142 }
143
144 void
145 AudioRegionView::init (Gdk::Color const & basic_color, bool wfd)
146 {
147         // FIXME: Some redundancy here with RegionView::init.  Need to figure out
148         // where order is important and where it isn't...
149
150         RegionView::init (basic_color, wfd);
151
152         XMLNode *node;
153
154         _amplitude_above_axis = 1.0;
155         zero_line             = 0;
156         _flags                = 0;
157
158         if ((node = _region->extra_xml ("GUI")) != 0) {
159                 set_flags (node);
160         } else {
161                 _flags = WaveformVisible;
162                 store_flags ();
163         }
164
165         /* make envelope visible if it has anything interesting in it */
166         if (audio_region()->envelope()->size() > 2) {
167                 _flags |= EnvelopeVisible;
168         }
169
170         compute_colors (basic_color);
171
172         create_waves ();
173
174         fade_in_shape = new ArdourCanvas::Polygon (*group);
175         fade_in_shape->property_fill_color_rgba() = fade_color;
176         fade_in_shape->set_data ("regionview", this);
177
178         fade_out_shape = new ArdourCanvas::Polygon (*group);
179         fade_out_shape->property_fill_color_rgba() = fade_color;
180         fade_out_shape->set_data ("regionview", this);
181
182         {
183                 uint32_t r,g,b,a;
184                 UINT_TO_RGBA(fill_color,&r,&g,&b,&a);
185
186                 fade_in_handle = new ArdourCanvas::SimpleRect (*group);
187                 fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0);
188                 fade_in_handle->property_outline_pixels() = 0;
189
190                 fade_in_handle->set_data ("regionview", this);
191
192                 fade_out_handle = new ArdourCanvas::SimpleRect (*group);
193                 fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0);
194                 fade_out_handle->property_outline_pixels() = 0;
195
196                 fade_out_handle->set_data ("regionview", this);
197         }
198
199         setup_fade_handle_positions ();
200
201         if (!trackview.session()->config.get_show_region_fades()) {
202                 set_fade_visibility (false);
203         }
204
205         const string line_name = _region->name() + ":gain";
206
207         if (!Profile->get_sae()) {
208                 gain_line = new AudioRegionGainLine (line_name, *this, *group, audio_region()->envelope());
209         }
210
211         if (!(_flags & EnvelopeVisible)) {
212                 gain_line->hide ();
213         } else {
214                 gain_line->show ();
215         }
216
217         gain_line->reset ();
218
219         set_height (trackview.current_height());
220
221         region_muted ();
222         region_sync_changed ();
223
224         region_resized (ARDOUR::bounds_change);
225         set_waveview_data_src();
226         region_locked ();
227         envelope_active_changed ();
228         fade_in_active_changed ();
229         fade_out_active_changed ();
230
231         reset_width_dependent_items (_pixel_width);
232
233         fade_in_shape->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_event), fade_in_shape, this));
234         fade_in_handle->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this));
235         fade_out_shape->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_event), fade_out_shape, this));
236         fade_out_handle->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this));
237
238         set_colors ();
239
240         /* XXX sync mark drag? */
241 }
242
243 AudioRegionView::~AudioRegionView ()
244 {
245         in_destructor = true;
246
247         RegionViewGoingAway (this); /* EMIT_SIGNAL */
248
249         for (vector<GnomeCanvasWaveViewCache *>::iterator cache = wave_caches.begin(); cache != wave_caches.end() ; ++cache) {
250                 gnome_canvas_waveview_cache_destroy (*cache);
251         }
252
253         for (vector<ScopedConnection*>::iterator i = _data_ready_connections.begin(); i != _data_ready_connections.end(); ++i) {
254                 delete *i;
255         }
256
257         for (list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::iterator i = feature_lines.begin(); i != feature_lines.end(); ++i) {
258                 delete ((*i).second);
259         }
260         
261         /* all waveviews etc will be destroyed when the group is destroyed */
262
263         delete gain_line;
264 }
265
266 boost::shared_ptr<ARDOUR::AudioRegion>
267 AudioRegionView::audio_region() const
268 {
269         // "Guaranteed" to succeed...
270         return boost::dynamic_pointer_cast<AudioRegion>(_region);
271 }
272
273 void
274 AudioRegionView::region_changed (const PropertyChange& what_changed)
275 {
276         ENSURE_GUI_THREAD (*this, &AudioRegionView::region_changed, what_changed);
277         // cerr << "AudioRegionView::region_changed() called" << endl;
278
279         RegionView::region_changed (what_changed);
280
281         if (what_changed.contains (ARDOUR::Properties::scale_amplitude)) {
282                 region_scale_amplitude_changed ();
283         }
284         if (what_changed.contains (ARDOUR::Properties::fade_in)) {
285                 fade_in_changed ();
286         }
287         if (what_changed.contains (ARDOUR::Properties::fade_out)) {
288                 fade_out_changed ();
289         }
290         if (what_changed.contains (ARDOUR::Properties::fade_in_active)) {
291                 fade_in_active_changed ();
292         }
293         if (what_changed.contains (ARDOUR::Properties::fade_out_active)) {
294                 fade_out_active_changed ();
295         }
296         if (what_changed.contains (ARDOUR::Properties::envelope_active)) {
297                 envelope_active_changed ();
298         }
299         if (what_changed.contains (ARDOUR::Properties::valid_transients)) {
300                 transients_changed ();
301         }
302 }
303
304 void
305 AudioRegionView::fade_in_changed ()
306 {
307         reset_fade_in_shape ();
308 }
309
310 void
311 AudioRegionView::fade_out_changed ()
312 {
313         reset_fade_out_shape ();
314 }
315 void
316 AudioRegionView::fade_in_active_changed ()
317 {
318 //      uint32_t r,g,b,a;
319 //      uint32_t col;
320 //      UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
321
322         if (audio_region()->fade_in_active()) {
323                 fade_in_shape->property_fill_color_rgba() = RGBA_TO_UINT(45,45,45,90);                          // FIXME make a themeable colour
324                 fade_in_shape->property_width_pixels() = 1;
325                 fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(180,180,180,190);                   // FIXME make a themeable colour
326         } else {
327                 fade_in_shape->property_fill_color_rgba() = RGBA_TO_UINT(45,45,45,20);                          // FIXME make a themeable colour
328                 fade_in_shape->property_width_pixels() = 1;
329                 fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(45,45,45,150);                      // FIXME make a themeable colour
330         }
331 }
332
333 void
334 AudioRegionView::fade_out_active_changed ()
335 {
336 //      uint32_t r,g,b,a;
337 //      uint32_t col;
338 //      UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
339
340         if (audio_region()->fade_out_active()) {
341                 fade_out_shape->property_fill_color_rgba() = RGBA_TO_UINT(45,45,45,90);                         // FIXME make a themeable colour
342                 fade_out_shape->property_width_pixels() = 1;
343                 fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(180,180,180,200);                  // FIXME make a themeable colour
344         } else {
345                 fade_out_shape->property_fill_color_rgba() = RGBA_TO_UINT(45,45,45,20);                         // FIXME make a themeable colour
346                 fade_out_shape->property_width_pixels() = 1;
347                 fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(45,45,45,200);                     // FIXME make a themeable colour
348         }
349 }
350
351
352 void
353 AudioRegionView::region_scale_amplitude_changed ()
354 {
355         ENSURE_GUI_THREAD (*this, &AudioRegionView::region_scale_amplitude_changed)
356
357         for (uint32_t n = 0; n < waves.size(); ++n) {
358                 // force a reload of the cache
359                 waves[n]->property_data_src() = _region.get();
360         }
361 }
362
363 void
364 AudioRegionView::region_renamed ()
365 {
366         Glib::ustring str = RegionView::make_name ();
367
368         if (audio_region()->speed_mismatch (trackview.session()->frame_rate())) {
369                 str = string ("*") + str;
370         }
371
372         if (_region->muted()) {
373                 str = string ("!") + str;
374         }
375
376         set_item_name (str, this);
377         set_name_text (str);
378 }
379
380 void
381 AudioRegionView::region_resized (const PropertyChange& what_changed)
382 {
383         AudioGhostRegion* agr;
384
385         RegionView::region_resized(what_changed);
386         PropertyChange interesting_stuff;
387
388         interesting_stuff.add (ARDOUR::Properties::start);
389         interesting_stuff.add (ARDOUR::Properties::length);
390
391         if (what_changed.contains (interesting_stuff)) {
392
393                 for (uint32_t n = 0; n < waves.size(); ++n) {
394                         waves[n]->property_region_start() = _region->start();
395                 }
396
397                 for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
398                         if ((agr = dynamic_cast<AudioGhostRegion*>(*i)) != 0) {
399
400                                 for (vector<WaveView*>::iterator w = agr->waves.begin(); w != agr->waves.end(); ++w) {
401                                         (*w)->property_region_start() = _region->start();
402                                 }
403                         }
404                 }
405                 
406                 /* hide transient lines that extend beyond the region end */
407                 
408                 list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::iterator l;
409                 
410                 for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
411                         if ((*l).first > _region->length()- 1){
412                           (*l).second->hide();
413                         }
414                         else {
415                           (*l).second->show();
416                         }
417                 }
418         }
419 }
420
421 void
422 AudioRegionView::reset_width_dependent_items (double pixel_width)
423 {
424         RegionView::reset_width_dependent_items(pixel_width);
425         assert(_pixel_width == pixel_width);
426
427         if (zero_line) {
428                 zero_line->property_x2() = pixel_width - 1.0;
429         }
430
431         if (fade_in_handle) {
432                 if (pixel_width <= 6.0) {
433                         fade_in_handle->hide();
434                         fade_out_handle->hide();
435                 } else {
436                         if (_height < 5.0) {
437                                 fade_in_handle->hide();
438                                 fade_out_handle->hide();
439                         } else {
440                                 if (trackview.session()->config.get_show_region_fades()) {
441                                         fade_in_handle->show();
442                                         fade_out_handle->show();
443                                 }
444                         }
445                 }
446         }
447
448         AnalysisFeatureList analysis_features = _region->transients();
449         AnalysisFeatureList::const_iterator i;
450         list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::iterator l;
451
452         for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
453                 (*l).second->property_x1() = trackview.editor().frame_to_pixel (*i);
454                 (*l).second->property_x2() = trackview.editor().frame_to_pixel (*i);
455         }
456         
457         reset_fade_shapes ();
458 }
459
460 void
461 AudioRegionView::region_muted ()
462 {
463         RegionView::region_muted();
464
465         for (uint32_t n=0; n < waves.size(); ++n) {
466                 if (_region->muted()) {
467                         waves[n]->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA);
468                 } else {
469                         waves[n]->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm.get();
470                 }
471         }
472 }
473
474 void
475 AudioRegionView::setup_fade_handle_positions()
476 {
477         /* position of fade handle offset from the top of the region view */
478         double const handle_pos = 2;
479         /* height of fade handles */
480         double const handle_height = 5;
481
482         if (fade_in_handle) {
483                 fade_in_handle->property_y1() = handle_pos;
484                 fade_in_handle->property_y2() = handle_pos + handle_height;
485         }
486
487         if (fade_out_handle) {
488                 fade_out_handle->property_y1() = handle_pos;
489                 fade_out_handle->property_y2() = handle_pos + handle_height;
490         }
491 }
492
493 void
494 AudioRegionView::set_height (gdouble height)
495 {
496         RegionView::set_height (height);
497
498         uint32_t wcnt = waves.size();
499
500         // FIXME: ick
501         height -= 2;
502
503         for (uint32_t n = 0; n < wcnt; ++n) {
504                 gdouble ht;
505
506                 if ((height) < NAME_HIGHLIGHT_THRESH) {
507                         ht = ((height - 2 * wcnt) / (double) wcnt);
508                 } else {
509                         ht = (((height - 2 * wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt);
510                 }
511
512                 gdouble yoff = n * (ht + 1);
513
514                 waves[n]->property_height() = ht;
515                 waves[n]->property_y() = yoff + 2;
516         }
517
518         if (gain_line) {
519
520                 if ((height/wcnt) < NAME_HIGHLIGHT_THRESH) {
521                         gain_line->hide ();
522                 } else {
523                         if (_flags & EnvelopeVisible) {
524                                 gain_line->show ();
525                         }
526                 }
527
528                 gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE) - 2);
529         }
530
531         manage_zero_line ();
532         reset_fade_shapes ();
533         
534         /* Update hights for any active feature lines */
535         list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::iterator l;
536
537         for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
538                 (*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1;
539         }       
540
541         if (name_pixbuf) {
542                 name_pixbuf->raise_to_top();
543         }
544 }
545
546 void
547 AudioRegionView::manage_zero_line ()
548 {
549         if (!zero_line) {
550                 return;
551         }
552
553         if (_height >= 100) {
554                 double const wave_midpoint = (_height - NAME_HIGHLIGHT_SIZE) / 2.0;
555                 zero_line->property_y1() = wave_midpoint;
556                 zero_line->property_y2() = wave_midpoint;
557                 zero_line->show();
558         } else {
559                 zero_line->hide();
560         }
561 }
562
563 void
564 AudioRegionView::reset_fade_shapes ()
565 {
566         reset_fade_in_shape ();
567         reset_fade_out_shape ();
568 }
569
570 void
571 AudioRegionView::reset_fade_in_shape ()
572 {
573         reset_fade_in_shape_width ((nframes_t) audio_region()->fade_in()->back()->when);
574 }
575
576 void
577 AudioRegionView::reset_fade_in_shape_width (nframes_t width)
578 {
579         if (fade_in_handle == 0) {
580                 return;
581         }
582
583         /* smallest size for a fade is 64 frames */
584
585         width = std::max ((nframes_t) 64, width);
586
587         Points* points;
588         double pwidth = width / samples_per_unit;
589         uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth);
590         double h;
591
592         if (_height < 5) {
593                 fade_in_shape->hide();
594                 fade_in_handle->hide();
595                 return;
596         }
597
598         double handle_center;
599         handle_center = pwidth;
600
601         if (handle_center > 7.0) {
602                 handle_center -= 3.0;
603         } else {
604                 handle_center = 3.0;
605         }
606
607         fade_in_handle->property_x1() =  handle_center - 3.0;
608         fade_in_handle->property_x2() =  handle_center + 3.0;
609
610         if (pwidth < 5) {
611                 fade_in_shape->hide();
612                 return;
613         }
614
615         if (trackview.session()->config.get_show_region_fades()) {
616                 fade_in_shape->show();
617         }
618
619         float curve[npoints];
620         audio_region()->fade_in()->curve().get_vector (0, audio_region()->fade_in()->back()->when, curve, npoints);
621
622         points = get_canvas_points ("fade in shape", npoints + 3);
623
624         if (_height >= NAME_HIGHLIGHT_THRESH) {
625                 h = _height - NAME_HIGHLIGHT_SIZE;
626         } else {
627                 h = _height;
628         }
629
630         /* points *MUST* be in anti-clockwise order */
631
632         uint32_t pi, pc;
633         double xdelta = pwidth/npoints;
634
635         for (pi = 0, pc = 0; pc < npoints; ++pc) {
636                 (*points)[pi].set_x(1 + (pc * xdelta));
637                 (*points)[pi++].set_y(2 + (h - (curve[pc] * h)));
638         }
639
640         /* fold back */
641
642         (*points)[pi].set_x(pwidth);
643         (*points)[pi++].set_y(2);
644
645         (*points)[pi].set_x(1);
646         (*points)[pi++].set_y(2);
647
648         /* connect the dots ... */
649
650         (*points)[pi] = (*points)[0];
651
652         fade_in_shape->property_points() = *points;
653         delete points;
654
655         /* ensure trim handle stays on top */
656         frame_handle_start->raise_to_top();
657 }
658
659 void
660 AudioRegionView::reset_fade_out_shape ()
661 {
662         reset_fade_out_shape_width ((nframes_t) audio_region()->fade_out()->back()->when);
663 }
664
665 void
666 AudioRegionView::reset_fade_out_shape_width (nframes_t width)
667 {
668         if (fade_out_handle == 0) {
669                 return;
670         }
671
672         /* smallest size for a fade is 64 frames */
673
674         width = std::max ((nframes_t) 64, width);
675
676         Points* points;
677         double pwidth = width / samples_per_unit;
678         uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth);
679         double h;
680
681         if (_height < 5) {
682                 fade_out_shape->hide();
683                 fade_out_handle->hide();
684                 return;
685         }
686
687         double handle_center;
688         handle_center = (_region->length() - width) / samples_per_unit;
689
690         if (handle_center > 7.0) {
691                 handle_center -= 3.0;
692         } else {
693                 handle_center = 3.0;
694         }
695
696         fade_out_handle->property_x1() =  handle_center - 3.0;
697         fade_out_handle->property_x2() =  handle_center + 3.0;
698
699         /* don't show shape if its too small */
700
701         if (pwidth < 5) {
702                 fade_out_shape->hide();
703                 return;
704         }
705
706         if (trackview.session()->config.get_show_region_fades()) {
707                 fade_out_shape->show();
708         }
709
710         float curve[npoints];
711         audio_region()->fade_out()->curve().get_vector (0, audio_region()->fade_out()->back()->when, curve, npoints);
712
713         if (_height >= NAME_HIGHLIGHT_THRESH) {
714                 h = _height - NAME_HIGHLIGHT_SIZE;
715         } else {
716                 h = _height;
717         }
718
719         /* points *MUST* be in anti-clockwise order */
720
721         points = get_canvas_points ("fade out shape", npoints + 3);
722
723         uint32_t pi, pc;
724         double xdelta = pwidth/npoints;
725
726         for (pi = 0, pc = 0; pc < npoints; ++pc) {
727                 (*points)[pi].set_x(_pixel_width - 1 - pwidth + (pc*xdelta));
728                 (*points)[pi++].set_y(2 + (h - (curve[pc] * h)));
729         }
730
731         /* fold back */
732
733         (*points)[pi].set_x(_pixel_width);
734         (*points)[pi++].set_y(h);
735
736         (*points)[pi].set_x(_pixel_width);
737         (*points)[pi++].set_y(2);
738
739         /* connect the dots ... */
740
741         (*points)[pi] = (*points)[0];
742
743         fade_out_shape->property_points() = *points;
744         delete points;
745
746         /* ensure trim handle stays on top */
747         frame_handle_end->raise_to_top();
748 }
749
750 void
751 AudioRegionView::set_samples_per_unit (gdouble spu)
752 {
753         RegionView::set_samples_per_unit (spu);
754
755         if (_flags & WaveformVisible) {
756                 for (uint32_t n=0; n < waves.size(); ++n) {
757                         waves[n]->property_samples_per_unit() = spu;
758                 }
759         }
760
761         if (gain_line) {
762                 gain_line->reset ();
763         }
764
765         reset_fade_shapes ();
766 }
767
768 void
769 AudioRegionView::set_amplitude_above_axis (gdouble spp)
770 {
771         for (uint32_t n=0; n < waves.size(); ++n) {
772                 waves[n]->property_amplitude_above_axis() = spp;
773         }
774 }
775
776 void
777 AudioRegionView::compute_colors (Gdk::Color const & basic_color)
778 {
779         RegionView::compute_colors (basic_color);
780
781         uint32_t r, g, b, a;
782
783         /* gain color computed in envelope_active_changed() */
784
785         UINT_TO_RGBA (fill_color, &r, &g, &b, &a);
786         fade_color = RGBA_TO_UINT(r,g,b,120);
787 }
788
789 void
790 AudioRegionView::set_colors ()
791 {
792         RegionView::set_colors();
793
794         if (gain_line) {
795                 gain_line->set_line_color (audio_region()->envelope_active() ? ARDOUR_UI::config()->canvasvar_GainLine.get() : ARDOUR_UI::config()->canvasvar_GainLineInactive.get());
796         }
797
798         for (uint32_t n=0; n < waves.size(); ++n) {
799                 if (_region->muted()) {
800                         waves[n]->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA);
801                 } else {
802                         waves[n]->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm.get();
803                 }
804
805                 waves[n]->property_clip_color() = ARDOUR_UI::config()->canvasvar_WaveFormClip.get();
806                 waves[n]->property_zero_color() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
807         }
808 }
809
810 void
811 AudioRegionView::set_waveform_visible (bool yn)
812 {
813         if (((_flags & WaveformVisible) != yn)) {
814                 if (yn) {
815                         for (uint32_t n=0; n < waves.size(); ++n) {
816                                 /* make sure the zoom level is correct, since we don't update
817                                    this when waveforms are hidden.
818                                 */
819                                 waves[n]->property_samples_per_unit() = samples_per_unit;
820                                 waves[n]->show();
821                         }
822                         _flags |= WaveformVisible;
823                 } else {
824                         for (uint32_t n=0; n < waves.size(); ++n) {
825                                 waves[n]->hide();
826                         }
827                         _flags &= ~WaveformVisible;
828                 }
829                 store_flags ();
830         }
831 }
832
833 void
834 AudioRegionView::temporarily_hide_envelope ()
835 {
836         if (gain_line) {
837                 gain_line->hide ();
838         }
839 }
840
841 void
842 AudioRegionView::unhide_envelope ()
843 {
844         if (gain_line && (_flags & EnvelopeVisible)) {
845                 gain_line->show ();
846         }
847 }
848
849 void
850 AudioRegionView::set_envelope_visible (bool yn)
851 {
852         if (gain_line && ((_flags & EnvelopeVisible) != yn)) {
853                 if (yn) {
854                         gain_line->show ();
855                         _flags |= EnvelopeVisible;
856                 } else {
857                         gain_line->hide ();
858                         _flags &= ~EnvelopeVisible;
859                 }
860                 store_flags ();
861         }
862 }
863
864 void
865 AudioRegionView::create_waves ()
866 {
867         // cerr << "AudioRegionView::create_waves() called on " << this << endl;//DEBUG
868         RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
869
870         if (!atv.track()) {
871                 return;
872         }
873
874         ChanCount nchans = atv.track()->n_channels();
875
876         // cerr << "creating waves for " << _region->name() << " with wfd = " << wait_for_data
877         //              << " and channels = " << nchans.n_audio() << endl;
878
879         /* in tmp_waves, set up null pointers for each channel so the vector is allocated */
880         for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
881                 tmp_waves.push_back (0);
882         }
883
884         for (vector<ScopedConnection*>::iterator i = _data_ready_connections.begin(); i != _data_ready_connections.end(); ++i) {
885                 delete *i;
886         }
887
888         _data_ready_connections.clear ();
889
890         for (uint32_t i = 0; i < nchans.n_audio(); ++i) {
891                 _data_ready_connections.push_back (0);
892         }
893
894         for (uint32_t n = 0; n < nchans.n_audio(); ++n) {
895
896                 if (n >= audio_region()->n_channels()) {
897                         break;
898                 }
899
900                 wave_caches.push_back (WaveView::create_cache ());
901
902                 // cerr << "\tchannel " << n << endl;
903
904                 if (wait_for_data) {
905                         if (audio_region()->audio_source(n)->peaks_ready (boost::bind (&AudioRegionView::peaks_ready_handler, this, n), &_data_ready_connections[n], gui_context())) {
906                                 // cerr << "\tData is ready\n";
907                                 create_one_wave (n, true);
908                         } else {
909                                 // cerr << "\tdata is not ready\n";
910                                 // we'll get a PeaksReady signal from the source in the future
911                                 // and will call create_one_wave(n) then.
912                         }
913
914                 } else {
915                         // cerr << "\tdon't delay, display today!\n";
916                         create_one_wave (n, true);
917                 }
918
919         }
920 }
921
922 void
923 AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/)
924 {
925         //cerr << "AudioRegionView::create_one_wave() called which: " << which << " this: " << this << endl;//DEBUG
926         RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
927         uint32_t nchans = atv.track()->n_channels().n_audio();
928         uint32_t n;
929         uint32_t nwaves = std::min (nchans, audio_region()->n_channels());
930         gdouble ht;
931
932         if (trackview.current_height() < NAME_HIGHLIGHT_THRESH) {
933                 ht = ((trackview.current_height()) / (double) nchans);
934         } else {
935                 ht = ((trackview.current_height() - NAME_HIGHLIGHT_SIZE) / (double) nchans);
936         }
937
938         gdouble yoff = which * ht;
939
940         WaveView *wave = new WaveView(*group);
941
942         wave->property_data_src() = (gpointer) _region.get();
943         wave->property_cache() =  wave_caches[which];
944         wave->property_cache_updater() = true;
945         wave->property_channel() =  which;
946         wave->property_length_function() = (gpointer) region_length_from_c;
947         wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c;
948         wave->property_peak_function() =  (gpointer) region_read_peaks_from_c;
949         wave->property_x() =  0.0;
950         wave->property_y() =  yoff;
951         wave->property_height() =  (double) ht;
952         wave->property_samples_per_unit() =  samples_per_unit;
953         wave->property_amplitude_above_axis() =  _amplitude_above_axis;
954
955         if (_recregion) {
956                 wave->property_wave_color() = _region->muted() ? UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_RecWaveForm.get(), MUTED_ALPHA) : ARDOUR_UI::config()->canvasvar_RecWaveForm.get();
957                 wave->property_fill_color() = ARDOUR_UI::config()->canvasvar_RecWaveFormFill.get();
958         } else {
959                 wave->property_wave_color() = _region->muted() ? UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA) : ARDOUR_UI::config()->canvasvar_WaveForm.get();
960                 wave->property_fill_color() = ARDOUR_UI::config()->canvasvar_WaveFormFill.get();
961         }
962
963         wave->property_clip_color() = ARDOUR_UI::config()->canvasvar_WaveFormClip.get();
964         wave->property_zero_color() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
965         wave->property_region_start() = _region->start();
966         wave->property_rectified() = (bool) (_flags & WaveformRectified);
967         wave->property_logscaled() = (bool) (_flags & WaveformLogScaled);
968
969         if (!(_flags & WaveformVisible)) {
970                 wave->hide();
971         }
972
973         /* note: calling this function is serialized by the lock
974            held in the peak building thread that signals that
975            peaks are ready for use *or* by the fact that it is
976            called one by one from the GUI thread.
977         */
978
979         if (which < nchans) {
980                 tmp_waves[which] = wave;
981         } else {
982                 /* n-channel track, >n-channel source */
983         }
984
985         /* see if we're all ready */
986
987         for (n = 0; n < nchans; ++n) {
988                 if (tmp_waves[n] == 0) {
989                         break;
990                 }
991         }
992
993         if (n == nwaves && waves.empty()) {
994                 /* all waves are ready */
995                 tmp_waves.resize(nwaves);
996
997                 waves = tmp_waves;
998                 tmp_waves.clear ();
999
1000                 /* all waves created, don't hook into peaks ready anymore */
1001                 delete _data_ready_connections[which];
1002                 _data_ready_connections[which] = 0;
1003
1004 #if 0
1005                 if (!zero_line) {
1006                         zero_line = new ArdourCanvas::SimpleLine (*group);
1007                         zero_line->property_x1() = (gdouble) 1.0;
1008                         zero_line->property_x2() = (gdouble) (_region->length() / samples_per_unit) - 1.0;
1009                         zero_line->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
1010                         manage_zero_line ();
1011                 }
1012 #endif
1013         }
1014 }
1015
1016 void
1017 AudioRegionView::peaks_ready_handler (uint32_t which)
1018 {
1019         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&AudioRegionView::create_one_wave, this, which, false));
1020         // cerr << "AudioRegionView::peaks_ready_handler() called on " << which << " this: " << this << endl;
1021 }
1022
1023 void
1024 AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
1025 {
1026         if (gain_line == 0) {
1027                 return;
1028         }
1029
1030         double x, y;
1031
1032         /* don't create points that can't be seen */
1033
1034         set_envelope_visible (true);
1035
1036         x = ev->button.x;
1037         y = ev->button.y;
1038
1039         item->w2i (x, y);
1040
1041         nframes_t fx = trackview.editor().pixel_to_frame (x);
1042
1043         if (fx > _region->length()) {
1044                 return;
1045         }
1046
1047         /* compute vertical fractional position */
1048
1049         y = 1.0 - (y / (_height - NAME_HIGHLIGHT_SIZE));
1050
1051         /* map using gain line */
1052
1053         gain_line->view_to_model_coord (x, y);
1054
1055         /* XXX STATEFUL: can't convert to stateful diff until we 
1056            can represent automation data with it.
1057         */
1058
1059         trackview.session()->begin_reversible_command (_("add gain control point"));
1060         XMLNode &before = audio_region()->envelope()->get_state();
1061
1062         if (!audio_region()->envelope_active()) {
1063                 XMLNode &region_before = audio_region()->get_state();
1064                 audio_region()->set_envelope_active(true);
1065                 XMLNode &region_after = audio_region()->get_state();
1066                 trackview.session()->add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &region_before, &region_after));
1067         }
1068
1069         audio_region()->envelope()->add (fx, y);
1070
1071         XMLNode &after = audio_region()->envelope()->get_state();
1072         trackview.session()->add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
1073         trackview.session()->commit_reversible_command ();
1074 }
1075
1076 void
1077 AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent */*ev*/)
1078 {
1079         ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
1080         audio_region()->envelope()->erase (cp->model());
1081 }
1082
1083 void
1084 AudioRegionView::store_flags()
1085 {
1086         XMLNode *node = new XMLNode ("GUI");
1087
1088         node->add_property ("waveform-visible", (_flags & WaveformVisible) ? "yes" : "no");
1089         node->add_property ("envelope-visible", (_flags & EnvelopeVisible) ? "yes" : "no");
1090         node->add_property ("waveform-rectified", (_flags & WaveformRectified) ? "yes" : "no");
1091         node->add_property ("waveform-logscaled", (_flags & WaveformLogScaled) ? "yes" : "no");
1092
1093         _region->add_extra_xml (*node);
1094 }
1095
1096 void
1097 AudioRegionView::set_flags (XMLNode* node)
1098 {
1099         XMLProperty *prop;
1100
1101         if ((prop = node->property ("waveform-visible")) != 0) {
1102                 if (string_is_affirmative (prop->value())) {
1103                         _flags |= WaveformVisible;
1104                 }
1105         }
1106
1107         if ((prop = node->property ("envelope-visible")) != 0) {
1108                 if (string_is_affirmative (prop->value())) {
1109                         _flags |= EnvelopeVisible;
1110                 }
1111         }
1112
1113         if ((prop = node->property ("waveform-rectified")) != 0) {
1114                 if (string_is_affirmative (prop->value())) {
1115                         _flags |= WaveformRectified;
1116                 }
1117         }
1118
1119         if ((prop = node->property ("waveform-logscaled")) != 0) {
1120                 if (string_is_affirmative (prop->value())) {
1121                         _flags |= WaveformLogScaled;
1122                 }
1123         }
1124 }
1125
1126 void
1127 AudioRegionView::set_waveform_shape (WaveformShape shape)
1128 {
1129         bool yn;
1130
1131         /* this slightly odd approach is to leave the door open to
1132            other "shapes" such as spectral displays, etc.
1133         */
1134
1135         switch (shape) {
1136         case Rectified:
1137                 yn = true;
1138                 break;
1139
1140         default:
1141                 yn = false;
1142                 break;
1143         }
1144
1145         if (yn != (bool) (_flags & WaveformRectified)) {
1146                 for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
1147                         (*wave)->property_rectified() = yn;
1148                 }
1149
1150                 if (zero_line) {
1151                         if (yn) {
1152                                 zero_line->hide();
1153                         } else {
1154                                 zero_line->show();
1155                         }
1156                 }
1157
1158                 if (yn) {
1159                         _flags |= WaveformRectified;
1160                 } else {
1161                         _flags &= ~WaveformRectified;
1162                 }
1163                 store_flags ();
1164         }
1165 }
1166
1167 void
1168 AudioRegionView::set_waveform_scale (WaveformScale scale)
1169 {
1170         bool yn = (scale == Logarithmic);
1171
1172         if (yn != (bool) (_flags & WaveformLogScaled)) {
1173                 for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
1174                         (*wave)->property_logscaled() = yn;
1175                 }
1176
1177                 if (yn) {
1178                         _flags |= WaveformLogScaled;
1179                 } else {
1180                         _flags &= ~WaveformLogScaled;
1181                 }
1182                 store_flags ();
1183         }
1184 }
1185
1186
1187 GhostRegion*
1188 AudioRegionView::add_ghost (TimeAxisView& tv)
1189 {
1190         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&trackview);
1191         assert(rtv);
1192
1193         double unit_position = _region->position () / samples_per_unit;
1194         AudioGhostRegion* ghost = new AudioGhostRegion (tv, trackview, unit_position);
1195         uint32_t nchans;
1196
1197         nchans = rtv->track()->n_channels().n_audio();
1198
1199         for (uint32_t n = 0; n < nchans; ++n) {
1200
1201                 if (n >= audio_region()->n_channels()) {
1202                         break;
1203                 }
1204
1205                 WaveView *wave = new WaveView(*ghost->group);
1206
1207                 wave->property_data_src() = _region.get();
1208                 wave->property_cache() =  wave_caches[n];
1209                 wave->property_cache_updater() = false;
1210                 wave->property_channel() = n;
1211                 wave->property_length_function() = (gpointer)region_length_from_c;
1212                 wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c;
1213                 wave->property_peak_function() =  (gpointer) region_read_peaks_from_c;
1214                 wave->property_x() =  0.0;
1215                 wave->property_samples_per_unit() =  samples_per_unit;
1216                 wave->property_amplitude_above_axis() =  _amplitude_above_axis;
1217
1218                 wave->property_region_start() = _region->start();
1219
1220                 ghost->waves.push_back(wave);
1221         }
1222
1223         ghost->set_height ();
1224         ghost->set_duration (_region->length() / samples_per_unit);
1225         ghost->set_colors();
1226         ghosts.push_back (ghost);
1227
1228         return ghost;
1229 }
1230
1231 void
1232 AudioRegionView::entered ()
1233 {
1234         if (gain_line && _flags & EnvelopeVisible) {
1235                 gain_line->show_all_control_points ();
1236         }
1237
1238         uint32_t r,g,b,a;
1239         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
1240         a=255;
1241
1242         if (fade_in_handle) {
1243                 fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1244                 fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1245         }
1246 }
1247
1248 void
1249 AudioRegionView::exited ()
1250 {
1251         if (gain_line) {
1252                 gain_line->hide_all_but_selected_control_points ();
1253         }
1254
1255         uint32_t r,g,b,a;
1256         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
1257         a=0;
1258
1259         if (fade_in_handle) {
1260                 fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1261                 fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1262         }
1263 }
1264
1265 void
1266 AudioRegionView::envelope_active_changed ()
1267 {
1268         if (gain_line) {
1269                 gain_line->set_line_color (audio_region()->envelope_active() ? ARDOUR_UI::config()->canvasvar_GainLine.get() : ARDOUR_UI::config()->canvasvar_GainLineInactive.get());
1270         }
1271 }
1272
1273 void
1274 AudioRegionView::set_waveview_data_src()
1275 {
1276         AudioGhostRegion* agr;
1277         double unit_length= _region->length() / samples_per_unit;
1278
1279         for (uint32_t n = 0; n < waves.size(); ++n) {
1280                 // TODO: something else to let it know the channel
1281                 waves[n]->property_data_src() = _region.get();
1282         }
1283
1284         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1285
1286                 (*i)->set_duration (unit_length);
1287
1288                 if((agr = dynamic_cast<AudioGhostRegion*>(*i)) != 0) {
1289                         for (vector<WaveView*>::iterator w = agr->waves.begin(); w != agr->waves.end(); ++w) {
1290                                 (*w)->property_data_src() = _region.get();
1291                         }
1292                 }
1293         }
1294
1295 }
1296
1297 void
1298 AudioRegionView::color_handler ()
1299 {
1300         //case cMutedWaveForm:
1301         //case cWaveForm:
1302         //case cWaveFormClip:
1303         //case cZeroLine:
1304         set_colors ();
1305
1306         //case cGainLineInactive:
1307         //case cGainLine:
1308         envelope_active_changed();
1309
1310 }
1311
1312 void
1313 AudioRegionView::set_frame_color ()
1314 {
1315         if (!frame) {
1316                 return;
1317         }
1318
1319         if (_region->opaque()) {
1320                 fill_opacity = 130;
1321         } else {
1322                 fill_opacity = 0;
1323         }
1324
1325         uint32_t r,g,b,a;
1326
1327         if (_selected && should_show_selection) {
1328                 UINT_TO_RGBA(ARDOUR_UI::config()->canvasvar_SelectedFrameBase.get(), &r, &g, &b, &a);
1329                 frame->property_fill_color_rgba() = RGBA_TO_UINT(r, g, b, fill_opacity ? fill_opacity : a);
1330
1331                 for (vector<ArdourCanvas::WaveView*>::iterator w = waves.begin(); w != waves.end(); ++w) {
1332                         if (_region->muted()) {
1333                                 (*w)->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_SelectedWaveForm.get(), MUTED_ALPHA);
1334                         } else {
1335                                 (*w)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedWaveForm.get();
1336                                 (*w)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedWaveFormFill.get();
1337                         }
1338                 }
1339         } else {
1340                 if (_recregion) {
1341                         UINT_TO_RGBA(ARDOUR_UI::config()->canvasvar_RecordingRect.get(), &r, &g, &b, &a);
1342                         frame->property_fill_color_rgba() = RGBA_TO_UINT(r, g, b, a);
1343
1344                         for (vector<ArdourCanvas::WaveView*>::iterator w = waves.begin(); w != waves.end(); ++w) {
1345                                 if (_region->muted()) {
1346                                         (*w)->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_RecWaveForm.get(), MUTED_ALPHA);
1347                                 } else {
1348                                         (*w)->property_wave_color() = ARDOUR_UI::config()->canvasvar_RecWaveForm.get();
1349                                         (*w)->property_fill_color() = ARDOUR_UI::config()->canvasvar_RecWaveFormFill.get();
1350                                 }
1351                         }
1352                 } else {
1353                         UINT_TO_RGBA(ARDOUR_UI::config()->canvasvar_FrameBase.get(), &r, &g, &b, &a);
1354                         frame->property_fill_color_rgba() = RGBA_TO_UINT(r, g, b, fill_opacity ? fill_opacity : a);
1355
1356                         for (vector<ArdourCanvas::WaveView*>::iterator w = waves.begin(); w != waves.end(); ++w) {
1357                                 if (_region->muted()) {
1358                                         (*w)->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA);
1359                                 } else {
1360                                         (*w)->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm.get();
1361                                         (*w)->property_fill_color() = ARDOUR_UI::config()->canvasvar_WaveFormFill.get();
1362                                 }
1363                         }
1364                 }
1365         }
1366 }
1367
1368 void
1369 AudioRegionView::set_fade_visibility (bool yn)
1370 {
1371         if (yn) {
1372                 if (fade_in_shape) {
1373                         fade_in_shape->show();
1374                 }
1375                 if (fade_out_shape) {
1376                         fade_out_shape->show ();
1377                 }
1378                 if (fade_in_handle) {
1379                         fade_in_handle->show ();
1380                 }
1381                 if (fade_out_handle) {
1382                         fade_out_handle->show ();
1383                 }
1384         } else {
1385                 if (fade_in_shape) {
1386                         fade_in_shape->hide();
1387                 }
1388                 if (fade_out_shape) {
1389                         fade_out_shape->hide ();
1390                 }
1391                 if (fade_in_handle) {
1392                         fade_in_handle->hide ();
1393                 }
1394                 if (fade_out_handle) {
1395                         fade_out_handle->hide ();
1396                 }
1397         }
1398 }
1399
1400 void
1401 AudioRegionView::update_coverage_frames (LayerDisplay d)
1402 {
1403         RegionView::update_coverage_frames (d);
1404
1405         fade_in_handle->raise_to_top ();
1406         fade_out_handle->raise_to_top ();
1407 }
1408
1409 void
1410 AudioRegionView::show_region_editor ()
1411 {
1412         if (editor == 0) {
1413                 editor = new AudioRegionEditor (trackview.session(), audio_region());
1414         }
1415
1416         editor->present ();
1417         editor->show_all();
1418 }
1419
1420 void
1421 AudioRegionView::transients_changed ()
1422 {
1423         AnalysisFeatureList analysis_features = _region->transients();
1424
1425         while (feature_lines.size() < analysis_features.size()) {
1426                 ArdourCanvas::SimpleLine* l = new ArdourCanvas::SimpleLine (*group);
1427                 l->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
1428                 feature_lines.push_back (make_pair(0, l));
1429         }
1430
1431         while (feature_lines.size() > analysis_features.size()) {
1432                 ArdourCanvas::SimpleLine *line = feature_lines.back().second;
1433                 feature_lines.pop_back ();
1434                 delete line;
1435         }
1436
1437         AnalysisFeatureList::const_iterator i;
1438         list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::iterator l;
1439
1440         for (i = analysis_features.begin(), l = feature_lines.begin(); i != analysis_features.end() && l != feature_lines.end(); ++i, ++l) {
1441                 (*l).first = *i;
1442                 (*l).second->property_x1() = trackview.editor().frame_to_pixel (*i);
1443                 (*l).second->property_x2() = trackview.editor().frame_to_pixel (*i);            
1444                 (*l).second->property_y1() = 2;
1445                 (*l).second->property_y2() = _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1;
1446                 (*l).second->set_data("regionview", this);
1447                 (*l).second->show ();
1448                 (*l).second->raise_to_top ();
1449                 
1450                 (*l).second->signal_event().connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_feature_line_event), (*l).second, this));
1451         }
1452 }
1453
1454 void
1455 AudioRegionView::update_transient(float old_pos, float new_pos)
1456 {
1457         /* Find frame at old pos, calulate new frame then update region transients*/
1458         list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::iterator l;
1459
1460         for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
1461                 /* Simple line x1 has been updated in drag so we compare to new_pos */
1462                 if (rint(new_pos) == rint((*l).second->property_x1())) {
1463                     
1464                     nframes64_t old_frame = (*l).first;
1465                     nframes64_t new_frame = trackview.editor().pixel_to_frame (new_pos);
1466
1467                     _region->update_transient (old_frame, new_frame);
1468                     
1469                     break;
1470                 }
1471         }
1472 }
1473
1474 void
1475 AudioRegionView::remove_transient(float pos)
1476 {
1477         /* Find frame at old pos, calulate new frame then update region transients*/
1478         list<std::pair<nframes64_t, ArdourCanvas::SimpleLine*> >::iterator l;
1479
1480         for (l = feature_lines.begin(); l != feature_lines.end(); ++l) {
1481                 /* Simple line x1 has been updated in drag so we compare to new_pos */
1482                 if (rint(pos) == rint((*l).second->property_x1())) {
1483                     _region->remove_transient ((*l).first);                 
1484                     break;
1485                 }
1486         }
1487 }