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