Fix some set-but-not-used variable warnings from gcc 4.6
[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
41 #include <gtkmm2ext/gtk_ui.h>
42
43 #include "ardour_ui.h"
44 #include "crossfade_edit.h"
45 #include "rgb_macros.h"
46 #include "keyboard.h"
47 #include "utils.h"
48 #include "gui_thread.h"
49 #include "canvas_impl.h"
50 #include "simplerect.h"
51 #include "waveview.h"
52 #include "actions.h"
53
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57 using namespace Gtk;
58 using namespace Editing;
59
60 using Gtkmm2ext::Keyboard;
61
62 #include "i18n.h"
63
64 const int32_t CrossfadeEditor::Point::size = 7;
65 const double CrossfadeEditor::canvas_border = 10;
66 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
67 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
68
69 CrossfadeEditor::Half::Half ()
70         : line (0)
71         , normative_curve (Evoral::Parameter(GainAutomation))
72         , gain_curve (Evoral::Parameter(GainAutomation))
73 {
74 }
75
76 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
77         : ArdourDialog (_("Edit Crossfade")),
78           xfade (xf),
79           clear_button (_("Clear")),
80           revert_button (_("Reset")),
81           audition_both_button (_("Fade")),
82           audition_left_dry_button (_("Out (dry)")),
83           audition_left_button (_("Out")),
84           audition_right_dry_button (_("In (dry)")),
85           audition_right_button (_("In")),
86
87           preroll_button (_("With Pre-roll")),
88           postroll_button (_("With Post-roll")),
89
90           miny (my),
91           maxy (mxy),
92
93           fade_in_table (3, 3),
94           fade_out_table (3, 3),
95
96           select_in_button (_("Fade In")),
97           select_out_button (_("Fade Out")),
98
99           _peaks_ready_connection (0)
100
101 {
102         set_session (s);
103
104         set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
105         set_name ("CrossfadeEditWindow");
106         set_position (Gtk::WIN_POS_MOUSE);
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), ui_bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
299
300         _session->AuditionActive.connect (_session_connections, invalidator (*this), ui_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 (new MementoCommand<Crossfade> (*xfade.get(), &before, &xfade->get_state ()));
795         _session->commit_reversible_command ();
796 }
797
798 void
799 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
800 {
801         ARDOUR::AutomationList& in (xf->fade_in());
802         ARDOUR::AutomationList& out (xf->fade_out());
803
804         /* IN */
805
806
807         ARDOUR::AutomationList::const_iterator the_end = in.end();
808         --the_end;
809
810         double firstx = (*in.begin())->when;
811         double endx = (*the_end)->when;
812
813         in.freeze ();
814         in.clear ();
815
816         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
817
818                 double when = firstx + ((*i)->x * (endx - firstx));
819                 double value = (*i)->y;
820                 in.add (when, value);
821         }
822
823         /* OUT */
824
825         the_end = out.end();
826         --the_end;
827
828         firstx = (*out.begin())->when;
829         endx = (*the_end)->when;
830
831         out.freeze ();
832         out.clear ();
833
834         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
835
836                 double when = firstx + ((*i)->x * (endx - firstx));
837                 double value = (*i)->y;
838                 out.add (when, value);
839         }
840
841         in.thaw ();
842         out.thaw ();
843 }
844
845 void
846 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
847 {
848         _apply_to (xfade);
849         xfade->set_active (true);
850         xfade->fade_in().curve().solve ();
851         xfade->fade_out().curve().solve ();
852 }
853
854 void
855 CrossfadeEditor::clear ()
856 {
857         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
858                 delete *i;
859         }
860
861         fade[current].points.clear ();
862
863         redraw ();
864 }
865
866 void
867 CrossfadeEditor::reset ()
868 {
869         set (xfade->fade_in(),  In);
870         set (xfade->fade_out(), Out);
871
872         curve_select_clicked (current);
873 }
874
875 void
876 CrossfadeEditor::build_presets ()
877 {
878         Preset* p;
879
880         fade_in_presets = new Presets;
881         fade_out_presets = new Presets;
882
883         /* FADE IN */
884
885         p = new Preset ("Linear (-6dB)", "crossfade-in-linear");
886         p->push_back (PresetPoint (0, 0));
887         p->push_back (PresetPoint (0.000000, 0.000000));
888         p->push_back (PresetPoint (0.166667, 0.166366));
889         p->push_back (PresetPoint (0.333333, 0.332853));
890         p->push_back (PresetPoint (0.500000, 0.499459));
891         p->push_back (PresetPoint (0.666667, 0.666186));
892         p->push_back (PresetPoint (0.833333, 0.833033));
893         p->push_back (PresetPoint (1.000000, 1.000000));
894         fade_in_presets->push_back (p);
895
896         p = new Preset ("S(1)-curve", "crossfade-in-S1");
897         p->push_back (PresetPoint (0, 0));
898         p->push_back (PresetPoint (0.1, 0.01));
899         p->push_back (PresetPoint (0.2, 0.03));
900         p->push_back (PresetPoint (0.8, 0.97));
901         p->push_back (PresetPoint (0.9, 0.99));
902         p->push_back (PresetPoint (1, 1));
903         fade_in_presets->push_back (p);
904
905         p = new Preset ("S(2)-curve", "crossfade-in-S2");
906         p->push_back (PresetPoint (0.0, 0.0));
907         p->push_back (PresetPoint (0.055, 0.222));
908         p->push_back (PresetPoint (0.163, 0.35));
909         p->push_back (PresetPoint (0.837, 0.678));
910         p->push_back (PresetPoint (0.945, 0.783));
911         p->push_back (PresetPoint (1.0, 1.0));
912         fade_in_presets->push_back (p);
913
914         p = new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
915
916         p->push_back (PresetPoint (0.000000, 0.000000));
917         p->push_back (PresetPoint (0.166667, 0.282192));
918         p->push_back (PresetPoint (0.333333, 0.518174));
919         p->push_back (PresetPoint (0.500000, 0.707946));
920         p->push_back (PresetPoint (0.666667, 0.851507));
921         p->push_back (PresetPoint (0.833333, 0.948859));
922         p->push_back (PresetPoint (1.000000, 1.000000));
923
924         fade_in_presets->push_back (p);
925
926         if (!Profile->get_sae()) {
927
928                 p = new Preset ("Short cut", "crossfade-in-short-cut");
929                 p->push_back (PresetPoint (0, 0));
930                 p->push_back (PresetPoint (0.389401, 0.0333333));
931                 p->push_back (PresetPoint (0.629032, 0.0861111));
932                 p->push_back (PresetPoint (0.829493, 0.233333));
933                 p->push_back (PresetPoint (0.9447, 0.483333));
934                 p->push_back (PresetPoint (0.976959, 0.697222));
935                 p->push_back (PresetPoint (1, 1));
936                 fade_in_presets->push_back (p);
937
938                 p = new Preset ("Slow cut", "crossfade-in-slow-cut");
939                 p->push_back (PresetPoint (0, 0));
940                 p->push_back (PresetPoint (0.304147, 0.0694444));
941                 p->push_back (PresetPoint (0.529954, 0.152778));
942                 p->push_back (PresetPoint (0.725806, 0.333333));
943                 p->push_back (PresetPoint (0.847926, 0.558333));
944                 p->push_back (PresetPoint (0.919355, 0.730556));
945                 p->push_back (PresetPoint (1, 1));
946                 fade_in_presets->push_back (p);
947
948                 p = new Preset ("Fast cut", "crossfade-in-fast-cut");
949                 p->push_back (PresetPoint (0, 0));
950                 p->push_back (PresetPoint (0.0737327, 0.308333));
951                 p->push_back (PresetPoint (0.246544, 0.658333));
952                 p->push_back (PresetPoint (0.470046, 0.886111));
953                 p->push_back (PresetPoint (0.652074, 0.972222));
954                 p->push_back (PresetPoint (0.771889, 0.988889));
955                 p->push_back (PresetPoint (1, 1));
956                 fade_in_presets->push_back (p);
957
958                 p = new Preset ("Long cut", "crossfade-in-long-cut");
959                 p->push_back (PresetPoint (0, 0));
960                 p->push_back (PresetPoint (0.0207373, 0.197222));
961                 p->push_back (PresetPoint (0.0645161, 0.525));
962                 p->push_back (PresetPoint (0.152074, 0.802778));
963                 p->push_back (PresetPoint (0.276498, 0.919444));
964                 p->push_back (PresetPoint (0.481567, 0.980556));
965                 p->push_back (PresetPoint (0.767281, 1));
966                 p->push_back (PresetPoint (1, 1));
967                 fade_in_presets->push_back (p);
968         }
969
970         /* FADE OUT */
971
972         // p = new Preset ("regout.xpm");
973         p = new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
974         p->push_back (PresetPoint (0, 1));
975         p->push_back (PresetPoint (0.000000, 1.000000));
976         p->push_back (PresetPoint (0.166667, 0.833033));
977         p->push_back (PresetPoint (0.333333, 0.666186));
978         p->push_back (PresetPoint (0.500000, 0.499459));
979         p->push_back (PresetPoint (0.666667, 0.332853));
980         p->push_back (PresetPoint (0.833333, 0.166366));
981         p->push_back (PresetPoint (1.000000, 0.000000));
982         fade_out_presets->push_back (p);
983
984         p = new Preset ("S(1)-Curve", "crossfade-out-S1");
985         p->push_back (PresetPoint (0, 1));
986         p->push_back (PresetPoint (0.1, 0.99));
987         p->push_back (PresetPoint (0.2, 0.97));
988         p->push_back (PresetPoint (0.8, 0.03));
989         p->push_back (PresetPoint (0.9, 0.01));
990         p->push_back (PresetPoint (1, 0));
991         fade_out_presets->push_back (p);
992
993         p = new Preset ("S(2)-Curve", "crossfade-out-S2");
994         p->push_back (PresetPoint (0.0, 1.0));
995         p->push_back (PresetPoint (0.163, 0.678));
996         p->push_back (PresetPoint (0.055, 0.783));
997         p->push_back (PresetPoint (0.837, 0.35));
998         p->push_back (PresetPoint (0.945, 0.222));
999         p->push_back (PresetPoint (1.0, 0.0));
1000         fade_out_presets->push_back (p);
1001
1002         // p = new Preset ("linout.xpm");
1003         p = new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
1004         p->push_back (PresetPoint (0.000000, 1.000000));
1005         p->push_back (PresetPoint (0.166667, 0.948859));
1006         p->push_back (PresetPoint (0.333333, 0.851507));
1007         p->push_back (PresetPoint (0.500000, 0.707946));
1008         p->push_back (PresetPoint (0.666667, 0.518174));
1009         p->push_back (PresetPoint (0.833333, 0.282192));
1010         p->push_back (PresetPoint (1.000000, 0.000000));
1011         fade_out_presets->push_back (p);
1012
1013         if (!Profile->get_sae()) {
1014                 // p = new Preset ("hiout.xpm");
1015                 p = new Preset ("Short cut", "crossfade-out-short-cut");
1016                 p->push_back (PresetPoint (0, 1));
1017                 p->push_back (PresetPoint (0.305556, 1));
1018                 p->push_back (PresetPoint (0.548611, 0.991736));
1019                 p->push_back (PresetPoint (0.759259, 0.931129));
1020                 p->push_back (PresetPoint (0.918981, 0.68595));
1021                 p->push_back (PresetPoint (0.976852, 0.22865));
1022                 p->push_back (PresetPoint (1, 0));
1023                 fade_out_presets->push_back (p);
1024
1025                 p = new Preset ("Slow cut", "crossfade-out-slow-cut");
1026                 p->push_back (PresetPoint (0, 1));
1027                 p->push_back (PresetPoint (0.228111, 0.988889));
1028                 p->push_back (PresetPoint (0.347926, 0.972222));
1029                 p->push_back (PresetPoint (0.529954, 0.886111));
1030                 p->push_back (PresetPoint (0.753456, 0.658333));
1031                 p->push_back (PresetPoint (0.9262673, 0.308333));
1032                 p->push_back (PresetPoint (1, 0));
1033                 fade_out_presets->push_back (p);
1034
1035                 p = new Preset ("Fast cut", "crossfade-out-fast-cut");
1036                 p->push_back (PresetPoint (0, 1));
1037                 p->push_back (PresetPoint (0.080645, 0.730556));
1038                 p->push_back (PresetPoint (0.277778, 0.289256));
1039                 p->push_back (PresetPoint (0.470046, 0.152778));
1040                 p->push_back (PresetPoint (0.695853, 0.0694444));
1041                 p->push_back (PresetPoint (1, 0));
1042                 fade_out_presets->push_back (p);
1043
1044                 // p = new Preset ("loout.xpm");
1045                 p = new Preset ("Long cut", "crossfade-out-long-cut");
1046                 p->push_back (PresetPoint (0, 1));
1047                 p->push_back (PresetPoint (0.023041, 0.697222));
1048                 p->push_back (PresetPoint (0.0553,   0.483333));
1049                 p->push_back (PresetPoint (0.170507, 0.233333));
1050                 p->push_back (PresetPoint (0.370968, 0.0861111));
1051                 p->push_back (PresetPoint (0.610599, 0.0333333));
1052                 p->push_back (PresetPoint (1, 0));
1053                 fade_out_presets->push_back (p);
1054
1055         }
1056 }
1057
1058 void
1059 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1060 {
1061         current = wf;
1062
1063         if (wf == In) {
1064
1065                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1066                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1067                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1068                 }
1069
1070                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1071                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1072                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1073                 }
1074
1075                 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1076                 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1077                 fade[Out].shading->hide();
1078                 fade[In].shading->show();
1079
1080                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1081                         (*i)->box->hide();
1082                 }
1083
1084                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1085                         (*i)->box->show ();
1086                 }
1087
1088         } else {
1089
1090                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1091                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1092                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1093                 }
1094
1095                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1096                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1097                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1098                 }
1099
1100                 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1101                 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1102                 fade[In].shading->hide();
1103                 fade[Out].shading->show();
1104
1105                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1106                         (*i)->box->hide();
1107                 }
1108
1109                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1110                         (*i)->box->show();
1111                 }
1112
1113         }
1114 }
1115
1116 double
1117 CrossfadeEditor::x_coordinate (double& xfract) const
1118 {
1119         xfract = min (1.0, xfract);
1120         xfract = max (0.0, xfract);
1121
1122         return canvas_border + (xfract * effective_width());
1123 }
1124
1125 double
1126 CrossfadeEditor::y_coordinate (double& yfract) const
1127 {
1128         yfract = min (1.0, yfract);
1129         yfract = max (0.0, yfract);
1130
1131         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1132 }
1133
1134 void
1135 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1136 {
1137         gdouble ht;
1138         uint32_t nchans = region->n_channels();
1139         guint32 color;
1140         double spu;
1141
1142         if (which == In) {
1143                 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1144         } else {
1145                 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1146         }
1147
1148         ht = canvas->get_allocation().get_height() / (double) nchans;
1149         spu = xfade->length() / (double) effective_width();
1150
1151         delete _peaks_ready_connection;
1152         _peaks_ready_connection = 0;
1153
1154         for (uint32_t n = 0; n < nchans; ++n) {
1155
1156                 gdouble yoff = n * ht;
1157
1158                 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1159                         WaveView* waveview = new WaveView (*(canvas->root()));
1160
1161                         waveview->property_data_src() = region.get();
1162                         waveview->property_cache_updater() =  true;
1163                         waveview->property_cache() = WaveView::create_cache();
1164                         waveview->property_channel() = n;
1165                         waveview->property_length_function() = (void*) region_length_from_c;
1166                         waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1167                         waveview->property_peak_function() = (void*) region_read_peaks_from_c;
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->property_x() = canvas_border;
1171                         waveview->property_y() = yoff;
1172                         waveview->property_height() = ht;
1173                         waveview->property_samples_per_unit() = spu;
1174                         waveview->property_amplitude_above_axis() = 2.0;
1175                         waveview->property_wave_color() = color;
1176                         waveview->property_fill_color() = color;
1177
1178                         if (which==In)
1179                                 waveview->property_region_start() = region->start();
1180                         else
1181                                 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1182
1183                         waveview->lower_to_bottom();
1184                         fade[which].waves.push_back (waveview);
1185                 }
1186         }
1187
1188         toplevel->lower_to_bottom();
1189 }
1190
1191 void
1192 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1193 {
1194         boost::shared_ptr<AudioRegion> r (wr.lock());
1195
1196         if (!r) {
1197                 return;
1198         }
1199
1200         /* this should never be called, because the peak files for an xfade
1201            will be ready by the time we want them. but our API forces us
1202            to provide this, so ..
1203         */
1204         delete _peaks_ready_connection;
1205         _peaks_ready_connection = 0;
1206
1207         make_waves (r, which);
1208 }
1209
1210 void
1211 CrossfadeEditor::audition (Audition which)
1212 {
1213         AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1214         framecnt_t preroll;
1215         framecnt_t postroll;
1216         framecnt_t left_start_offset;
1217         framecnt_t right_length;
1218         framecnt_t left_length;
1219
1220         if (which != Right && preroll_button.get_active()) {
1221                 preroll = _session->frame_rate() * 2;  //2 second hardcoded preroll for now
1222         } else {
1223                 preroll = 0;
1224         }
1225
1226         if (which != Left && postroll_button.get_active()) {
1227                 postroll = _session->frame_rate() * 2;  //2 second hardcoded postroll for now
1228         } else {
1229                 postroll = 0;
1230         }
1231
1232         // Is there enough data for the whole preroll?
1233         left_length = xfade->length();
1234         if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1235                 left_start_offset -= preroll;
1236         } else {
1237                 preroll = left_start_offset;
1238                 left_start_offset = 0;
1239         }
1240         left_length += preroll;
1241
1242         // Is there enough data for the whole postroll?
1243         right_length = xfade->length();
1244         if ((xfade->in()->length() - right_length) > postroll) {
1245                 right_length += postroll;
1246         } else {
1247                 right_length = xfade->in()->length();
1248         }
1249
1250         PropertyList left_plist;
1251         PropertyList right_plist;
1252
1253
1254         left_plist.add (ARDOUR::Properties::start, left_start_offset);
1255         left_plist.add (ARDOUR::Properties::length, left_length);
1256         left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1257         left_plist.add (ARDOUR::Properties::layer, 0);
1258         left_plist.add (ARDOUR::Properties::fade_in_active, true);
1259
1260         right_plist.add (ARDOUR::Properties::start, 0);
1261         right_plist.add (ARDOUR::Properties::length, right_length);
1262         right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1263         right_plist.add (ARDOUR::Properties::layer, 0);
1264         right_plist.add (ARDOUR::Properties::fade_out_active, true);
1265
1266         if (which == Left) {
1267                 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1268         } else if (which == Right) {
1269                 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1270         }
1271
1272         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1273                                                      (RegionFactory::create (xfade->out(), left_plist, false)));
1274         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1275                                               (RegionFactory::create (xfade->in(), right_plist, false)));
1276
1277         // apply a 20ms declicking fade at the start and end of auditioning
1278         // XXX this should really be a property
1279
1280         left->set_fade_in_length (_session->frame_rate() / 50);
1281         right->set_fade_out_length (_session->frame_rate() / 50);
1282
1283         pl.add_region (left, 0);
1284         pl.add_region (right, 1 + preroll);
1285
1286         /* there is only one ... */
1287         pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1288
1289         _session->audition_playlist ();
1290 }
1291
1292 void
1293 CrossfadeEditor::audition_both ()
1294 {
1295         audition (Both);
1296 }
1297
1298 void
1299 CrossfadeEditor::audition_left_dry ()
1300 {
1301         PropertyList plist;
1302
1303         plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1304         plist.add (ARDOUR::Properties::length, xfade->length());
1305         plist.add (ARDOUR::Properties::name, string("xfade left"));
1306         plist.add (ARDOUR::Properties::layer, 0);
1307
1308         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1309                                              (RegionFactory::create (xfade->out(), plist, false)));
1310
1311         _session->audition_region (left);
1312 }
1313
1314 void
1315 CrossfadeEditor::audition_left ()
1316 {
1317         audition (Left);
1318 }
1319
1320 void
1321 CrossfadeEditor::audition_right_dry ()
1322 {
1323         PropertyList plist;
1324
1325         plist.add (ARDOUR::Properties::start, 0);
1326         plist.add (ARDOUR::Properties::length, xfade->length());
1327         plist.add (ARDOUR::Properties::name, string ("xfade right"));
1328         plist.add (ARDOUR::Properties::layer, 0);
1329
1330         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1331                                               (RegionFactory::create (xfade->in(), plist, false)));
1332
1333         _session->audition_region (right);
1334 }
1335
1336 void
1337 CrossfadeEditor::audition_right ()
1338 {
1339         audition (Right);
1340 }
1341
1342 void
1343 CrossfadeEditor::cancel_audition ()
1344 {
1345         _session->cancel_audition ();
1346 }
1347
1348 void
1349 CrossfadeEditor::audition_toggled ()
1350 {
1351         bool x;
1352
1353         if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1354
1355                 if (x) {
1356                         audition_both ();
1357                 } else {
1358                         cancel_audition ();
1359                 }
1360         }
1361 }
1362
1363 void
1364 CrossfadeEditor::audition_right_toggled ()
1365 {
1366         bool x;
1367
1368         if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1369
1370                 if (x) {
1371                         audition_right ();
1372                 } else {
1373                         cancel_audition ();
1374                 }
1375         }
1376 }
1377
1378 void
1379 CrossfadeEditor::audition_right_dry_toggled ()
1380 {
1381         bool x;
1382
1383         if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1384
1385                 if (x) {
1386                         audition_right_dry ();
1387                 } else {
1388                         cancel_audition ();
1389                 }
1390         }
1391 }
1392
1393 void
1394 CrossfadeEditor::audition_left_toggled ()
1395 {
1396         bool x;
1397
1398         if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1399
1400                 if (x) {
1401                         audition_left ();
1402                 } else {
1403                         cancel_audition ();
1404                 }
1405         }
1406 }
1407
1408 void
1409 CrossfadeEditor::audition_left_dry_toggled ()
1410 {
1411         bool x;
1412
1413         if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1414
1415                 if (x) {
1416                         audition_left_dry ();
1417                 } else {
1418                         cancel_audition ();
1419                 }
1420         }
1421 }
1422
1423 bool
1424 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1425 {
1426         return true;
1427 }
1428
1429 bool
1430 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1431 {
1432         switch (ev->keyval) {
1433         case GDK_Right:
1434                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1435                         audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1436                 } else {
1437                         audition_right_button.set_active (!audition_right_button.get_active());
1438                 }
1439                 break;
1440
1441         case GDK_Left:
1442                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1443                         audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1444                 } else {
1445                         audition_left_button.set_active (!audition_left_button.get_active());
1446                 }
1447                 break;
1448
1449         case GDK_space:
1450                 if (_session->is_auditioning()) {
1451                         cancel_audition ();
1452                 } else {
1453                         audition_both_button.set_active (!audition_both_button.get_active());
1454                 }
1455                 break;
1456
1457         default:
1458                 break;
1459         }
1460
1461         return true;
1462 }