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