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