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