Remove special handling of session range in export. Fixes things when the session...
[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 #include <libgnomecanvasmm/line.h>
29
30 #include "pbd/memento_command.h"
31 #include "ardour/automation_list.h"
32 #include "evoral/Curve.hpp"
33 #include "ardour/crossfade.h"
34 #include "ardour/session.h"
35 #include "ardour/auditioner.h"
36 #include "ardour/audioplaylist.h"
37 #include "ardour/audiosource.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/profile.h"
40 #include "ardour/crossfade_binder.h"
41
42 #include <gtkmm2ext/gtk_ui.h>
43
44 #include "ardour_ui.h"
45 #include "crossfade_edit.h"
46 #include "rgb_macros.h"
47 #include "keyboard.h"
48 #include "utils.h"
49 #include "gui_thread.h"
50 #include "canvas_impl.h"
51 #include "simplerect.h"
52 #include "waveview.h"
53 #include "actions.h"
54
55 using namespace std;
56 using namespace ARDOUR;
57 using namespace PBD;
58 using namespace Gtk;
59 using namespace Editing;
60
61 using Gtkmm2ext::Keyboard;
62
63 #include "i18n.h"
64
65 const int32_t CrossfadeEditor::Point::size = 7;
66 const double CrossfadeEditor::canvas_border = 10;
67 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
68 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
69
70 CrossfadeEditor::Half::Half ()
71         : line (0)
72         , normative_curve (Evoral::Parameter(GainAutomation))
73         , gain_curve (Evoral::Parameter(GainAutomation))
74 {
75 }
76
77 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
78         : ArdourDialog (_("Edit Crossfade")),
79           xfade (xf),
80           clear_button (_("Clear")),
81           revert_button (_("Reset")),
82           audition_both_button (_("Fade")),
83           audition_left_dry_button (_("Out (dry)")),
84           audition_left_button (_("Out")),
85           audition_right_dry_button (_("In (dry)")),
86           audition_right_button (_("In")),
87
88           preroll_button (_("With Pre-roll")),
89           postroll_button (_("With Post-roll")),
90
91           miny (my),
92           maxy (mxy),
93
94           fade_in_table (3, 3),
95           fade_out_table (3, 3),
96
97           select_in_button (_("Fade In")),
98           select_out_button (_("Fade Out")),
99
100           _peaks_ready_connection (0)
101
102 {
103         set_session (s);
104
105         set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
106         set_name ("CrossfadeEditWindow");
107
108         add_accel_group (ActionManager::ui_manager->get_accel_group());
109
110         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
111
112         RadioButtonGroup sel_but_group = select_in_button.get_group();
113         select_out_button.set_group (sel_but_group);
114         select_out_button.set_mode (false);
115         select_in_button.set_mode (false);
116
117         get_action_area()->set_layout(BUTTONBOX_SPREAD);
118         get_action_area()->pack_start(clear_button);
119         get_action_area()->pack_start(revert_button);
120         cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
121         ok_button = add_button ("OK", RESPONSE_ACCEPT);
122
123         if (fade_in_presets == 0) {
124                 build_presets ();
125         }
126
127         point_grabbed = false;
128         toplevel = 0;
129
130         canvas = new ArdourCanvas::CanvasAA ();
131         canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
132         canvas->set_size_request (425, 200);
133
134         toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
135         toplevel->property_x1() =  0.0;
136         toplevel->property_y1() =  0.0;
137         toplevel->property_x2() =  10.0;
138         toplevel->property_y2() =  10.0;
139         toplevel->property_fill() =  true;
140         toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
141         toplevel->property_outline_pixels() =  0;
142         toplevel->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
143
144         fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
145         fade[Out].line->property_width_pixels() = 1;
146         fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
147
148         fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
149         fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
150
151         fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
152         fade[In].line->property_width_pixels() = 1;
153         fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
154
155         fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
156         fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
157
158         fade[In].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
159         fade[In].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
160         fade[Out].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
161         fade[Out].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
162
163         select_in_button.set_name (X_("CrossfadeEditCurveButton"));
164         select_out_button.set_name (X_("CrossfadeEditCurveButton"));
165
166         select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
167         select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
168
169         HBox* acbox = manage (new HBox);
170
171         audition_box.set_border_width (7);
172         audition_box.set_spacing (5);
173         audition_box.set_homogeneous (false);
174         audition_box.pack_start (audition_left_dry_button, false, false);
175         audition_box.pack_start (audition_left_button, false, false);
176         audition_box.pack_start (audition_both_button, false, false);
177         audition_box.pack_start (audition_right_button, false, false);
178         audition_box.pack_start (audition_right_dry_button, false, false);
179
180         Frame* audition_frame = manage (new Frame (_("Audition")));
181
182         audition_frame->set_name (X_("CrossfadeEditFrame"));
183         audition_frame->add (audition_box);
184
185         acbox->pack_start (*audition_frame, true, false);
186
187         Frame* canvas_frame = manage (new Frame);
188         canvas_frame->add (*canvas);
189         canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
190
191         fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
192         fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
193
194         Image *pxmap;
195         Button* pbutton;
196         int row;
197         int col;
198
199         row = 1;
200         col = 0;
201
202         for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
203
204                 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
205                 pbutton = manage (new Button);
206                 pbutton->add (*pxmap);
207                 pbutton->set_name ("CrossfadeEditButton");
208                 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
209                 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
210                 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
211                 fade_in_buttons.push_back (pbutton);
212
213                 col++;
214
215                 if (col == 2) {
216                         col = 0;
217                         row++;
218                 }
219         }
220
221         row = 1;
222         col = 0;
223
224         for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
225
226                 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
227                 pbutton = manage (new Button);
228                 pbutton->add (*pxmap);
229                 pbutton->set_name ("CrossfadeEditButton");
230                 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
231                 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
232                 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
233                 fade_out_buttons.push_back (pbutton);
234
235                 col++;
236
237                 if (col == 2) {
238                         col = 0;
239                         row++;
240                 }
241         }
242
243         clear_button.set_name ("CrossfadeEditButton");
244         revert_button.set_name ("CrossfadeEditButton");
245         ok_button->set_name ("CrossfadeEditButton");
246         cancel_button->set_name ("CrossfadeEditButton");
247         preroll_button.set_name ("CrossfadeEditButton");
248         postroll_button.set_name ("CrossfadeEditButton");
249         audition_both_button.set_name ("CrossfadeEditAuditionButton");
250         audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
251         audition_left_button.set_name ("CrossfadeEditAuditionButton");
252         audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
253         audition_right_button.set_name ("CrossfadeEditAuditionButton");
254
255         clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
256         revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
257         audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
258         audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
259         audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
260         audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
261         audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
262
263         roll_box.pack_start (preroll_button, false, false);
264         roll_box.pack_start (postroll_button, false, false);
265
266         Gtk::HBox* rcenter_box = manage (new HBox);
267         rcenter_box->pack_start (roll_box, true, false);
268
269         VBox* vpacker2 = manage (new (VBox));
270
271         vpacker2->set_border_width (12);
272         vpacker2->set_spacing (7);
273         vpacker2->pack_start (*acbox, false, false);
274         vpacker2->pack_start (*rcenter_box, false, false);
275
276         curve_button_box.set_spacing (7);
277         curve_button_box.pack_start (fade_out_table, false, false, 12);
278         curve_button_box.pack_start (*vpacker2, false, false, 12);
279         curve_button_box.pack_start (fade_in_table, false, false, 12);
280
281         get_vbox()->pack_start (*canvas_frame, true, true);
282         get_vbox()->pack_start (curve_button_box, false, false);
283
284         /* button to allow hackers to check the actual curve values */
285
286 //      Button* foobut = manage (new Button ("dump"));
287 //      foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
288 //      vpacker.pack_start (*foobut, false, false);
289
290         current = In;
291         set (xfade->fade_in(), In);
292
293         current = Out;
294         set (xfade->fade_out(), Out);
295
296         curve_select_clicked (In);
297
298         xfade->PropertyChanged.connect (state_connection, invalidator (*this), boost::bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
299
300         _session->AuditionActive.connect (_session_connections, invalidator (*this), boost::bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
301         show_all_children();
302 }
303
304 CrossfadeEditor::~CrossfadeEditor()
305 {
306         /* most objects will be destroyed when the toplevel window is. */
307
308         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
309                 delete *i;
310         }
311
312         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
313                 delete *i;
314         }
315
316         delete _peaks_ready_connection;
317 }
318
319 void
320 CrossfadeEditor::dump ()
321 {
322         for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
323                 cerr << (*i)->when << ' ' << (*i)->value << endl;
324         }
325 }
326
327 void
328 CrossfadeEditor::audition_state_changed (bool yn)
329 {
330         ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
331
332         if (!yn) {
333                 audition_both_button.set_active (false);
334                 audition_left_button.set_active (false);
335                 audition_right_button.set_active (false);
336                 audition_left_dry_button.set_active (false);
337                 audition_right_dry_button.set_active (false);
338         }
339 }
340
341 void
342 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
343 {
344         double firstx, endx;
345         ARDOUR::AutomationList::const_iterator the_end;
346
347         for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
348                         delete *i;
349         }
350
351         fade[which].points.clear ();
352         fade[which].gain_curve.clear ();
353         fade[which].normative_curve.clear ();
354
355         if (curve.empty()) {
356                 goto out;
357         }
358
359         the_end = curve.end();
360         --the_end;
361
362         firstx = (*curve.begin())->when;
363         endx = (*the_end)->when;
364
365         for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
366
367                 double xfract = ((*i)->when - firstx) / (endx - firstx);
368                 double yfract = ((*i)->value - miny) / (maxy - miny);
369
370                 Point* p = make_point ();
371
372                 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
373                             xfract, yfract);
374
375                 fade[which].points.push_back (p);
376         }
377
378         /* no need to sort because curve is already time-ordered */
379
380   out:
381
382         swap (which, current);
383         redraw ();
384         swap (which, current);
385 }
386
387 bool
388 CrossfadeEditor::curve_event (GdkEvent* event)
389 {
390         /* treat it like a toplevel event */
391
392         return canvas_event (event);
393 }
394
395 bool
396 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
397 {
398
399         if (point->curve != fade[current].line) {
400                 return FALSE;
401         }
402
403         switch (event->type) {
404         case GDK_BUTTON_PRESS:
405                 point_grabbed = true;
406                 break;
407         case GDK_BUTTON_RELEASE:
408                 point_grabbed = false;
409
410                 if (Keyboard::is_delete_event (&event->button)) {
411                         fade[current].points.remove (point);
412                         delete point;
413                 }
414
415                 redraw ();
416                 break;
417
418         case GDK_MOTION_NOTIFY:
419                 if (point_grabbed) {
420                         double new_x, new_y;
421
422                         /* can't drag first or last points horizontally or vertically */
423
424                         if (point == fade[current].points.front() || point == fade[current].points.back()) {
425                                 new_x = point->x;
426                                 new_y = point->y;
427                         } else {
428                                 new_x = (event->motion.x - canvas_border)/effective_width();
429                                 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
430                         }
431
432                         point->move_to (x_coordinate (new_x), y_coordinate (new_y),
433                                         new_x, new_y);
434                         redraw ();
435                 }
436                 break;
437         default:
438                 break;
439         }
440         return TRUE;
441 }
442
443 bool
444 CrossfadeEditor::canvas_event (GdkEvent* event)
445 {
446         switch (event->type) {
447         case GDK_BUTTON_PRESS:
448                 add_control_point ((event->button.x - canvas_border)/effective_width(),
449                                    1.0 - ((event->button.y - canvas_border)/effective_height()));
450                 return true;
451                 break;
452         default:
453                 break;
454         }
455         return false;
456 }
457
458 CrossfadeEditor::Point::~Point()
459 {
460         delete box;
461 }
462
463 CrossfadeEditor::Point*
464 CrossfadeEditor::make_point ()
465 {
466         Point* p = new Point;
467
468         p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
469         p->box->property_fill() = true;
470         p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
471         p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
472         p->box->property_outline_pixels() = 1;
473
474         p->curve = fade[current].line;
475
476         p->box->signal_event().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
477
478         return p;
479 }
480
481 void
482 CrossfadeEditor::add_control_point (double x, double y)
483 {
484         PointSorter cmp;
485
486         /* enforce end point x location */
487
488         if (fade[current].points.empty()) {
489                 x = 0.0;
490         } else if (fade[current].points.size() == 1) {
491                 x = 1.0;
492         }
493
494         Point* p = make_point ();
495
496         p->move_to (x_coordinate (x), y_coordinate (y), x, y);
497
498         fade[current].points.push_back (p);
499         fade[current].points.sort (cmp);
500
501         redraw ();
502 }
503
504 void
505 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
506 {
507         if ( xfract < 0.0 ) {
508                 xfract = 0.0;
509         } else if ( xfract > 1.0 ) {
510                 xfract = 1.0;
511         }
512
513         if ( yfract < 0.0 ) {
514                 yfract = 0.0;
515         } else if ( yfract > 1.0 ) {
516                 yfract = 1.0;
517         }
518
519         const double half_size = rint(size/2.0);
520         double x1 = nx - half_size;
521         double x2 = nx + half_size;
522
523         box->property_x1() = x1;
524         box->property_x2() = x2;
525
526         box->property_y1() = ny - half_size;
527         box->property_y2() = ny + half_size;
528
529         x = xfract;
530         y = yfract;
531 }
532
533 void
534 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
535 {
536         if (toplevel) {
537                 toplevel->property_x1() = 0.0;
538                 toplevel->property_y1() = 0.0;
539                 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
540                 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
541         }
542
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)->property_y() = yoff;
626                 (*i)->property_height() = ht;
627                 (*i)->property_samples_per_unit() = 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)->property_y() = yoff;
638                 (*i)->property_height() = ht;
639                 (*i)->property_samples_per_unit() = 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 (Gnome::Art::Point (0,0));
685         }
686
687         while (spts.size() < npoints + 3) {
688                 spts.push_back (Gnome::Art::Point (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].set_x (canvas_border);
699                 spts[0].set_y (effective_height() + canvas_border);
700
701                 /* lower right */
702
703                 spts[1].set_x (effective_width() + canvas_border);
704                 spts[1].set_y (effective_height() + canvas_border);
705
706                 /* upper right */
707
708                 spts[2].set_x (effective_width() + canvas_border);
709                 spts[2].set_y (canvas_border);
710
711
712         } else {
713
714                 /*  upper left */
715
716                 spts[0].set_x (canvas_border);
717                 spts[0].set_y (canvas_border);
718
719                 /* lower left */
720
721                 spts[1].set_x (canvas_border);
722                 spts[1].set_y (effective_height() + canvas_border);
723
724                 /* lower right */
725
726                 spts[2].set_x (effective_width() + canvas_border);
727                 spts[2].set_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].set_x (canvas_border + i);
738                 pts[i].set_y  (y_coordinate (y));
739
740                 spts[last_spt - i].set_x (canvas_border + i);
741                 spts[last_spt - i].set_y (pts[i].get_y());
742         }
743
744         fade[current].line->property_points() = pts;
745         fade[current].shading->property_points() = spts;
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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1073                         (*i)->property_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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1078                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1079                 }
1080
1081                 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1082                 fade[Out].line->property_fill_color_rgba() = 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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1098                         (*i)->property_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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1103                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1104                 }
1105
1106                 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1107                 fade[In].line->property_fill_color_rgba() = 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                         WaveView* waveview = new WaveView (*(canvas->root()));
1166
1167                         waveview->property_data_src() = region.get();
1168                         waveview->property_cache_updater() =  true;
1169                         waveview->property_cache() = WaveView::create_cache();
1170                         waveview->property_channel() = n;
1171                         waveview->property_length_function() = (void*) region_length_from_c;
1172                         waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1173                         waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1174                         waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1175                         waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1176                         waveview->property_x() = canvas_border;
1177                         waveview->property_y() = yoff;
1178                         waveview->property_height() = ht;
1179                         waveview->property_samples_per_unit() = spu;
1180                         waveview->property_amplitude_above_axis() = 2.0;
1181                         waveview->property_wave_color() = color;
1182                         waveview->property_fill_color() = color;
1183
1184                         if (which==In)
1185                                 waveview->property_region_start() = region->start();
1186                         else
1187                                 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1188
1189                         waveview->lower_to_bottom();
1190                         fade[which].waves.push_back (waveview);
1191                 }
1192         }
1193
1194         toplevel->lower_to_bottom();
1195 }
1196
1197 void
1198 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1199 {
1200         boost::shared_ptr<AudioRegion> r (wr.lock());
1201
1202         if (!r) {
1203                 return;
1204         }
1205
1206         /* this should never be called, because the peak files for an xfade
1207            will be ready by the time we want them. but our API forces us
1208            to provide this, so ..
1209         */
1210         delete _peaks_ready_connection;
1211         _peaks_ready_connection = 0;
1212
1213         make_waves (r, which);
1214 }
1215
1216 void
1217 CrossfadeEditor::audition (Audition which)
1218 {
1219         AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1220         framecnt_t preroll;
1221         framecnt_t postroll;
1222         framecnt_t left_start_offset;
1223         framecnt_t right_length;
1224         framecnt_t left_length;
1225
1226         if (which != Right && preroll_button.get_active()) {
1227                 preroll = _session->frame_rate() * 2;  //2 second hardcoded preroll for now
1228         } else {
1229                 preroll = 0;
1230         }
1231
1232         if (which != Left && postroll_button.get_active()) {
1233                 postroll = _session->frame_rate() * 2;  //2 second hardcoded postroll for now
1234         } else {
1235                 postroll = 0;
1236         }
1237
1238         // Is there enough data for the whole preroll?
1239         left_length = xfade->length();
1240         if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1241                 left_start_offset -= preroll;
1242         } else {
1243                 preroll = left_start_offset;
1244                 left_start_offset = 0;
1245         }
1246         left_length += preroll;
1247
1248         // Is there enough data for the whole postroll?
1249         right_length = xfade->length();
1250         if ((xfade->in()->length() - right_length) > postroll) {
1251                 right_length += postroll;
1252         } else {
1253                 right_length = xfade->in()->length();
1254         }
1255
1256         PropertyList left_plist;
1257         PropertyList right_plist;
1258
1259
1260         left_plist.add (ARDOUR::Properties::start, left_start_offset);
1261         left_plist.add (ARDOUR::Properties::length, left_length);
1262         left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1263         left_plist.add (ARDOUR::Properties::layer, 0);
1264         left_plist.add (ARDOUR::Properties::fade_in_active, true);
1265
1266         right_plist.add (ARDOUR::Properties::start, 0);
1267         right_plist.add (ARDOUR::Properties::length, right_length);
1268         right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1269         right_plist.add (ARDOUR::Properties::layer, 0);
1270         right_plist.add (ARDOUR::Properties::fade_out_active, true);
1271
1272         if (which == Left) {
1273                 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1274         } else if (which == Right) {
1275                 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1276         }
1277
1278         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1279                                                      (RegionFactory::create (xfade->out(), left_plist, false)));
1280         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1281                                               (RegionFactory::create (xfade->in(), right_plist, false)));
1282
1283         // apply a 20ms declicking fade at the start and end of auditioning
1284         // XXX this should really be a property
1285
1286         left->set_fade_in_length (_session->frame_rate() / 50);
1287         right->set_fade_out_length (_session->frame_rate() / 50);
1288
1289         pl.add_region (left, 0);
1290         pl.add_region (right, 1 + preroll);
1291
1292         /* there is only one ... */
1293         pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1294
1295         _session->audition_playlist ();
1296 }
1297
1298 void
1299 CrossfadeEditor::audition_both ()
1300 {
1301         audition (Both);
1302 }
1303
1304 void
1305 CrossfadeEditor::audition_left_dry ()
1306 {
1307         PropertyList plist;
1308
1309         plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1310         plist.add (ARDOUR::Properties::length, xfade->length());
1311         plist.add (ARDOUR::Properties::name, string("xfade left"));
1312         plist.add (ARDOUR::Properties::layer, 0);
1313
1314         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1315                                              (RegionFactory::create (xfade->out(), plist, false)));
1316
1317         _session->audition_region (left);
1318 }
1319
1320 void
1321 CrossfadeEditor::audition_left ()
1322 {
1323         audition (Left);
1324 }
1325
1326 void
1327 CrossfadeEditor::audition_right_dry ()
1328 {
1329         PropertyList plist;
1330
1331         plist.add (ARDOUR::Properties::start, 0);
1332         plist.add (ARDOUR::Properties::length, xfade->length());
1333         plist.add (ARDOUR::Properties::name, string ("xfade right"));
1334         plist.add (ARDOUR::Properties::layer, 0);
1335
1336         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1337                                               (RegionFactory::create (xfade->in(), plist, false)));
1338
1339         _session->audition_region (right);
1340 }
1341
1342 void
1343 CrossfadeEditor::audition_right ()
1344 {
1345         audition (Right);
1346 }
1347
1348 void
1349 CrossfadeEditor::cancel_audition ()
1350 {
1351         _session->cancel_audition ();
1352 }
1353
1354 void
1355 CrossfadeEditor::audition_toggled ()
1356 {
1357         bool x;
1358
1359         if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1360
1361                 if (x) {
1362                         audition_both ();
1363                 } else {
1364                         cancel_audition ();
1365                 }
1366         }
1367 }
1368
1369 void
1370 CrossfadeEditor::audition_right_toggled ()
1371 {
1372         bool x;
1373
1374         if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1375
1376                 if (x) {
1377                         audition_right ();
1378                 } else {
1379                         cancel_audition ();
1380                 }
1381         }
1382 }
1383
1384 void
1385 CrossfadeEditor::audition_right_dry_toggled ()
1386 {
1387         bool x;
1388
1389         if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1390
1391                 if (x) {
1392                         audition_right_dry ();
1393                 } else {
1394                         cancel_audition ();
1395                 }
1396         }
1397 }
1398
1399 void
1400 CrossfadeEditor::audition_left_toggled ()
1401 {
1402         bool x;
1403
1404         if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1405
1406                 if (x) {
1407                         audition_left ();
1408                 } else {
1409                         cancel_audition ();
1410                 }
1411         }
1412 }
1413
1414 void
1415 CrossfadeEditor::audition_left_dry_toggled ()
1416 {
1417         bool x;
1418
1419         if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1420
1421                 if (x) {
1422                         audition_left_dry ();
1423                 } else {
1424                         cancel_audition ();
1425                 }
1426         }
1427 }
1428
1429 bool
1430 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1431 {
1432         return true;
1433 }
1434
1435 bool
1436 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1437 {
1438         switch (ev->keyval) {
1439         case GDK_Right:
1440                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1441                         audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1442                 } else {
1443                         audition_right_button.set_active (!audition_right_button.get_active());
1444                 }
1445                 break;
1446
1447         case GDK_Left:
1448                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1449                         audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1450                 } else {
1451                         audition_left_button.set_active (!audition_left_button.get_active());
1452                 }
1453                 break;
1454
1455         case GDK_space:
1456                 if (_session->is_auditioning()) {
1457                         cancel_audition ();
1458                 } else {
1459                         audition_both_button.set_active (!audition_both_button.get_active());
1460                 }
1461                 break;
1462
1463         default:
1464                 break;
1465         }
1466
1467         return true;
1468 }