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