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