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