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