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