dc6de8d0f6e3dbf6c9a81cfbb7a8c8bae2c26d8c
[ardour.git] / gtk2_ardour / audio_region_view.cc
1 /*
2     Copyright (C) 2001-2006 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
19 #include <cmath>
20 #include <cassert>
21 #include <algorithm>
22
23 #include <gtkmm.h>
24
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include <ardour/playlist.h>
28 #include <ardour/audioregion.h>
29 #include <ardour/audiosource.h>
30 #include <ardour/audio_diskstream.h>
31 #include <pbd/memento_command.h>
32 #include <pbd/stacktrace.h>
33
34 #include "streamview.h"
35 #include "audio_region_view.h"
36 #include "audio_time_axis.h"
37 #include "simplerect.h"
38 #include "simpleline.h"
39 #include "waveview.h"
40 #include "public_editor.h"
41 #include "audio_region_editor.h"
42 #include "region_gain_line.h"
43 #include "control_point.h"
44 #include "ghostregion.h"
45 #include "audio_time_axis.h"
46 #include "utils.h"
47 #include "rgb_macros.h"
48 #include "gui_thread.h"
49 #include "ardour_ui.h"
50
51 #include "i18n.h"
52
53 #define MUTED_ALPHA 0x50
54
55 using namespace sigc;
56 using namespace ARDOUR;
57 using namespace PBD;
58 using namespace Editing;
59 using namespace ArdourCanvas;
60
61 static const int32_t sync_mark_width = 9;
62
63 AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu,
64                                   Gdk::Color& basic_color)
65         : RegionView (parent, tv, r, spu, basic_color)
66         , sync_mark(0)
67         , zero_line(0)
68         , fade_in_shape(0)
69         , fade_out_shape(0)
70         , fade_in_handle(0)
71         , fade_out_handle(0)
72         , gain_line(0)
73         , _amplitude_above_axis(1.0)
74         , _flags(0)
75         , fade_color(0)
76 {
77 }
78
79 AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu, 
80                                   Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility)
81         : RegionView (parent, tv, r, spu, basic_color, visibility)
82         , sync_mark(0)
83         , zero_line(0)
84         , fade_in_shape(0)
85         , fade_out_shape(0)
86         , fade_in_handle(0)
87         , fade_out_handle(0)
88         , gain_line(0)
89         , _amplitude_above_axis(1.0)
90         , _flags(0)
91         , fade_color(0)
92 {
93 }
94
95
96 AudioRegionView::AudioRegionView (const AudioRegionView& other)
97         : RegionView (other)
98         , zero_line(0)
99         , fade_in_shape(0)
100         , fade_out_shape(0)
101         , fade_in_handle(0)
102         , fade_out_handle(0)
103         , gain_line(0)
104         , _amplitude_above_axis(1.0)
105         , _flags(0)
106         , fade_color(0)
107
108 {
109         Gdk::Color c;
110         int r,g,b,a;
111
112         UINT_TO_RGBA (other.fill_color, &r, &g, &b, &a);
113         c.set_rgb_p (r/255.0, g/255.0, b/255.0);
114         
115         init (c, false);
116 }
117
118 void
119 AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
120 {
121         // FIXME: Some redundancy here with RegionView::init.  Need to figure out
122         // where order is important and where it isn't...
123         
124         RegionView::init(basic_color, false);
125         
126         XMLNode *node;
127
128         _amplitude_above_axis = 1.0;
129         zero_line             = 0;
130         _flags                = 0;
131
132         if ((node = _region->extra_xml ("GUI")) != 0) {
133                 set_flags (node);
134         } else {
135                 _flags = WaveformVisible;
136                 store_flags ();
137         }
138
139         if (trackview.editor.new_regionviews_display_gain()) {
140                 _flags |= EnvelopeVisible;
141         }
142
143         compute_colors (basic_color);
144
145         create_waves ();
146
147         fade_in_shape = new ArdourCanvas::Polygon (*group);
148         fade_in_shape->property_fill_color_rgba() = fade_color;
149         fade_in_shape->set_data ("regionview", this);
150         
151         fade_out_shape = new ArdourCanvas::Polygon (*group);
152         fade_out_shape->property_fill_color_rgba() = fade_color;
153         fade_out_shape->set_data ("regionview", this);
154
155
156         {
157                 uint32_t r,g,b,a;
158                 UINT_TO_RGBA(fill_color,&r,&g,&b,&a);
159         
160
161                 fade_in_handle = new ArdourCanvas::SimpleRect (*group);
162                 fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0);
163                 fade_in_handle->property_outline_pixels() = 0;
164                 
165                 fade_in_handle->set_data ("regionview", this);
166                 
167                 fade_out_handle = new ArdourCanvas::SimpleRect (*group);
168                 fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0);
169                 fade_out_handle->property_outline_pixels() = 0;
170                 
171                 fade_out_handle->set_data ("regionview", this);
172         }
173
174         setup_fade_handle_positions ();
175
176         string line_name = _region->name();
177         line_name += ':';
178         line_name += "gain";
179
180         gain_line = new AudioRegionGainLine (line_name, trackview.session(), *this, *group, audio_region()->envelope());
181
182         if (!(_flags & EnvelopeVisible)) {
183                 gain_line->hide ();
184         } else {
185                 gain_line->show ();
186         }
187
188         gain_line->reset ();
189
190         set_y_position_and_height (0, trackview.height);
191
192         region_muted ();
193         region_sync_changed ();
194         region_resized (BoundsChanged);
195         set_waveview_data_src();
196         region_locked ();
197         envelope_active_changed ();
198         fade_in_active_changed ();
199         fade_out_active_changed ();
200
201         fade_in_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_event), fade_in_shape, this));
202         fade_in_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this));
203         fade_out_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_event), fade_out_shape, this));
204         fade_out_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this));
205
206         set_colors ();
207
208         /* XXX sync mark drag? */
209 }
210
211 AudioRegionView::~AudioRegionView ()
212 {
213         in_destructor = true;
214
215         RegionViewGoingAway (this); /* EMIT_SIGNAL */
216
217         for (vector<GnomeCanvasWaveViewCache *>::iterator cache = wave_caches.begin(); cache != wave_caches.end() ; ++cache) {
218                 gnome_canvas_waveview_cache_destroy (*cache);
219         }
220
221         /* all waveviews etc will be destroyed when the group is destroyed */
222
223         if (gain_line) {
224                 delete gain_line;
225         }
226 }
227
228 boost::shared_ptr<ARDOUR::AudioRegion>
229 AudioRegionView::audio_region() const
230 {
231         // "Guaranteed" to succeed...
232         return boost::dynamic_pointer_cast<AudioRegion>(_region);
233 }
234
235 void
236 AudioRegionView::region_changed (Change what_changed)
237 {
238         ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionView::region_changed), what_changed));
239
240         RegionView::region_changed(what_changed);
241
242         if (what_changed & AudioRegion::ScaleAmplitudeChanged) {
243                 region_scale_amplitude_changed ();
244         }
245         if (what_changed & AudioRegion::FadeInChanged) {
246                 fade_in_changed ();
247         }
248         if (what_changed & AudioRegion::FadeOutChanged) {
249                 fade_out_changed ();
250         }
251         if (what_changed & AudioRegion::FadeInActiveChanged) {
252                 fade_in_active_changed ();
253         }
254         if (what_changed & AudioRegion::FadeOutActiveChanged) {
255                 fade_out_active_changed ();
256         }
257         if (what_changed & AudioRegion::EnvelopeActiveChanged) {
258                 envelope_active_changed ();
259         }
260 }
261
262 void
263 AudioRegionView::fade_in_changed ()
264 {
265         reset_fade_in_shape ();
266 }
267
268 void
269 AudioRegionView::fade_out_changed ()
270 {
271         reset_fade_out_shape ();
272 }
273 void
274 AudioRegionView::fade_in_active_changed ()
275 {
276         uint32_t r,g,b,a;
277         uint32_t col;
278         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
279
280         if (audio_region()->fade_in_active()) {
281                 col = RGBA_TO_UINT(r,g,b,120);
282                 fade_in_shape->property_fill_color_rgba() = col;
283                 fade_in_shape->property_width_pixels() = 0;
284                 fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0);
285         } else { 
286                 col = RGBA_TO_UINT(r,g,b,0);
287                 fade_in_shape->property_fill_color_rgba() = col;
288                 fade_in_shape->property_width_pixels() = 1;
289                 fade_in_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255);
290         }
291 }
292
293 void
294 AudioRegionView::fade_out_active_changed ()
295 {
296         uint32_t r,g,b,a;
297         uint32_t col;
298         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
299
300         if (audio_region()->fade_out_active()) {
301                 col = RGBA_TO_UINT(r,g,b,120);
302                 fade_out_shape->property_fill_color_rgba() = col;
303                 fade_out_shape->property_width_pixels() = 0;
304                 fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,0);
305         } else { 
306                 col = RGBA_TO_UINT(r,g,b,0);
307                 fade_out_shape->property_fill_color_rgba() = col;
308                 fade_out_shape->property_width_pixels() = 1;
309                 fade_out_shape->property_outline_color_rgba() = RGBA_TO_UINT(r,g,b,255);
310         }
311 }
312
313
314 void
315 AudioRegionView::region_scale_amplitude_changed ()
316 {
317         ENSURE_GUI_THREAD (mem_fun(*this, &AudioRegionView::region_scale_amplitude_changed));
318
319         for (uint32_t n = 0; n < waves.size(); ++n) {
320                 // force a reload of the cache
321                 waves[n]->property_data_src() = _region.get();
322         }
323 }
324
325 void
326 AudioRegionView::region_renamed ()
327 {
328         Glib::ustring str = RegionView::make_name ();
329         
330         if (audio_region()->speed_mismatch (trackview.session().frame_rate())) {
331                 str = string ("*") + str;
332         }
333
334         if (_region->muted()) {
335                 str = string ("!") + str;
336         }
337
338         set_item_name (str, this);
339         set_name_text (str);
340 }
341
342 void
343 AudioRegionView::region_resized (Change what_changed)
344 {
345         RegionView::region_resized(what_changed);
346
347         if (what_changed & Change (StartChanged|LengthChanged)) {
348
349                 for (uint32_t n = 0; n < waves.size(); ++n) {
350                         waves[n]->property_region_start() = _region->start();
351                 }
352                 
353                 for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
354
355                         for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) {
356                                 (*w)->property_region_start() = _region->start();
357                         }
358                 }
359         }
360 }
361
362 void
363 AudioRegionView::reset_width_dependent_items (double pixel_width)
364 {
365         RegionView::reset_width_dependent_items(pixel_width);
366         assert(_pixel_width == pixel_width);
367
368         if (zero_line) {
369                 zero_line->property_x2() = pixel_width - 1.0;
370         }
371
372         if (fade_in_handle) {
373                 if (pixel_width <= 6.0) {
374                         fade_in_handle->hide();
375                         fade_out_handle->hide();
376                 } else {
377                         if (_height < 5.0) {
378                                 fade_in_handle->hide();
379                                 fade_out_handle->hide();
380                         } else {
381                                 fade_in_handle->show();
382                                 fade_out_handle->show();
383                         }
384                 }
385         }
386
387         reset_fade_shapes ();
388 }
389
390 void
391 AudioRegionView::region_muted ()
392 {
393         RegionView::region_muted();
394
395         for (uint32_t n=0; n < waves.size(); ++n) {
396                 if (_region->muted()) {
397                         waves[n]->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA);
398                 } else {
399                         waves[n]->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm.get();
400                 }
401         }
402 }
403
404 void
405 AudioRegionView::set_y_position_and_height (double y, double h)
406 {
407         RegionView::set_y_position_and_height(y, h - 1);
408
409         _y_position = y;
410         _height = h;
411
412         uint32_t const wcnt = waves.size();
413         for (uint32_t n = 0; n < wcnt; ++n) {
414                 double ht;
415
416                 if (h <= NAME_HIGHLIGHT_THRESH) {
417                         ht = ((_height - 2 * wcnt) / (double) wcnt);
418                 } else {
419                         ht = (((_height - 2 * wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt);
420                 }
421                 
422                 double const yoff = n * (ht + 1);
423                 
424                 waves[n]->property_height() = ht;
425                 waves[n]->property_y() = _y_position + yoff + 2;
426         }
427
428         if (gain_line) {
429                 if ((_height / wcnt) < NAME_HIGHLIGHT_SIZE) {
430                         gain_line->hide ();
431                 } else {
432                         if (_flags & EnvelopeVisible) {
433                                 gain_line->show ();
434                         }
435                 }
436                 gain_line->set_y_position_and_height ((uint32_t) _y_position, (uint32_t) rint (_height - NAME_HIGHLIGHT_SIZE));
437         }
438
439         setup_fade_handle_positions ();
440         manage_zero_line ();
441         reset_fade_shapes ();
442         
443         if (name_text) {
444                 name_text->raise_to_top();
445         }
446 }
447
448 void
449 AudioRegionView::setup_fade_handle_positions()
450 {
451         /* position of fade handle offset from the top of the region view */
452         double const handle_pos = 2;
453         /* height of fade handles */
454         double const handle_height = 5;
455
456         if (fade_in_handle) {
457                 fade_in_handle->property_y1() = _y_position + handle_pos;
458                 fade_in_handle->property_y2() = _y_position + handle_pos + handle_height;
459         }
460         
461         if (fade_out_handle) {
462                 fade_out_handle->property_y1() = _y_position + handle_pos;
463                 fade_out_handle->property_y2() = _y_position + handle_pos + handle_height;
464         }
465 }
466
467 void
468 AudioRegionView::manage_zero_line ()
469 {
470         if (!zero_line) {
471                 return;
472         }
473
474         if (_height >= 100) {
475                 double const wave_midpoint = _y_position + (_height - NAME_HIGHLIGHT_SIZE) / 2.0;
476                 zero_line->property_y1() = wave_midpoint;
477                 zero_line->property_y2() = wave_midpoint;
478                 zero_line->show();
479         } else {
480                 zero_line->hide();
481         }
482 }
483
484 void
485 AudioRegionView::reset_fade_shapes ()
486 {
487         reset_fade_in_shape ();
488         reset_fade_out_shape ();
489 }
490
491 void
492 AudioRegionView::reset_fade_in_shape ()
493 {
494         reset_fade_in_shape_width ((nframes_t) audio_region()->fade_in()->back()->when);
495 }
496         
497 void
498 AudioRegionView::reset_fade_in_shape_width (nframes_t width)
499 {
500         if (fade_in_handle == 0) {
501                 return;
502         }
503
504         /* smallest size for a fade is 64 frames */
505
506         width = std::max ((nframes_t) 64, width);
507
508         Points* points;
509         double pwidth = width / samples_per_unit;
510         uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth);
511         double h; 
512         
513         if (_height < 5) {
514                 fade_in_shape->hide();
515                 fade_in_handle->hide();
516                 return;
517         }
518
519         double handle_center;
520         handle_center = pwidth;
521         
522         if (handle_center > 7.0) {
523                 handle_center -= 3.0;
524         } else {
525                 handle_center = 3.0;
526         }
527         
528         fade_in_handle->property_x1() =  handle_center - 3.0;
529         fade_in_handle->property_x2() =  handle_center + 3.0;
530         
531         if (pwidth < 5) {
532                 fade_in_shape->hide();
533                 return;
534         }
535
536         fade_in_shape->show();
537
538         float curve[npoints];
539         audio_region()->fade_in()->curve().get_vector (0, audio_region()->fade_in()->back()->when, curve, npoints);
540
541         points = get_canvas_points ("fade in shape", npoints+3);
542
543         if (_height > NAME_HIGHLIGHT_THRESH) {
544                 h = _height - NAME_HIGHLIGHT_SIZE;
545         } else {
546                 h = _height;
547         }
548
549         /* points *MUST* be in anti-clockwise order */
550
551         uint32_t pi, pc;
552         double xdelta = pwidth/npoints;
553
554         for (pi = 0, pc = 0; pc < npoints; ++pc) {
555                 (*points)[pi].set_x(1 + (pc * xdelta));
556                 (*points)[pi++].set_y(_y_position + 2 + (h - (curve[pc] * h)));
557         }
558         
559         /* fold back */
560
561         (*points)[pi].set_x(pwidth);
562         (*points)[pi++].set_y(_y_position + 2);
563
564         (*points)[pi].set_x(1);
565         (*points)[pi++].set_y(_y_position + 2);
566
567         /* connect the dots ... */
568
569         (*points)[pi] = (*points)[0];
570         
571         fade_in_shape->property_points() = *points;
572         delete points;
573 }
574
575 void
576 AudioRegionView::reset_fade_out_shape ()
577 {
578         reset_fade_out_shape_width ((nframes_t) audio_region()->fade_out()->back()->when);
579 }
580
581 void
582 AudioRegionView::reset_fade_out_shape_width (nframes_t width)
583 {       
584         if (fade_out_handle == 0) {
585                 return;
586         }
587
588         /* smallest size for a fade is 64 frames */
589
590         width = std::max ((nframes_t) 64, width);
591
592         Points* points;
593         double pwidth = width / samples_per_unit;
594         uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth);
595         double h;
596
597         if (_height < 5) {
598                 fade_out_shape->hide();
599                 fade_out_handle->hide();
600                 return;
601         }
602
603         double handle_center;
604         handle_center = (_region->length() - width) / samples_per_unit;
605         
606         if (handle_center > 7.0) {
607                 handle_center -= 3.0;
608         } else {
609                 handle_center = 3.0;
610         }
611         
612         fade_out_handle->property_x1() =  handle_center - 3.0;
613         fade_out_handle->property_x2() =  handle_center + 3.0;
614
615         /* don't show shape if its too small */
616         
617         if (pwidth < 5) {
618                 fade_out_shape->hide();
619                 return;
620         } 
621         
622         fade_out_shape->show();
623
624         float curve[npoints];
625         audio_region()->fade_out()->curve().get_vector (0, audio_region()->fade_out()->back()->when, curve, npoints);
626
627         if (_height > NAME_HIGHLIGHT_THRESH) {
628                 h = _height - NAME_HIGHLIGHT_SIZE;
629         } else {
630                 h = _height;
631         }
632
633         /* points *MUST* be in anti-clockwise order */
634
635         points = get_canvas_points ("fade out shape", npoints+3);
636
637         uint32_t pi, pc;
638         double xdelta = pwidth/npoints;
639
640         for (pi = 0, pc = 0; pc < npoints; ++pc) {
641                 (*points)[pi].set_x(_pixel_width - 1 - pwidth + (pc*xdelta));
642                 (*points)[pi++].set_y(_y_position + 2 + (h - (curve[pc] * h)));
643         }
644         
645         /* fold back */
646
647         (*points)[pi].set_x(_pixel_width);
648         (*points)[pi++].set_y(_y_position + h);
649
650         (*points)[pi].set_x(_pixel_width);
651         (*points)[pi++].set_y(_y_position + 2);
652
653         /* connect the dots ... */
654
655         (*points)[pi] = (*points)[0];
656
657         fade_out_shape->property_points() = *points;
658         delete points;
659 }
660
661 void
662 AudioRegionView::set_samples_per_unit (gdouble spu)
663 {
664         RegionView::set_samples_per_unit (spu);
665
666         if (_flags & WaveformVisible) {
667                 for (uint32_t n=0; n < waves.size(); ++n) {
668                         waves[n]->property_samples_per_unit() = spu;
669                 }
670         }
671
672         if (gain_line) {
673                 gain_line->reset ();
674         }
675
676         reset_fade_shapes ();
677 }
678
679 void
680 AudioRegionView::set_amplitude_above_axis (gdouble spp)
681 {
682         for (uint32_t n=0; n < waves.size(); ++n) {
683                 waves[n]->property_amplitude_above_axis() = spp;
684         }
685 }
686
687 void
688 AudioRegionView::compute_colors (Gdk::Color& basic_color)
689 {
690         RegionView::compute_colors(basic_color);
691         
692         uint32_t r, g, b, a;
693
694         /* gain color computed in envelope_active_changed() */
695
696         UINT_TO_RGBA (fill_color, &r, &g, &b, &a);
697         fade_color = RGBA_TO_UINT(r,g,b,120);
698 }
699
700 void
701 AudioRegionView::set_colors ()
702 {
703         RegionView::set_colors();
704         
705         if (gain_line) {
706                 gain_line->set_line_color (audio_region()->envelope_active() ? ARDOUR_UI::config()->canvasvar_GainLine.get() : ARDOUR_UI::config()->canvasvar_GainLineInactive.get());
707         }
708
709         for (uint32_t n=0; n < waves.size(); ++n) {
710                 if (_region->muted()) {
711                         waves[n]->property_wave_color() = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA);
712                 } else {
713                         waves[n]->property_wave_color() = ARDOUR_UI::config()->canvasvar_WaveForm.get();
714                 }
715
716                 waves[n]->property_clip_color() = ARDOUR_UI::config()->canvasvar_WaveFormClip.get();
717                 waves[n]->property_zero_color() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
718         }
719 }
720
721 void
722 AudioRegionView::show_region_editor ()
723 {
724         if (editor == 0) {
725                 editor = new AudioRegionEditor (trackview.session(), audio_region(), *this);
726                 // GTK2FIX : how to ensure float without realizing
727                 // editor->realize ();
728                 // trackview.editor.ensure_float (*editor);
729         } 
730
731         editor->present ();
732         editor->show_all();
733 }
734
735 void
736 AudioRegionView::set_waveform_visible (bool yn)
737 {
738         if (((_flags & WaveformVisible) != yn)) {
739                 if (yn) {
740                         for (uint32_t n=0; n < waves.size(); ++n) {
741                                 /* make sure the zoom level is correct, since we don't update
742                                    this when waveforms are hidden.
743                                 */
744                                 waves[n]->property_samples_per_unit() = samples_per_unit;
745                                 waves[n]->show();
746                         }
747                         _flags |= WaveformVisible;
748                 } else {
749                         for (uint32_t n=0; n < waves.size(); ++n) {
750                                 waves[n]->hide();
751                         }
752                         _flags &= ~WaveformVisible;
753                 }
754                 store_flags ();
755         }
756 }
757
758 void
759 AudioRegionView::temporarily_hide_envelope ()
760 {
761         if (gain_line) {
762                 gain_line->hide ();
763         }
764 }
765
766 void
767 AudioRegionView::unhide_envelope ()
768 {
769         if (gain_line && (_flags & EnvelopeVisible)) {
770                 gain_line->show ();
771         }
772 }
773
774 void
775 AudioRegionView::set_envelope_visible (bool yn)
776 {
777         if (gain_line && ((_flags & EnvelopeVisible) != yn)) {
778                 if (yn) {
779                         gain_line->show ();
780                         _flags |= EnvelopeVisible;
781                 } else {
782                         gain_line->hide ();
783                         _flags &= ~EnvelopeVisible;
784                 }
785                 store_flags ();
786         }
787 }
788
789 void
790 AudioRegionView::create_waves ()
791 {
792         RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
793
794         if (!atv.get_diskstream()) {
795                 return;
796         }
797
798         uint32_t nchans = atv.get_diskstream()->n_channels().n_audio();
799         
800         /* in tmp_waves, set up null pointers for each channel so the vector is allocated */
801         for (uint32_t n = 0; n < nchans; ++n) {
802                 tmp_waves.push_back (0);
803         }
804
805         for (uint32_t n = 0; n < nchans; ++n) {
806                 
807                 if (n >= audio_region()->n_channels()) {
808                         break;
809                 }
810                 
811                 wave_caches.push_back (WaveView::create_cache ());
812
813                 if (wait_for_data) {
814                         if (audio_region()->audio_source(n)->peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) {
815                                 create_one_wave (n, true);
816                         } else {
817                         }
818                 } else {
819                         create_one_wave (n, true);
820                 }
821         }
822 }
823
824 void
825 AudioRegionView::create_one_wave (uint32_t which, bool direct)
826 {
827         RouteTimeAxisView& atv (*(dynamic_cast<RouteTimeAxisView*>(&trackview))); // ick
828         uint32_t nchans = atv.get_diskstream()->n_channels().n_audio();
829         uint32_t n;
830         uint32_t nwaves = std::min (nchans, audio_region()->n_channels());
831         gdouble ht;
832
833         if (trackview.height < NAME_HIGHLIGHT_SIZE) {
834                 ht = ((trackview.height) / (double) nchans);
835         } else {
836                 ht = ((trackview.height - NAME_HIGHLIGHT_SIZE) / (double) nchans);
837         }
838
839         gdouble yoff = which * ht;
840
841         WaveView *wave = new WaveView(*group);
842
843         wave->property_data_src() = (gpointer) _region.get();
844         wave->property_cache() =  wave_caches[which];
845         wave->property_cache_updater() = true;
846         wave->property_channel() =  which;
847         wave->property_length_function() = (gpointer) region_length_from_c;
848         wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c;
849         wave->property_peak_function() =  (gpointer) region_read_peaks_from_c;
850         wave->property_x() =  0.0;
851         wave->property_y() =  yoff;
852         wave->property_height() =  (double) ht;
853         wave->property_samples_per_unit() =  samples_per_unit;
854         wave->property_amplitude_above_axis() =  _amplitude_above_axis;
855         wave->property_wave_color() = _region->muted() ? UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->canvasvar_WaveForm.get(), MUTED_ALPHA) : ARDOUR_UI::config()->canvasvar_WaveForm.get();
856         wave->property_clip_color() = ARDOUR_UI::config()->canvasvar_WaveFormClip.get();
857         wave->property_zero_color() = ARDOUR_UI::config()->canvasvar_ZeroLine.get();
858         wave->property_region_start() = _region->start();
859         wave->property_rectified() = (bool) (_flags & WaveformRectified);
860         wave->property_logscaled() = (bool) (_flags & WaveformLogScaled);
861
862         if (!(_flags & WaveformVisible)) {
863                 wave->hide();
864         }
865
866         /* note: calling this function is serialized by the lock
867            held in the peak building thread that signals that
868            peaks are ready for use *or* by the fact that it is
869            called one by one from the GUI thread.
870         */
871
872         if (which < nchans) {
873                 tmp_waves[which] = wave;
874         } else {
875                 /* n-channel track, >n-channel source */
876         }
877         
878         /* see if we're all ready */
879         
880         for (n = 0; n < nchans; ++n) {
881                 if (tmp_waves[n] == 0) {
882                         break;
883                 }
884         }
885
886         if (n == nwaves && waves.empty()) {
887                 /* all waves are ready */
888                 tmp_waves.resize(nwaves);
889
890                 waves = tmp_waves;
891                 tmp_waves.clear ();
892
893                 /* all waves created, don't hook into peaks ready anymore */
894                 data_ready_connection.disconnect ();            
895
896                 if(0)
897                 if (!zero_line) {
898                         zero_line = new ArdourCanvas::SimpleLine (*group);
899                         zero_line->property_x1() = (gdouble) 1.0;
900                         zero_line->property_x2() = (gdouble) (_region->length() / samples_per_unit) - 1.0;
901                         zero_line->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();
902                         manage_zero_line ();
903                 }
904         }
905 }
906
907 void
908 AudioRegionView::peaks_ready_handler (uint32_t which)
909 {
910         Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false));
911 }
912
913 void
914 AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
915 {
916         if (gain_line == 0) {
917                 return;
918         }
919
920         double x, y;
921
922         /* don't create points that can't be seen */
923
924         set_envelope_visible (true);
925         
926         x = ev->button.x;
927         y = ev->button.y;
928
929         item->w2i (x, y);
930
931         nframes_t fx = trackview.editor.pixel_to_frame (x);
932
933         if (fx > _region->length()) {
934                 return;
935         }
936
937         /* compute vertical fractional position */
938
939         y = 1.0 - ((y - _y_position) / (_height - NAME_HIGHLIGHT_SIZE));
940         
941         /* map using gain line */
942
943         gain_line->view_to_model_y (y);
944
945         trackview.session().begin_reversible_command (_("add gain control point"));
946         XMLNode &before = audio_region()->envelope()->get_state();
947
948         if (!audio_region()->envelope_active()) {
949                 XMLNode &region_before = audio_region()->get_state();
950                 audio_region()->set_envelope_active(true);
951                 XMLNode &region_after = audio_region()->get_state();
952                 trackview.session().add_command (new MementoCommand<AudioRegion>(*(audio_region().get()), &region_before, &region_after));
953         }
954
955         audio_region()->envelope()->add (fx, y);
956         
957         XMLNode &after = audio_region()->envelope()->get_state();
958         trackview.session().add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
959         trackview.session().commit_reversible_command ();
960 }
961
962 void
963 AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
964 {
965         ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
966         audio_region()->envelope()->erase (cp->model());
967 }
968
969 void
970 AudioRegionView::store_flags()
971 {
972         XMLNode *node = new XMLNode ("GUI");
973
974         node->add_property ("waveform-visible", (_flags & WaveformVisible) ? "yes" : "no");
975         node->add_property ("envelope-visible", (_flags & EnvelopeVisible) ? "yes" : "no");
976         node->add_property ("waveform-rectified", (_flags & WaveformRectified) ? "yes" : "no");
977         node->add_property ("waveform-logscaled", (_flags & WaveformLogScaled) ? "yes" : "no");
978
979         _region->add_extra_xml (*node);
980 }
981
982 void
983 AudioRegionView::set_flags (XMLNode* node)
984 {
985         XMLProperty *prop;
986
987         if ((prop = node->property ("waveform-visible")) != 0) {
988                 if (prop->value() == "yes") {
989                         _flags |= WaveformVisible;
990                 }
991         }
992
993         if ((prop = node->property ("envelope-visible")) != 0) {
994                 if (prop->value() == "yes") {
995                         _flags |= EnvelopeVisible;
996                 }
997         }
998
999         if ((prop = node->property ("waveform-rectified")) != 0) {
1000                 if (prop->value() == "yes") {
1001                         _flags |= WaveformRectified;
1002                 }
1003         }
1004
1005         if ((prop = node->property ("waveform-logscaled")) != 0) {
1006                 if (prop->value() == "yes") {
1007                         _flags |= WaveformLogScaled;
1008                 }
1009         }
1010 }
1011         
1012 void
1013 AudioRegionView::set_waveform_shape (WaveformShape shape)
1014 {
1015         bool yn;
1016
1017         /* this slightly odd approach is to leave the door open to 
1018            other "shapes" such as spectral displays, etc.
1019         */
1020
1021         switch (shape) {
1022         case Rectified:
1023                 yn = true;
1024                 break;
1025
1026         default:
1027                 yn = false;
1028                 break;
1029         }
1030
1031         if (yn != (bool) (_flags & WaveformRectified)) {
1032                 for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
1033                         (*wave)->property_rectified() = yn;
1034                 }
1035
1036                 if (zero_line) {
1037                         if (yn) {
1038                                 zero_line->hide();
1039                         } else {
1040                                 zero_line->show();
1041                         }
1042                 }
1043
1044                 if (yn) {
1045                         _flags |= WaveformRectified;
1046                 } else {
1047                         _flags &= ~WaveformRectified;
1048                 }
1049                 store_flags ();
1050         }
1051 }
1052
1053 void
1054 AudioRegionView::set_waveform_scale (WaveformScale scale)
1055 {
1056         bool yn = (scale == LogWaveform);
1057
1058         if (yn != (bool) (_flags & WaveformLogScaled)) {
1059                 for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
1060                         (*wave)->property_logscaled() = yn;
1061                 }
1062
1063                 if (yn) {
1064                         _flags |= WaveformLogScaled;
1065                 } else {
1066                         _flags &= ~WaveformLogScaled;
1067                 }
1068                 store_flags ();
1069         }
1070 }
1071
1072
1073 GhostRegion*
1074 AudioRegionView::add_ghost (AutomationTimeAxisView& atv)
1075 {
1076         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&trackview);
1077         assert(rtv);
1078
1079         double unit_position = _region->position () / samples_per_unit;
1080         GhostRegion* ghost = new GhostRegion (atv, unit_position);
1081         uint32_t nchans;
1082         
1083         nchans = rtv->get_diskstream()->n_channels().n_audio();
1084
1085         for (uint32_t n = 0; n < nchans; ++n) {
1086                 
1087                 if (n >= audio_region()->n_channels()) {
1088                         break;
1089                 }
1090                 
1091                 WaveView *wave = new WaveView(*ghost->group);
1092
1093                 wave->property_data_src() = _region.get();
1094                 wave->property_cache() =  wave_caches[n];
1095                 wave->property_cache_updater() = false;
1096                 wave->property_channel() = n;
1097                 wave->property_length_function() = (gpointer)region_length_from_c;
1098                 wave->property_sourcefile_length_function() = (gpointer) sourcefile_length_from_c;
1099                 wave->property_peak_function() =  (gpointer) region_read_peaks_from_c;
1100                 wave->property_x() =  0.0;
1101                 wave->property_samples_per_unit() =  samples_per_unit;
1102                 wave->property_amplitude_above_axis() =  _amplitude_above_axis;
1103                 wave->property_wave_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWave.get();
1104                 wave->property_clip_color() = ARDOUR_UI::config()->canvasvar_GhostTrackWaveClip.get();
1105                 wave->property_zero_color() = ARDOUR_UI::config()->canvasvar_GhostTrackZeroLine.get();
1106                 wave->property_region_start() = _region->start();
1107
1108                 ghost->waves.push_back(wave);
1109         }
1110
1111         ghost->set_height ();
1112         ghost->set_duration (_region->length() / samples_per_unit);
1113         ghosts.push_back (ghost);
1114
1115         ghost->GoingAway.connect (mem_fun(*this, &AudioRegionView::remove_ghost));
1116
1117         return ghost;
1118 }
1119
1120 void
1121 AudioRegionView::entered ()
1122 {
1123         if (gain_line && _flags & EnvelopeVisible) {
1124                 gain_line->show_all_control_points ();
1125         }
1126
1127         uint32_t r,g,b,a;
1128         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
1129         a=255;
1130         
1131         if (fade_in_handle) {
1132                 fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1133                 fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1134         }
1135 }
1136
1137 void
1138 AudioRegionView::exited ()
1139 {
1140         if (gain_line) {
1141                 gain_line->hide_all_but_selected_control_points ();
1142         }
1143         
1144         uint32_t r,g,b,a;
1145         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
1146         a=0;
1147         
1148         if (fade_in_handle) {
1149                 fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1150                 fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,a);
1151         }
1152 }
1153
1154 void
1155 AudioRegionView::envelope_active_changed ()
1156 {
1157         if (gain_line) {
1158                 gain_line->set_line_color (audio_region()->envelope_active() ? ARDOUR_UI::config()->canvasvar_GainLine.get() : ARDOUR_UI::config()->canvasvar_GainLineInactive.get());
1159         }
1160 }
1161
1162 void
1163 AudioRegionView::set_waveview_data_src()
1164 {
1165
1166         double unit_length= _region->length() / samples_per_unit;
1167
1168         for (uint32_t n = 0; n < waves.size(); ++n) {
1169                 // TODO: something else to let it know the channel
1170                 waves[n]->property_data_src() = _region.get();
1171         }
1172         
1173         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1174                 
1175                 (*i)->set_duration (unit_length);
1176                 
1177                 for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) {
1178                         (*w)->property_data_src() = _region.get();
1179                 }
1180         }
1181
1182 }
1183
1184 void
1185 AudioRegionView::color_handler ()
1186 {
1187         //case cMutedWaveForm:
1188         //case cWaveForm:
1189         //case cWaveFormClip:
1190         //case cZeroLine:
1191         set_colors ();
1192
1193         //case cGainLineInactive:
1194         //case cGainLine:
1195         envelope_active_changed();
1196
1197 }