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