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