many pervasive changes primarily related to waveform drawing, particular content...
[ardour.git] / gtk2_ardour / crossfade_edit.cc
1 /*
2     Copyright (C) 2004 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
20 #include <cmath>
21
22 #include <sigc++/bind.h>
23
24 #include <gtkmm/frame.h>
25 #include <gtkmm/image.h>
26 #include <gtkmm/scrolledwindow.h>
27
28
29 #include "pbd/memento_command.h"
30 #include "ardour/automation_list.h"
31 #include "evoral/Curve.hpp"
32 #include "ardour/crossfade.h"
33 #include "ardour/session.h"
34 #include "ardour/auditioner.h"
35 #include "ardour/audioplaylist.h"
36 #include "ardour/audiosource.h"
37 #include "ardour/region_factory.h"
38 #include "ardour/profile.h"
39 #include "ardour/crossfade_binder.h"
40
41 #include <gtkmm2ext/gtk_ui.h>
42
43 #include "canvas/rectangle.h"
44 #include "canvas/wave_view.h"
45 #include "canvas/line.h"
46 #include "canvas/polygon.h"
47
48 #include "ardour_ui.h"
49 #include "crossfade_edit.h"
50 #include "rgb_macros.h"
51 #include "keyboard.h"
52 #include "utils.h"
53 #include "gui_thread.h"
54 #include "actions.h"
55
56 using namespace std;
57 using namespace ARDOUR;
58 using namespace PBD;
59 using namespace Gtk;
60 using namespace Editing;
61
62 using Gtkmm2ext::Keyboard;
63
64 #include "i18n.h"
65
66 const int32_t CrossfadeEditor::Point::size = 7;
67 const double CrossfadeEditor::canvas_border = 10;
68 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
69 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
70
71 CrossfadeEditor::Half::Half ()
72         : line (0)
73         , normative_curve (Evoral::Parameter(GainAutomation))
74         , gain_curve (Evoral::Parameter(GainAutomation))
75 {
76 }
77
78 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
79         : ArdourDialog (_("Edit Crossfade")),
80           xfade (xf),
81           clear_button (_("Clear")),
82           revert_button (_("Reset")),
83           audition_both_button (_("Fade")),
84           audition_left_dry_button (_("Out (dry)")),
85           audition_left_button (_("Out")),
86           audition_right_dry_button (_("In (dry)")),
87           audition_right_button (_("In")),
88
89           preroll_button (_("With Pre-roll")),
90           postroll_button (_("With Post-roll")),
91
92           miny (my),
93           maxy (mxy),
94
95           fade_in_table (3, 3),
96           fade_out_table (3, 3),
97
98           select_in_button (_("Fade In")),
99           select_out_button (_("Fade Out")),
100
101           _peaks_ready_connection (0)
102
103 {
104         set_session (s);
105
106         set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
107         set_name ("CrossfadeEditWindow");
108         set_position (Gtk::WIN_POS_MOUSE);
109
110         add_accel_group (ActionManager::ui_manager->get_accel_group());
111
112         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
113
114         RadioButtonGroup sel_but_group = select_in_button.get_group();
115         select_out_button.set_group (sel_but_group);
116         select_out_button.set_mode (false);
117         select_in_button.set_mode (false);
118
119         get_action_area()->set_layout(BUTTONBOX_SPREAD);
120         get_action_area()->pack_start(clear_button);
121         get_action_area()->pack_start(revert_button);
122         cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
123         ok_button = add_button ("OK", RESPONSE_ACCEPT);
124
125         if (fade_in_presets == 0) {
126                 build_presets ();
127         }
128
129         point_grabbed = false;
130         toplevel = 0;
131
132         canvas = new ArdourCanvas::GtkCanvas ();
133         canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
134         canvas->set_size_request (425, 200);
135
136         toplevel = new ArdourCanvas::Rectangle (canvas->root());
137         toplevel->set (ArdourCanvas::Rect (0, 0, 10, 10));
138         toplevel->set_fill (true);
139         toplevel->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorBase());
140         toplevel->set_outline (false);
141         toplevel->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
142
143         fade[Out].line = new ArdourCanvas::PolyLine (canvas->root());
144         fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
145
146         fade[Out].shading = new ArdourCanvas::Polygon (canvas->root());
147         fade[Out].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
148
149         fade[In].line = new ArdourCanvas::PolyLine (canvas->root());
150         fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
151
152         fade[In].shading = new ArdourCanvas::Polygon (canvas->root());
153         fade[In].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
154
155         fade[In].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
156         fade[In].line->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
157         fade[Out].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
158         fade[Out].line->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
159
160         select_in_button.set_name (X_("CrossfadeEditCurveButton"));
161         select_out_button.set_name (X_("CrossfadeEditCurveButton"));
162
163         select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
164         select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
165
166         HBox* acbox = manage (new HBox);
167
168         audition_box.set_border_width (7);
169         audition_box.set_spacing (5);
170         audition_box.set_homogeneous (false);
171         audition_box.pack_start (audition_left_dry_button, false, false);
172         audition_box.pack_start (audition_left_button, false, false);
173         audition_box.pack_start (audition_both_button, false, false);
174         audition_box.pack_start (audition_right_button, false, false);
175         audition_box.pack_start (audition_right_dry_button, false, false);
176
177         Frame* audition_frame = manage (new Frame (_("Audition")));
178
179         audition_frame->set_name (X_("CrossfadeEditFrame"));
180         audition_frame->add (audition_box);
181
182         acbox->pack_start (*audition_frame, true, false);
183
184         Frame* canvas_frame = manage (new Frame);
185         canvas_frame->add (*canvas);
186         canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
187
188         fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
189         fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
190
191         Image *pxmap;
192         Button* pbutton;
193         int row;
194         int col;
195
196         row = 1;
197         col = 0;
198
199         for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
200
201                 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
202                 pbutton = manage (new Button);
203                 pbutton->add (*pxmap);
204                 pbutton->set_name ("CrossfadeEditButton");
205                 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
206                 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
207                 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
208                 fade_in_buttons.push_back (pbutton);
209
210                 col++;
211
212                 if (col == 2) {
213                         col = 0;
214                         row++;
215                 }
216         }
217
218         row = 1;
219         col = 0;
220
221         for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
222
223                 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
224                 pbutton = manage (new Button);
225                 pbutton->add (*pxmap);
226                 pbutton->set_name ("CrossfadeEditButton");
227                 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
228                 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
229                 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
230                 fade_out_buttons.push_back (pbutton);
231
232                 col++;
233
234                 if (col == 2) {
235                         col = 0;
236                         row++;
237                 }
238         }
239
240         clear_button.set_name ("CrossfadeEditButton");
241         revert_button.set_name ("CrossfadeEditButton");
242         ok_button->set_name ("CrossfadeEditButton");
243         cancel_button->set_name ("CrossfadeEditButton");
244         preroll_button.set_name ("CrossfadeEditButton");
245         postroll_button.set_name ("CrossfadeEditButton");
246         audition_both_button.set_name ("CrossfadeEditAuditionButton");
247         audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
248         audition_left_button.set_name ("CrossfadeEditAuditionButton");
249         audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
250         audition_right_button.set_name ("CrossfadeEditAuditionButton");
251
252         clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
253         revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
254         audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
255         audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
256         audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
257         audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
258         audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
259
260         roll_box.pack_start (preroll_button, false, false);
261         roll_box.pack_start (postroll_button, false, false);
262
263         Gtk::HBox* rcenter_box = manage (new HBox);
264         rcenter_box->pack_start (roll_box, true, false);
265
266         VBox* vpacker2 = manage (new (VBox));
267
268         vpacker2->set_border_width (12);
269         vpacker2->set_spacing (7);
270         vpacker2->pack_start (*acbox, false, false);
271         vpacker2->pack_start (*rcenter_box, false, false);
272
273         curve_button_box.set_spacing (7);
274         curve_button_box.pack_start (fade_out_table, false, false, 12);
275         curve_button_box.pack_start (*vpacker2, false, false, 12);
276         curve_button_box.pack_start (fade_in_table, false, false, 12);
277
278         get_vbox()->pack_start (*canvas_frame, true, true);
279         get_vbox()->pack_start (curve_button_box, false, false);
280
281         /* button to allow hackers to check the actual curve values */
282
283 //      Button* foobut = manage (new Button ("dump"));
284 //      foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
285 //      vpacker.pack_start (*foobut, false, false);
286
287         current = In;
288         set (xfade->fade_in(), In);
289
290         current = Out;
291         set (xfade->fade_out(), Out);
292
293         curve_select_clicked (In);
294
295         xfade->PropertyChanged.connect (state_connection, invalidator (*this), boost::bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
296
297         _session->AuditionActive.connect (_session_connections, invalidator (*this), boost::bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
298         show_all_children();
299 }
300
301 CrossfadeEditor::~CrossfadeEditor()
302 {
303         /* most objects will be destroyed when the toplevel window is. */
304
305         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
306                 delete *i;
307         }
308
309         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
310                 delete *i;
311         }
312
313         delete _peaks_ready_connection;
314 }
315
316 void
317 CrossfadeEditor::dump ()
318 {
319         for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
320                 cerr << (*i)->when << ' ' << (*i)->value << endl;
321         }
322 }
323
324 void
325 CrossfadeEditor::audition_state_changed (bool yn)
326 {
327         ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
328
329         if (!yn) {
330                 audition_both_button.set_active (false);
331                 audition_left_button.set_active (false);
332                 audition_right_button.set_active (false);
333                 audition_left_dry_button.set_active (false);
334                 audition_right_dry_button.set_active (false);
335         }
336 }
337
338 void
339 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
340 {
341         double firstx, endx;
342         ARDOUR::AutomationList::const_iterator the_end;
343
344         for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
345                         delete *i;
346         }
347
348         fade[which].points.clear ();
349         fade[which].gain_curve.clear ();
350         fade[which].normative_curve.clear ();
351
352         if (curve.empty()) {
353                 goto out;
354         }
355
356         the_end = curve.end();
357         --the_end;
358
359         firstx = (*curve.begin())->when;
360         endx = (*the_end)->when;
361
362         for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
363
364                 double xfract = ((*i)->when - firstx) / (endx - firstx);
365                 double yfract = ((*i)->value - miny) / (maxy - miny);
366
367                 Point* p = make_point ();
368
369                 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
370                             xfract, yfract);
371
372                 fade[which].points.push_back (p);
373         }
374
375         /* no need to sort because curve is already time-ordered */
376
377   out:
378
379         swap (which, current);
380         redraw ();
381         swap (which, current);
382 }
383
384 bool
385 CrossfadeEditor::curve_event (GdkEvent* event)
386 {
387         /* treat it like a toplevel event */
388
389         return canvas_event (event);
390 }
391
392 bool
393 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
394 {
395
396         if (point->curve != fade[current].line) {
397                 return FALSE;
398         }
399
400         switch (event->type) {
401         case GDK_BUTTON_PRESS:
402                 point_grabbed = true;
403                 break;
404         case GDK_BUTTON_RELEASE:
405                 point_grabbed = false;
406
407                 if (Keyboard::is_delete_event (&event->button)) {
408                         fade[current].points.remove (point);
409                         delete point;
410                 }
411
412                 redraw ();
413                 break;
414
415         case GDK_MOTION_NOTIFY:
416                 if (point_grabbed) {
417                         double new_x, new_y;
418
419                         /* can't drag first or last points horizontally or vertically */
420
421                         if (point == fade[current].points.front() || point == fade[current].points.back()) {
422                                 new_x = point->x;
423                                 new_y = point->y;
424                         } else {
425                                 new_x = (event->motion.x - canvas_border)/effective_width();
426                                 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
427                         }
428
429                         point->move_to (x_coordinate (new_x), y_coordinate (new_y),
430                                         new_x, new_y);
431                         redraw ();
432                 }
433                 break;
434         default:
435                 break;
436         }
437         return TRUE;
438 }
439
440 bool
441 CrossfadeEditor::canvas_event (GdkEvent* event)
442 {
443         switch (event->type) {
444         case GDK_BUTTON_PRESS:
445                 add_control_point ((event->button.x - canvas_border)/effective_width(),
446                                    1.0 - ((event->button.y - canvas_border)/effective_height()));
447                 return true;
448                 break;
449         default:
450                 break;
451         }
452         return false;
453 }
454
455 CrossfadeEditor::Point::~Point()
456 {
457         delete box;
458 }
459
460 CrossfadeEditor::Point*
461 CrossfadeEditor::make_point ()
462 {
463         Point* p = new Point;
464
465         p->box = new ArdourCanvas::Rectangle (canvas->root());
466         p->box->set_fill (true);
467         p->box->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointFill());
468         p->box->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointOutline());
469
470         p->curve = fade[current].line;
471
472         p->box->Event.connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
473
474         return p;
475 }
476
477 void
478 CrossfadeEditor::add_control_point (double x, double y)
479 {
480         PointSorter cmp;
481
482         /* enforce end point x location */
483
484         if (fade[current].points.empty()) {
485                 x = 0.0;
486         } else if (fade[current].points.size() == 1) {
487                 x = 1.0;
488         }
489
490         Point* p = make_point ();
491
492         p->move_to (x_coordinate (x), y_coordinate (y), x, y);
493
494         fade[current].points.push_back (p);
495         fade[current].points.sort (cmp);
496
497         redraw ();
498 }
499
500 void
501 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
502 {
503         if ( xfract < 0.0 ) {
504                 xfract = 0.0;
505         } else if ( xfract > 1.0 ) {
506                 xfract = 1.0;
507         }
508
509         if ( yfract < 0.0 ) {
510                 yfract = 0.0;
511         } else if ( yfract > 1.0 ) {
512                 yfract = 1.0;
513         }
514
515         const double half_size = rint(size/2.0);
516         double x1 = nx - half_size;
517         double x2 = nx + half_size;
518
519         box->set (ArdourCanvas::Rect (x1, ny - half_size, x2, ny + half_size));
520
521         x = xfract;
522         y = yfract;
523 }
524
525 void
526 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
527 {
528         if (toplevel) {
529                 toplevel->set (
530                         ArdourCanvas::Rect (
531                                 0,
532                                 0,
533                                 canvas->get_allocation().get_width() + canvas_border,
534                                 canvas->get_allocation().get_height() + canvas_border
535                                 )
536                         );
537         }
538
539         /* XXX: CANVAS */
540 //      canvas->set_scroll_region (0.0, 0.0,
541 //                                 canvas->get_allocation().get_width(),
542 //                                 canvas->get_allocation().get_height());
543
544         Point* end = make_point ();
545         PointSorter cmp;
546
547         if (fade[In].points.size() > 1) {
548                 Point* old_end = fade[In].points.back();
549                 fade[In].points.pop_back ();
550                 end->move_to (x_coordinate (old_end->x),
551                               y_coordinate (old_end->y),
552                               old_end->x, old_end->y);
553                 delete old_end;
554         } else {
555                 double x = 1.0;
556                 double y = 0.5;
557                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
558
559         }
560
561         fade[In].points.push_back (end);
562         fade[In].points.sort (cmp);
563
564         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
565                 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
566                                (*i)->x, (*i)->y);
567         }
568
569         end = make_point ();
570
571         if (fade[Out].points.size() > 1) {
572                 Point* old_end = fade[Out].points.back();
573                 fade[Out].points.pop_back ();
574                 end->move_to (x_coordinate (old_end->x),
575                               y_coordinate (old_end->y),
576                               old_end->x, old_end->y);
577                 delete old_end;
578         } else {
579                 double x = 1.0;
580                 double y = 0.5;
581                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
582
583         }
584
585         fade[Out].points.push_back (end);
586         fade[Out].points.sort (cmp);
587
588         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
589                 (*i)->move_to (x_coordinate ((*i)->x),
590                                y_coordinate ((*i)->y),
591                                (*i)->x, (*i)->y);
592         }
593
594         WhichFade old_current = current;
595         current = In;
596         redraw ();
597         current = Out;
598         redraw ();
599         current = old_current;
600
601         double spu = xfade->length() / (double) effective_width();
602
603         if (fade[In].waves.empty()) {
604                 make_waves (xfade->in(), In);
605         }
606
607         if (fade[Out].waves.empty()) {
608                 make_waves (xfade->out(), Out);
609         }
610
611         double ht;
612         vector<ArdourCanvas::WaveView*>::iterator i;
613         uint32_t n;
614
615         ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
616
617         for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
618                 double yoff;
619
620                 yoff = n * ht;
621
622                 (*i)->set_y_position (yoff);
623                 (*i)->set_height (ht);
624                 (*i)->set_samples_per_pixel (spu);
625         }
626
627         ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
628
629         for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
630                 double yoff;
631
632                 yoff = n * ht;
633
634                 (*i)->set_y_position (yoff);
635                 (*i)->set_height (ht);
636                 (*i)->set_samples_per_pixel (spu);
637         }
638
639 }
640
641
642 void
643 CrossfadeEditor::xfade_changed (const PropertyChange&)
644 {
645         set (xfade->fade_in(), In);
646         set (xfade->fade_out(), Out);
647 }
648
649 void
650 CrossfadeEditor::redraw ()
651 {
652         if (canvas->get_allocation().get_width() < 2) {
653                 return;
654         }
655
656         framecnt_t len = xfade->length ();
657
658         fade[current].normative_curve.clear ();
659         fade[current].gain_curve.clear ();
660
661         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
662                 fade[current].normative_curve.add ((*i)->x, (*i)->y);
663                 double offset;
664                 if (current==In)
665                         offset = xfade->in()->start();
666                 else
667                         offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
668                 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
669         }
670
671
672         size_t npoints = (size_t) effective_width();
673         float vec[npoints];
674
675         fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
676
677         ArdourCanvas::Points pts;
678         ArdourCanvas::Points spts;
679
680         while (pts.size() < npoints) {
681                 pts.push_back (ArdourCanvas::Duple (0,0));
682         }
683
684         while (spts.size() < npoints + 3) {
685                 spts.push_back (ArdourCanvas::Duple (0,0));
686         }
687
688         /* the shade coordinates *MUST* be in anti-clockwise order.
689          */
690
691         if (current == In) {
692
693                 /* lower left */
694
695                 spts[0].x = canvas_border;
696                 spts[0].y = effective_height() + canvas_border;
697
698                 /* lower right */
699
700                 spts[1].x = effective_width() + canvas_border;
701                 spts[1].y = effective_height() + canvas_border;
702
703                 /* upper right */
704
705                 spts[2].x = effective_width() + canvas_border;
706                 spts[2].y = canvas_border;
707
708
709         } else {
710
711                 /*  upper left */
712
713                 spts[0].x = canvas_border;
714                 spts[0].y = canvas_border;
715
716                 /* lower left */
717
718                 spts[1].x = canvas_border;
719                 spts[1].y = effective_height() + canvas_border;
720
721                 /* lower right */
722
723                 spts[2].x = effective_width() + canvas_border;
724                 spts[2].y = effective_height() + canvas_border;
725
726         }
727
728         size_t last_spt = (npoints + 3) - 1;
729
730         for (size_t i = 0; i < npoints; ++i) {
731
732                 double y = vec[i];
733
734                 pts[i].x = canvas_border + i;
735                 pts[i].y = y_coordinate (y);
736
737                 spts[last_spt - i].x = canvas_border + i;
738                 spts[last_spt - i].y = pts[i].y;
739         }
740
741         fade[current].line->set (pts);
742         fade[current].shading->set (pts);
743
744         for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
745                 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
746         }
747 }
748
749 void
750 CrossfadeEditor::apply_preset (Preset *preset)
751 {
752
753         WhichFade wf =  find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
754
755         if (current != wf) {
756
757                 if (wf == In) {
758                         select_in_button.clicked();
759                 } else {
760                         select_out_button.clicked();
761                 }
762
763                 curve_select_clicked (wf);
764         }
765
766         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
767                 delete *i;
768         }
769
770         fade[current].points.clear ();
771
772         for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
773                 Point* p = make_point ();
774                 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
775                             (*i).x, (*i).y);
776                 fade[current].points.push_back (p);
777         }
778
779         redraw ();
780 }
781
782 void
783 CrossfadeEditor::apply ()
784 {
785         _session->begin_reversible_command (_("Edit crossfade"));
786
787         XMLNode& before = xfade->get_state ();
788
789         _apply_to (xfade);
790
791         _session->add_command (
792                 new MementoCommand<Crossfade> (
793                         new ARDOUR::CrossfadeBinder (_session->playlists, xfade->id ()),
794                         &before, &xfade->get_state ()
795                         )
796                 );
797
798         _session->commit_reversible_command ();
799 }
800
801 void
802 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
803 {
804         ARDOUR::AutomationList& in (xf->fade_in());
805         ARDOUR::AutomationList& out (xf->fade_out());
806
807         /* IN */
808
809
810         ARDOUR::AutomationList::const_iterator the_end = in.end();
811         --the_end;
812
813         double firstx = (*in.begin())->when;
814         double endx = (*the_end)->when;
815
816         in.freeze ();
817         in.clear ();
818
819         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
820
821                 double when = firstx + ((*i)->x * (endx - firstx));
822                 double value = (*i)->y;
823                 in.add (when, value);
824         }
825
826         /* OUT */
827
828         the_end = out.end();
829         --the_end;
830
831         firstx = (*out.begin())->when;
832         endx = (*the_end)->when;
833
834         out.freeze ();
835         out.clear ();
836
837         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
838
839                 double when = firstx + ((*i)->x * (endx - firstx));
840                 double value = (*i)->y;
841                 out.add (when, value);
842         }
843
844         in.thaw ();
845         out.thaw ();
846 }
847
848 void
849 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
850 {
851         _apply_to (xfade);
852         xfade->set_active (true);
853         xfade->fade_in().curve().solve ();
854         xfade->fade_out().curve().solve ();
855 }
856
857 void
858 CrossfadeEditor::clear ()
859 {
860         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
861                 delete *i;
862         }
863
864         fade[current].points.clear ();
865
866         redraw ();
867 }
868
869 void
870 CrossfadeEditor::reset ()
871 {
872         set (xfade->fade_in(),  In);
873         set (xfade->fade_out(), Out);
874
875         curve_select_clicked (current);
876 }
877
878 void
879 CrossfadeEditor::build_presets ()
880 {
881         Preset* p;
882
883         fade_in_presets = new Presets;
884         fade_out_presets = new Presets;
885
886         /* FADE IN */
887
888         p = new Preset ("Linear (-6dB)", "fadein-linear");
889         p->push_back (PresetPoint (0, 0));
890         p->push_back (PresetPoint (0.000000, 0.000000));
891         p->push_back (PresetPoint (0.166667, 0.166366));
892         p->push_back (PresetPoint (0.333333, 0.332853));
893         p->push_back (PresetPoint (0.500000, 0.499459));
894         p->push_back (PresetPoint (0.666667, 0.666186));
895         p->push_back (PresetPoint (0.833333, 0.833033));
896         p->push_back (PresetPoint (1.000000, 1.000000));
897         fade_in_presets->push_back (p);
898
899         p = new Preset ("S(1)-curve", "fadein-S1");
900         p->push_back (PresetPoint (0, 0));
901         p->push_back (PresetPoint (0.1, 0.01));
902         p->push_back (PresetPoint (0.2, 0.03));
903         p->push_back (PresetPoint (0.8, 0.97));
904         p->push_back (PresetPoint (0.9, 0.99));
905         p->push_back (PresetPoint (1, 1));
906         fade_in_presets->push_back (p);
907
908         p = new Preset ("S(2)-curve", "fadein-S2");
909         p->push_back (PresetPoint (0.0, 0.0));
910         p->push_back (PresetPoint (0.055, 0.222));
911         p->push_back (PresetPoint (0.163, 0.35));
912         p->push_back (PresetPoint (0.837, 0.678));
913         p->push_back (PresetPoint (0.945, 0.783));
914         p->push_back (PresetPoint (1.0, 1.0));
915         fade_in_presets->push_back (p);
916
917         p = new Preset ("Constant power (-3dB)", "fadein-constant-power");
918
919         p->push_back (PresetPoint (0.000000, 0.000000));
920         p->push_back (PresetPoint (0.166667, 0.282192));
921         p->push_back (PresetPoint (0.333333, 0.518174));
922         p->push_back (PresetPoint (0.500000, 0.707946));
923         p->push_back (PresetPoint (0.666667, 0.851507));
924         p->push_back (PresetPoint (0.833333, 0.948859));
925         p->push_back (PresetPoint (1.000000, 1.000000));
926
927         fade_in_presets->push_back (p);
928
929         if (!Profile->get_sae()) {
930
931                 p = new Preset ("Short cut", "fadein-short-cut");
932                 p->push_back (PresetPoint (0, 0));
933                 p->push_back (PresetPoint (0.389401, 0.0333333));
934                 p->push_back (PresetPoint (0.629032, 0.0861111));
935                 p->push_back (PresetPoint (0.829493, 0.233333));
936                 p->push_back (PresetPoint (0.9447, 0.483333));
937                 p->push_back (PresetPoint (0.976959, 0.697222));
938                 p->push_back (PresetPoint (1, 1));
939                 fade_in_presets->push_back (p);
940
941                 p = new Preset ("Slow cut", "fadein-slow-cut");
942                 p->push_back (PresetPoint (0, 0));
943                 p->push_back (PresetPoint (0.304147, 0.0694444));
944                 p->push_back (PresetPoint (0.529954, 0.152778));
945                 p->push_back (PresetPoint (0.725806, 0.333333));
946                 p->push_back (PresetPoint (0.847926, 0.558333));
947                 p->push_back (PresetPoint (0.919355, 0.730556));
948                 p->push_back (PresetPoint (1, 1));
949                 fade_in_presets->push_back (p);
950
951                 p = new Preset ("Fast cut", "fadein-fast-cut");
952                 p->push_back (PresetPoint (0, 0));
953                 p->push_back (PresetPoint (0.0737327, 0.308333));
954                 p->push_back (PresetPoint (0.246544, 0.658333));
955                 p->push_back (PresetPoint (0.470046, 0.886111));
956                 p->push_back (PresetPoint (0.652074, 0.972222));
957                 p->push_back (PresetPoint (0.771889, 0.988889));
958                 p->push_back (PresetPoint (1, 1));
959                 fade_in_presets->push_back (p);
960
961                 p = new Preset ("Long cut", "fadein-long-cut");
962                 p->push_back (PresetPoint (0, 0));
963                 p->push_back (PresetPoint (0.0207373, 0.197222));
964                 p->push_back (PresetPoint (0.0645161, 0.525));
965                 p->push_back (PresetPoint (0.152074, 0.802778));
966                 p->push_back (PresetPoint (0.276498, 0.919444));
967                 p->push_back (PresetPoint (0.481567, 0.980556));
968                 p->push_back (PresetPoint (0.767281, 1));
969                 p->push_back (PresetPoint (1, 1));
970                 fade_in_presets->push_back (p);
971         }
972
973         /* FADE OUT */
974
975         // p = new Preset ("regout.xpm");
976         p = new Preset ("Linear (-6dB cut)", "fadeout-linear");
977         p->push_back (PresetPoint (0, 1));
978         p->push_back (PresetPoint (0.000000, 1.000000));
979         p->push_back (PresetPoint (0.166667, 0.833033));
980         p->push_back (PresetPoint (0.333333, 0.666186));
981         p->push_back (PresetPoint (0.500000, 0.499459));
982         p->push_back (PresetPoint (0.666667, 0.332853));
983         p->push_back (PresetPoint (0.833333, 0.166366));
984         p->push_back (PresetPoint (1.000000, 0.000000));
985         fade_out_presets->push_back (p);
986
987         p = new Preset ("S(1)-Curve", "fadeout-S1");
988         p->push_back (PresetPoint (0, 1));
989         p->push_back (PresetPoint (0.1, 0.99));
990         p->push_back (PresetPoint (0.2, 0.97));
991         p->push_back (PresetPoint (0.8, 0.03));
992         p->push_back (PresetPoint (0.9, 0.01));
993         p->push_back (PresetPoint (1, 0));
994         fade_out_presets->push_back (p);
995
996         p = new Preset ("S(2)-Curve", "fadeout-S2");
997         p->push_back (PresetPoint (0.0, 1.0));
998         p->push_back (PresetPoint (0.163, 0.678));
999         p->push_back (PresetPoint (0.055, 0.783));
1000         p->push_back (PresetPoint (0.837, 0.35));
1001         p->push_back (PresetPoint (0.945, 0.222));
1002         p->push_back (PresetPoint (1.0, 0.0));
1003         fade_out_presets->push_back (p);
1004
1005         // p = new Preset ("linout.xpm");
1006         p = new Preset ("Constant power (-3dB cut)", "fadeout-constant-power");
1007         p->push_back (PresetPoint (0.000000, 1.000000));
1008         p->push_back (PresetPoint (0.166667, 0.948859));
1009         p->push_back (PresetPoint (0.333333, 0.851507));
1010         p->push_back (PresetPoint (0.500000, 0.707946));
1011         p->push_back (PresetPoint (0.666667, 0.518174));
1012         p->push_back (PresetPoint (0.833333, 0.282192));
1013         p->push_back (PresetPoint (1.000000, 0.000000));
1014         fade_out_presets->push_back (p);
1015
1016         if (!Profile->get_sae()) {
1017                 // p = new Preset ("hiout.xpm");
1018                 p = new Preset ("Short cut", "fadeout-short-cut");
1019                 p->push_back (PresetPoint (0, 1));
1020                 p->push_back (PresetPoint (0.305556, 1));
1021                 p->push_back (PresetPoint (0.548611, 0.991736));
1022                 p->push_back (PresetPoint (0.759259, 0.931129));
1023                 p->push_back (PresetPoint (0.918981, 0.68595));
1024                 p->push_back (PresetPoint (0.976852, 0.22865));
1025                 p->push_back (PresetPoint (1, 0));
1026                 fade_out_presets->push_back (p);
1027
1028                 p = new Preset ("Slow cut", "fadeout-slow-cut");
1029                 p->push_back (PresetPoint (0, 1));
1030                 p->push_back (PresetPoint (0.228111, 0.988889));
1031                 p->push_back (PresetPoint (0.347926, 0.972222));
1032                 p->push_back (PresetPoint (0.529954, 0.886111));
1033                 p->push_back (PresetPoint (0.753456, 0.658333));
1034                 p->push_back (PresetPoint (0.9262673, 0.308333));
1035                 p->push_back (PresetPoint (1, 0));
1036                 fade_out_presets->push_back (p);
1037
1038                 p = new Preset ("Fast cut", "fadeout-fast-cut");
1039                 p->push_back (PresetPoint (0, 1));
1040                 p->push_back (PresetPoint (0.080645, 0.730556));
1041                 p->push_back (PresetPoint (0.277778, 0.289256));
1042                 p->push_back (PresetPoint (0.470046, 0.152778));
1043                 p->push_back (PresetPoint (0.695853, 0.0694444));
1044                 p->push_back (PresetPoint (1, 0));
1045                 fade_out_presets->push_back (p);
1046
1047                 // p = new Preset ("loout.xpm");
1048                 p = new Preset ("Long cut", "fadeout-long-cut");
1049                 p->push_back (PresetPoint (0, 1));
1050                 p->push_back (PresetPoint (0.023041, 0.697222));
1051                 p->push_back (PresetPoint (0.0553,   0.483333));
1052                 p->push_back (PresetPoint (0.170507, 0.233333));
1053                 p->push_back (PresetPoint (0.370968, 0.0861111));
1054                 p->push_back (PresetPoint (0.610599, 0.0333333));
1055                 p->push_back (PresetPoint (1, 0));
1056                 fade_out_presets->push_back (p);
1057
1058         }
1059 }
1060
1061 void
1062 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1063 {
1064         current = wf;
1065
1066         if (wf == In) {
1067
1068                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1069                         (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1070                         (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1071                 }
1072
1073                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1074                         (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1075                         (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1076                 }
1077
1078                 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1079                 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1080                 fade[Out].shading->hide();
1081                 fade[In].shading->show();
1082
1083                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1084                         (*i)->box->hide();
1085                 }
1086
1087                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1088                         (*i)->box->show ();
1089                 }
1090
1091         } else {
1092
1093                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1094                         (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1095                         (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1096                 }
1097
1098                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1099                         (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1100                         (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1101                 }
1102
1103                 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1104                 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1105                 fade[In].shading->hide();
1106                 fade[Out].shading->show();
1107
1108                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1109                         (*i)->box->hide();
1110                 }
1111
1112                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1113                         (*i)->box->show();
1114                 }
1115
1116         }
1117 }
1118
1119 double
1120 CrossfadeEditor::x_coordinate (double& xfract) const
1121 {
1122         xfract = min (1.0, xfract);
1123         xfract = max (0.0, xfract);
1124
1125         return canvas_border + (xfract * effective_width());
1126 }
1127
1128 double
1129 CrossfadeEditor::y_coordinate (double& yfract) const
1130 {
1131         yfract = min (1.0, yfract);
1132         yfract = max (0.0, yfract);
1133
1134         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1135 }
1136
1137 void
1138 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1139 {
1140         gdouble ht;
1141         uint32_t nchans = region->n_channels();
1142         guint32 color;
1143         double spu;
1144
1145         if (which == In) {
1146                 color = ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave();
1147         } else {
1148                 color = ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave();
1149         }
1150
1151         ht = canvas->get_allocation().get_height() / (double) nchans;
1152         spu = xfade->length() / (double) effective_width();
1153
1154         delete _peaks_ready_connection;
1155         _peaks_ready_connection = 0;
1156
1157         for (uint32_t n = 0; n < nchans; ++n) {
1158
1159                 gdouble yoff = n * ht;
1160
1161                 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1162                         ArdourCanvas::WaveView* waveview = new ArdourCanvas::WaveView (canvas->root(), region);
1163
1164                         waveview->set_channel (n);
1165                         waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1166                         waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1167                         waveview->set_x_position (canvas_border);
1168                         waveview->set_y_position (yoff);
1169                         waveview->set_height (ht);
1170                         waveview->set_samples_per_pixel (spu);
1171                         waveview->property_amplitude_above_axis() = 2.0;
1172                         waveview->set_outline_color (color);
1173                         waveview->set_fill_color (color);
1174
1175                         if (which != In) {
1176                                 waveview->set_region_start (region->start() + region->length() - xfade->length());
1177                         }
1178
1179                         waveview->lower_to_bottom();
1180                         fade[which].waves.push_back (waveview);
1181                 }
1182         }
1183
1184         toplevel->lower_to_bottom();
1185 }
1186
1187 void
1188 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1189 {
1190         boost::shared_ptr<AudioRegion> r (wr.lock());
1191
1192         if (!r) {
1193                 return;
1194         }
1195
1196         /* this should never be called, because the peak files for an xfade
1197            will be ready by the time we want them. but our API forces us
1198            to provide this, so ..
1199         */
1200         delete _peaks_ready_connection;
1201         _peaks_ready_connection = 0;
1202
1203         make_waves (r, which);
1204 }
1205
1206 void
1207 CrossfadeEditor::audition (Audition which)
1208 {
1209         AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1210         framecnt_t preroll;
1211         framecnt_t postroll;
1212         framecnt_t left_start_offset;
1213         framecnt_t right_length;
1214         framecnt_t left_length;
1215
1216         if (which != Right && preroll_button.get_active()) {
1217                 preroll = _session->frame_rate() * 2;  //2 second hardcoded preroll for now
1218         } else {
1219                 preroll = 0;
1220         }
1221
1222         if (which != Left && postroll_button.get_active()) {
1223                 postroll = _session->frame_rate() * 2;  //2 second hardcoded postroll for now
1224         } else {
1225                 postroll = 0;
1226         }
1227
1228         // Is there enough data for the whole preroll?
1229         left_length = xfade->length();
1230         if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1231                 left_start_offset -= preroll;
1232         } else {
1233                 preroll = left_start_offset;
1234                 left_start_offset = 0;
1235         }
1236         left_length += preroll;
1237
1238         // Is there enough data for the whole postroll?
1239         right_length = xfade->length();
1240         if ((xfade->in()->length() - right_length) > postroll) {
1241                 right_length += postroll;
1242         } else {
1243                 right_length = xfade->in()->length();
1244         }
1245
1246         PropertyList left_plist;
1247         PropertyList right_plist;
1248
1249
1250         left_plist.add (ARDOUR::Properties::start, left_start_offset);
1251         left_plist.add (ARDOUR::Properties::length, left_length);
1252         left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1253         left_plist.add (ARDOUR::Properties::layer, 0);
1254         left_plist.add (ARDOUR::Properties::fade_in_active, true);
1255
1256         right_plist.add (ARDOUR::Properties::start, 0);
1257         right_plist.add (ARDOUR::Properties::length, right_length);
1258         right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1259         right_plist.add (ARDOUR::Properties::layer, 0);
1260         right_plist.add (ARDOUR::Properties::fade_out_active, true);
1261
1262         if (which == Left) {
1263                 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1264         } else if (which == Right) {
1265                 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1266         }
1267
1268         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1269                                                      (RegionFactory::create (xfade->out(), left_plist, false)));
1270         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1271                                               (RegionFactory::create (xfade->in(), right_plist, false)));
1272
1273         // apply a 20ms declicking fade at the start and end of auditioning
1274         // XXX this should really be a property
1275
1276         left->set_fade_in_length (_session->frame_rate() / 50);
1277         right->set_fade_out_length (_session->frame_rate() / 50);
1278
1279         pl.add_region (left, 0);
1280         pl.add_region (right, 1 + preroll);
1281
1282         /* there is only one ... */
1283         pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1284
1285         _session->audition_playlist ();
1286 }
1287
1288 void
1289 CrossfadeEditor::audition_both ()
1290 {
1291         audition (Both);
1292 }
1293
1294 void
1295 CrossfadeEditor::audition_left_dry ()
1296 {
1297         PropertyList plist;
1298
1299         plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1300         plist.add (ARDOUR::Properties::length, xfade->length());
1301         plist.add (ARDOUR::Properties::name, string("xfade left"));
1302         plist.add (ARDOUR::Properties::layer, 0);
1303
1304         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1305                                              (RegionFactory::create (xfade->out(), plist, false)));
1306
1307         _session->audition_region (left);
1308 }
1309
1310 void
1311 CrossfadeEditor::audition_left ()
1312 {
1313         audition (Left);
1314 }
1315
1316 void
1317 CrossfadeEditor::audition_right_dry ()
1318 {
1319         PropertyList plist;
1320
1321         plist.add (ARDOUR::Properties::start, 0);
1322         plist.add (ARDOUR::Properties::length, xfade->length());
1323         plist.add (ARDOUR::Properties::name, string ("xfade right"));
1324         plist.add (ARDOUR::Properties::layer, 0);
1325
1326         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1327                                               (RegionFactory::create (xfade->in(), plist, false)));
1328
1329         _session->audition_region (right);
1330 }
1331
1332 void
1333 CrossfadeEditor::audition_right ()
1334 {
1335         audition (Right);
1336 }
1337
1338 void
1339 CrossfadeEditor::cancel_audition ()
1340 {
1341         _session->cancel_audition ();
1342 }
1343
1344 void
1345 CrossfadeEditor::audition_toggled ()
1346 {
1347         bool x;
1348
1349         if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1350
1351                 if (x) {
1352                         audition_both ();
1353                 } else {
1354                         cancel_audition ();
1355                 }
1356         }
1357 }
1358
1359 void
1360 CrossfadeEditor::audition_right_toggled ()
1361 {
1362         bool x;
1363
1364         if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1365
1366                 if (x) {
1367                         audition_right ();
1368                 } else {
1369                         cancel_audition ();
1370                 }
1371         }
1372 }
1373
1374 void
1375 CrossfadeEditor::audition_right_dry_toggled ()
1376 {
1377         bool x;
1378
1379         if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1380
1381                 if (x) {
1382                         audition_right_dry ();
1383                 } else {
1384                         cancel_audition ();
1385                 }
1386         }
1387 }
1388
1389 void
1390 CrossfadeEditor::audition_left_toggled ()
1391 {
1392         bool x;
1393
1394         if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1395
1396                 if (x) {
1397                         audition_left ();
1398                 } else {
1399                         cancel_audition ();
1400                 }
1401         }
1402 }
1403
1404 void
1405 CrossfadeEditor::audition_left_dry_toggled ()
1406 {
1407         bool x;
1408
1409         if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1410
1411                 if (x) {
1412                         audition_left_dry ();
1413                 } else {
1414                         cancel_audition ();
1415                 }
1416         }
1417 }
1418
1419 bool
1420 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1421 {
1422         return true;
1423 }
1424
1425 bool
1426 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1427 {
1428         switch (ev->keyval) {
1429         case GDK_Right:
1430                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1431                         audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1432                 } else {
1433                         audition_right_button.set_active (!audition_right_button.get_active());
1434                 }
1435                 break;
1436
1437         case GDK_Left:
1438                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1439                         audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1440                 } else {
1441                         audition_left_button.set_active (!audition_left_button.get_active());
1442                 }
1443                 break;
1444
1445         case GDK_space:
1446                 if (_session->is_auditioning()) {
1447                         cancel_audition ();
1448                 } else {
1449                         audition_both_button.set_active (!audition_both_button.get_active());
1450                 }
1451                 break;
1452
1453         default:
1454                 break;
1455         }
1456
1457         return true;
1458 }