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