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