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