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