remove all calls to Outline::set_outline_width (1) because this is "wrong" when using...
[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());
1177                         } else {
1178                                 waveview->set_region_start (region->start() + region->length() - xfade->length());
1179                         }
1180
1181                         waveview->lower_to_bottom();
1182                         fade[which].waves.push_back (waveview);
1183                 }
1184         }
1185
1186         toplevel->lower_to_bottom();
1187 }
1188
1189 void
1190 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1191 {
1192         boost::shared_ptr<AudioRegion> r (wr.lock());
1193
1194         if (!r) {
1195                 return;
1196         }
1197
1198         /* this should never be called, because the peak files for an xfade
1199            will be ready by the time we want them. but our API forces us
1200            to provide this, so ..
1201         */
1202         delete _peaks_ready_connection;
1203         _peaks_ready_connection = 0;
1204
1205         make_waves (r, which);
1206 }
1207
1208 void
1209 CrossfadeEditor::audition (Audition which)
1210 {
1211         AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1212         framecnt_t preroll;
1213         framecnt_t postroll;
1214         framecnt_t left_start_offset;
1215         framecnt_t right_length;
1216         framecnt_t left_length;
1217
1218         if (which != Right && preroll_button.get_active()) {
1219                 preroll = _session->frame_rate() * 2;  //2 second hardcoded preroll for now
1220         } else {
1221                 preroll = 0;
1222         }
1223
1224         if (which != Left && postroll_button.get_active()) {
1225                 postroll = _session->frame_rate() * 2;  //2 second hardcoded postroll for now
1226         } else {
1227                 postroll = 0;
1228         }
1229
1230         // Is there enough data for the whole preroll?
1231         left_length = xfade->length();
1232         if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1233                 left_start_offset -= preroll;
1234         } else {
1235                 preroll = left_start_offset;
1236                 left_start_offset = 0;
1237         }
1238         left_length += preroll;
1239
1240         // Is there enough data for the whole postroll?
1241         right_length = xfade->length();
1242         if ((xfade->in()->length() - right_length) > postroll) {
1243                 right_length += postroll;
1244         } else {
1245                 right_length = xfade->in()->length();
1246         }
1247
1248         PropertyList left_plist;
1249         PropertyList right_plist;
1250
1251
1252         left_plist.add (ARDOUR::Properties::start, left_start_offset);
1253         left_plist.add (ARDOUR::Properties::length, left_length);
1254         left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1255         left_plist.add (ARDOUR::Properties::layer, 0);
1256         left_plist.add (ARDOUR::Properties::fade_in_active, true);
1257
1258         right_plist.add (ARDOUR::Properties::start, 0);
1259         right_plist.add (ARDOUR::Properties::length, right_length);
1260         right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1261         right_plist.add (ARDOUR::Properties::layer, 0);
1262         right_plist.add (ARDOUR::Properties::fade_out_active, true);
1263
1264         if (which == Left) {
1265                 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1266         } else if (which == Right) {
1267                 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1268         }
1269
1270         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1271                                                      (RegionFactory::create (xfade->out(), left_plist, false)));
1272         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1273                                               (RegionFactory::create (xfade->in(), right_plist, false)));
1274
1275         // apply a 20ms declicking fade at the start and end of auditioning
1276         // XXX this should really be a property
1277
1278         left->set_fade_in_length (_session->frame_rate() / 50);
1279         right->set_fade_out_length (_session->frame_rate() / 50);
1280
1281         pl.add_region (left, 0);
1282         pl.add_region (right, 1 + preroll);
1283
1284         /* there is only one ... */
1285         pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1286
1287         _session->audition_playlist ();
1288 }
1289
1290 void
1291 CrossfadeEditor::audition_both ()
1292 {
1293         audition (Both);
1294 }
1295
1296 void
1297 CrossfadeEditor::audition_left_dry ()
1298 {
1299         PropertyList plist;
1300
1301         plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1302         plist.add (ARDOUR::Properties::length, xfade->length());
1303         plist.add (ARDOUR::Properties::name, string("xfade left"));
1304         plist.add (ARDOUR::Properties::layer, 0);
1305
1306         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1307                                              (RegionFactory::create (xfade->out(), plist, false)));
1308
1309         _session->audition_region (left);
1310 }
1311
1312 void
1313 CrossfadeEditor::audition_left ()
1314 {
1315         audition (Left);
1316 }
1317
1318 void
1319 CrossfadeEditor::audition_right_dry ()
1320 {
1321         PropertyList plist;
1322
1323         plist.add (ARDOUR::Properties::start, 0);
1324         plist.add (ARDOUR::Properties::length, xfade->length());
1325         plist.add (ARDOUR::Properties::name, string ("xfade right"));
1326         plist.add (ARDOUR::Properties::layer, 0);
1327
1328         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1329                                               (RegionFactory::create (xfade->in(), plist, false)));
1330
1331         _session->audition_region (right);
1332 }
1333
1334 void
1335 CrossfadeEditor::audition_right ()
1336 {
1337         audition (Right);
1338 }
1339
1340 void
1341 CrossfadeEditor::cancel_audition ()
1342 {
1343         _session->cancel_audition ();
1344 }
1345
1346 void
1347 CrossfadeEditor::audition_toggled ()
1348 {
1349         bool x;
1350
1351         if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1352
1353                 if (x) {
1354                         audition_both ();
1355                 } else {
1356                         cancel_audition ();
1357                 }
1358         }
1359 }
1360
1361 void
1362 CrossfadeEditor::audition_right_toggled ()
1363 {
1364         bool x;
1365
1366         if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1367
1368                 if (x) {
1369                         audition_right ();
1370                 } else {
1371                         cancel_audition ();
1372                 }
1373         }
1374 }
1375
1376 void
1377 CrossfadeEditor::audition_right_dry_toggled ()
1378 {
1379         bool x;
1380
1381         if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1382
1383                 if (x) {
1384                         audition_right_dry ();
1385                 } else {
1386                         cancel_audition ();
1387                 }
1388         }
1389 }
1390
1391 void
1392 CrossfadeEditor::audition_left_toggled ()
1393 {
1394         bool x;
1395
1396         if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1397
1398                 if (x) {
1399                         audition_left ();
1400                 } else {
1401                         cancel_audition ();
1402                 }
1403         }
1404 }
1405
1406 void
1407 CrossfadeEditor::audition_left_dry_toggled ()
1408 {
1409         bool x;
1410
1411         if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1412
1413                 if (x) {
1414                         audition_left_dry ();
1415                 } else {
1416                         cancel_audition ();
1417                 }
1418         }
1419 }
1420
1421 bool
1422 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1423 {
1424         return true;
1425 }
1426
1427 bool
1428 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1429 {
1430         switch (ev->keyval) {
1431         case GDK_Right:
1432                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1433                         audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1434                 } else {
1435                         audition_right_button.set_active (!audition_right_button.get_active());
1436                 }
1437                 break;
1438
1439         case GDK_Left:
1440                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1441                         audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1442                 } else {
1443                         audition_left_button.set_active (!audition_left_button.get_active());
1444                 }
1445                 break;
1446
1447         case GDK_space:
1448                 if (_session->is_auditioning()) {
1449                         cancel_audition ();
1450                 } else {
1451                         audition_both_button.set_active (!audition_both_button.get_active());
1452                 }
1453                 break;
1454
1455         default:
1456                 break;
1457         }
1458
1459         return true;
1460 }