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