Only create a Curve for an AutomationList if we need it.
[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_list.h>
31 #include <evoral/Curve.hpp>
32 #include <ardour/crossfade.h>
33 #include <ardour/session.h>
34 #include <ardour/auditioner.h>
35 #include <ardour/audioplaylist.h>
36 #include <ardour/audiosource.h>
37 #include <ardour/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 (Evoral::Parameter(GainAutomation))
71         , gain_curve (Evoral::Parameter(GainAutomation))
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::AutomationList& curve, WhichFade which)
336 {
337         double firstx, endx;
338         ARDOUR::AutomationList::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.end();
353         --the_end;
354         
355         firstx = (*curve.begin())->when;
356         endx = (*the_end)->when;
357
358         for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.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         const double half_size = rint(size/2.0);
500         double x1 = nx - half_size;
501         double x2 = nx + half_size;
502
503         box->property_x1() = x1;
504         box->property_x2() = x2;
505
506         box->property_y1() = ny - half_size;
507         box->property_y2() = ny + half_size;
508
509         x = xfract;
510         y = yfract;
511 }
512
513 void
514 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
515 {
516         if (toplevel) {
517                 toplevel->property_x1() = 0.0;
518                 toplevel->property_y1() = 0.0;
519                 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
520                 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
521         }
522         
523         canvas->set_scroll_region (0.0, 0.0, 
524                                    canvas->get_allocation().get_width(), 
525                                    canvas->get_allocation().get_height());
526
527         Point* end = make_point ();
528         PointSorter cmp;
529
530         if (fade[In].points.size() > 1) {
531                 Point* old_end = fade[In].points.back();
532                 fade[In].points.pop_back ();
533                 end->move_to (x_coordinate (old_end->x),
534                               y_coordinate (old_end->y),
535                               old_end->x, old_end->y);
536                 delete old_end;
537         } else {
538                 double x = 1.0;
539                 double y = 0.5;
540                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
541
542         }
543
544         fade[In].points.push_back (end);
545         fade[In].points.sort (cmp);
546
547         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
548                 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
549                                (*i)->x, (*i)->y);
550         }
551         
552         end = make_point ();
553         
554         if (fade[Out].points.size() > 1) {
555                 Point* old_end = fade[Out].points.back();
556                 fade[Out].points.pop_back ();
557                 end->move_to (x_coordinate (old_end->x),
558                               y_coordinate (old_end->y),
559                               old_end->x, old_end->y);
560                 delete old_end;
561         } else {
562                 double x = 1.0;
563                 double y = 0.5;
564                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
565
566         }
567
568         fade[Out].points.push_back (end);
569         fade[Out].points.sort (cmp);
570
571         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
572                 (*i)->move_to (x_coordinate ((*i)->x),
573                                y_coordinate ((*i)->y),
574                                (*i)->x, (*i)->y);
575         }
576         
577         WhichFade old_current = current;
578         current = In;
579         redraw ();
580         current = Out;
581         redraw ();
582         current = old_current;
583
584         double spu = xfade->length() / (double) effective_width();
585
586         if (fade[In].waves.empty()) {
587                 make_waves (xfade->in(), In);
588         }
589
590         if (fade[Out].waves.empty()) {
591                 make_waves (xfade->out(), Out);
592         }
593
594         double ht;
595         vector<ArdourCanvas::WaveView*>::iterator i;
596         uint32_t n;
597
598         ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
599
600         for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
601                 double yoff;
602
603                 yoff = n * ht;
604
605                 (*i)->property_y() = yoff;
606                 (*i)->property_height() = ht;
607                 (*i)->property_samples_per_unit() = spu;
608         }
609
610         ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
611
612         for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].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 }
623
624
625 void
626 CrossfadeEditor::xfade_changed (Change ignored)
627 {
628         set (xfade->fade_in(), In);
629         set (xfade->fade_out(), Out);
630 }
631
632 void
633 CrossfadeEditor::redraw ()
634 {
635         if (canvas->get_allocation().get_width() < 2) {
636                 return;
637         }
638
639         nframes_t len = xfade->length ();
640
641         fade[current].normative_curve.clear ();
642         fade[current].gain_curve.clear ();
643
644         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
645                 fade[current].normative_curve.add ((*i)->x, (*i)->y);
646                 double offset;
647                 if (current==In)
648                         offset = xfade->in()->start();
649                 else
650                         offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
651                 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
652         }
653
654
655         size_t npoints = (size_t) effective_width();
656         float vec[npoints];
657
658         fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
659         
660         ArdourCanvas::Points pts;
661         ArdourCanvas::Points spts;
662
663         while (pts.size() < npoints) {
664                 pts.push_back (Gnome::Art::Point (0,0));
665         }
666
667         while (spts.size() < npoints + 3) {
668                 spts.push_back (Gnome::Art::Point (0,0));
669         }
670
671         /* the shade coordinates *MUST* be in anti-clockwise order.
672          */
673
674         if (current == In) {
675
676                 /* lower left */
677
678                 spts[0].set_x (canvas_border);
679                 spts[0].set_y (effective_height() + canvas_border);
680
681                 /* lower right */
682
683                 spts[1].set_x (effective_width() + canvas_border);
684                 spts[1].set_y (effective_height() + canvas_border);
685
686                 /* upper right */
687
688                 spts[2].set_x (effective_width() + canvas_border);
689                 spts[2].set_y (canvas_border);
690
691                 
692         } else {
693
694                 /*  upper left */
695                 
696                 spts[0].set_x (canvas_border);
697                 spts[0].set_y (canvas_border);
698
699                 /* lower left */
700
701                 spts[1].set_x (canvas_border);
702                 spts[1].set_y (effective_height() + canvas_border);
703
704                 /* lower right */
705
706                 spts[2].set_x (effective_width() + canvas_border);
707                 spts[2].set_y (effective_height() + canvas_border);
708
709         }
710
711         size_t last_spt = (npoints + 3) - 1;
712
713         for (size_t i = 0; i < npoints; ++i) {
714
715                 double y = vec[i];
716                 
717                 pts[i].set_x (canvas_border + i);
718                 pts[i].set_y  (y_coordinate (y));
719
720                 spts[last_spt - i].set_x (canvas_border + i);
721                 spts[last_spt - i].set_y (pts[i].get_y());
722         }
723
724         fade[current].line->property_points() = pts;
725         fade[current].shading->property_points() = spts;
726
727         for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
728                 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
729         }
730 }
731
732 void
733 CrossfadeEditor::apply_preset (Preset *preset)
734 {
735   
736         WhichFade wf =  find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
737         
738         if (current != wf) {
739           
740                 if (wf == In) {
741                         select_in_button.clicked();
742                 } else {
743                         select_out_button.clicked();
744                 }
745                 
746                 curve_select_clicked (wf);
747         }  
748         
749         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
750                 delete *i;
751         }
752
753         fade[current].points.clear ();
754
755         for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
756                 Point* p = make_point ();
757                 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
758                             (*i).x, (*i).y);
759                 fade[current].points.push_back (p);
760         }
761
762         redraw ();
763 }
764
765 void
766 CrossfadeEditor::apply ()
767 {
768         _apply_to (xfade);
769 }
770
771 void
772 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
773 {
774         ARDOUR::AutomationList& in (xf->fade_in());
775         ARDOUR::AutomationList& out (xf->fade_out());
776
777         /* IN */
778
779
780         ARDOUR::AutomationList::const_iterator the_end = in.end();
781         --the_end;
782
783         double firstx = (*in.begin())->when;
784         double endx = (*the_end)->when;
785         double miny = in.get_min_y ();
786         double maxy = in.get_max_y ();
787
788         in.freeze ();
789         in.clear ();
790
791         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
792
793                 double when = firstx + ((*i)->x * (endx - firstx));
794                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
795                 in.add (when, value);
796         }
797
798         /* OUT */
799
800         the_end = out.end();
801         --the_end;
802
803         firstx = (*out.begin())->when;
804         endx = (*the_end)->when;
805         miny = out.get_min_y ();
806         maxy = out.get_max_y ();
807
808         out.freeze ();
809         out.clear ();
810
811         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
812
813                 double when = firstx + ((*i)->x * (endx - firstx));
814                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
815                 out.add (when, value);
816         }
817
818         in.thaw ();
819         out.thaw ();
820 }
821
822 void
823 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
824 {
825         _apply_to (xfade);
826         xfade->set_active (true);
827         xfade->fade_in().curve().solve ();
828         xfade->fade_out().curve().solve ();
829 }
830
831 void
832 CrossfadeEditor::clear ()
833 {
834         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
835                 delete *i;
836         }
837
838         fade[current].points.clear ();
839
840         redraw ();
841 }
842
843 void
844 CrossfadeEditor::reset ()
845 {
846         set (xfade->fade_in(),  In);
847         set (xfade->fade_out(), Out);
848
849         curve_select_clicked (current);
850 }
851
852 void
853 CrossfadeEditor::build_presets ()
854 {
855         Preset* p;
856
857         fade_in_presets = new Presets;
858         fade_out_presets = new Presets;
859
860         /* FADE OUT */
861
862         p = new Preset ("Linear (-6dB)", "crossfade_in_dipped");
863         p->push_back (PresetPoint (0, 0));
864         p->push_back (PresetPoint (0.000000, 0.000000));
865         p->push_back (PresetPoint (0.166667, 0.166366));
866         p->push_back (PresetPoint (0.333333, 0.332853));
867         p->push_back (PresetPoint (0.500000, 0.499459));
868         p->push_back (PresetPoint (0.666667, 0.666186));
869         p->push_back (PresetPoint (0.833333, 0.833033));
870         p->push_back (PresetPoint (1.000000, 1.000000));
871         fade_in_presets->push_back (p);
872
873         p = new Preset ("S(1)-curve", "crossfade_in_default");
874         p->push_back (PresetPoint (0, 0));
875         p->push_back (PresetPoint (0.1, 0.01));
876         p->push_back (PresetPoint (0.2, 0.03));
877         p->push_back (PresetPoint (0.8, 0.97));
878         p->push_back (PresetPoint (0.9, 0.99));
879         p->push_back (PresetPoint (1, 1));
880         fade_in_presets->push_back (p);
881
882         p = new Preset ("S(2)-curve", "crossfade_in_default");
883         p->push_back (PresetPoint (0.0, 0.0));
884         p->push_back (PresetPoint (0.055, 0.222));
885         p->push_back (PresetPoint (0.163, 0.35));
886         p->push_back (PresetPoint (0.837, 0.678));
887         p->push_back (PresetPoint (0.945, 0.783));
888         p->push_back (PresetPoint (1.0, 1.0));
889         fade_in_presets->push_back (p);
890
891         p = new Preset ("Constant Power (-3dB)", "crossfade_in_constant");
892
893         p->push_back (PresetPoint (0.000000, 0.000000));
894         p->push_back (PresetPoint (0.166667, 0.282192));
895         p->push_back (PresetPoint (0.333333, 0.518174));
896         p->push_back (PresetPoint (0.500000, 0.707946));
897         p->push_back (PresetPoint (0.666667, 0.851507));
898         p->push_back (PresetPoint (0.833333, 0.948859));
899         p->push_back (PresetPoint (1.000000, 1.000000));
900
901         fade_in_presets->push_back (p);
902
903         if (!Profile->get_sae()) {
904                 // p = new Preset ("hiin.xpm");
905                 p = new Preset ("Long cut", "crossfade_in_fast-cut");
906                 p->push_back (PresetPoint (0, 0));
907                 p->push_back (PresetPoint (0.0207373, 0.197222));
908                 p->push_back (PresetPoint (0.0645161, 0.525));
909                 p->push_back (PresetPoint (0.152074, 0.802778));
910                 p->push_back (PresetPoint (0.276498, 0.919444));
911                 p->push_back (PresetPoint (0.481567, 0.980556));
912                 p->push_back (PresetPoint (0.767281, 1));
913                 p->push_back (PresetPoint (1, 1));
914                 fade_in_presets->push_back (p);
915                 
916                 // p = new Preset ("loin.xpm");
917                 p = new Preset ("Short cut", "crossfade_in_transition");
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                 
928                 // p = new Preset ("regin2.xpm");
929                 p = new Preset ("Slow cut", "crossfade_in_slow-cut");
930                 p->push_back (PresetPoint (0, 0));
931                 p->push_back (PresetPoint (0.304147, 0.0694444));
932                 p->push_back (PresetPoint (0.529954, 0.152778));
933                 p->push_back (PresetPoint (0.725806, 0.333333));
934                 p->push_back (PresetPoint (0.847926, 0.558333));
935                 p->push_back (PresetPoint (0.919355, 0.730556));
936                 p->push_back (PresetPoint (1, 1));
937                 fade_in_presets->push_back (p);
938         }
939         
940         /* FADE OUT */
941
942         // p = new Preset ("regout.xpm");
943         p = new Preset ("Linear (-6dB cut)", "crossfade_out_dipped");
944         p->push_back (PresetPoint (0, 1));
945         p->push_back (PresetPoint (0.000000, 1.000000));
946         p->push_back (PresetPoint (0.166667, 0.833033));
947         p->push_back (PresetPoint (0.333333, 0.666186));
948         p->push_back (PresetPoint (0.500000, 0.499459));
949         p->push_back (PresetPoint (0.666667, 0.332853));
950         p->push_back (PresetPoint (0.833333, 0.166366));
951         p->push_back (PresetPoint (1.000000, 0.000000));
952         fade_out_presets->push_back (p);
953
954         p = new Preset ("S(1)-Curve", "crossfade_out_default");
955         p->push_back (PresetPoint (0, 1));
956         p->push_back (PresetPoint (0.1, 0.99));
957         p->push_back (PresetPoint (0.2, 0.97));
958         p->push_back (PresetPoint (0.8, 0.03));
959         p->push_back (PresetPoint (0.9, 0.01));
960         p->push_back (PresetPoint (1, 0));
961         fade_out_presets->push_back (p);
962
963         p = new Preset ("S(2)-Curve", "crossfade_out_default");
964         p->push_back (PresetPoint (0.0, 1.0));
965         p->push_back (PresetPoint (0.163, 0.678));
966         p->push_back (PresetPoint (0.055, 0.783));
967         p->push_back (PresetPoint (0.837, 0.35));
968         p->push_back (PresetPoint (0.945, 0.222));
969         p->push_back (PresetPoint (1.0, 0.0));
970         fade_out_presets->push_back (p);
971
972         // p = new Preset ("linout.xpm");
973         p = new Preset ("Constant Power (-3dB cut)", "crossfade_out_constant");
974         p->push_back (PresetPoint (0.000000, 1.000000));
975         p->push_back (PresetPoint (0.166667, 0.948859));
976         p->push_back (PresetPoint (0.333333, 0.851507));
977         p->push_back (PresetPoint (0.500000, 0.707946));
978         p->push_back (PresetPoint (0.666667, 0.518174));
979         p->push_back (PresetPoint (0.833333, 0.282192));
980         p->push_back (PresetPoint (1.000000, 0.000000));
981         fade_out_presets->push_back (p);
982         
983         if (!Profile->get_sae()) {
984                 // p = new Preset ("hiout.xpm");
985                 p = new Preset ("Slow end/cut", "crossfade_out_fast-cut");
986                 p->push_back (PresetPoint (0, 1));
987                 p->push_back (PresetPoint (0.305556, 1));
988                 p->push_back (PresetPoint (0.548611, 0.991736));
989                 p->push_back (PresetPoint (0.759259, 0.931129));
990                 p->push_back (PresetPoint (0.918981, 0.68595));
991                 p->push_back (PresetPoint (0.976852, 0.22865));
992                 p->push_back (PresetPoint (1, 0));
993                 fade_out_presets->push_back (p);
994                 
995                 // p = new Preset ("loout.xpm");
996                 p = new Preset ("Fast start/cut", "crossfade_out_transition");
997                 p->push_back (PresetPoint (0, 1));
998                 p->push_back (PresetPoint (0.023041, 0.697222));
999                 p->push_back (PresetPoint (0.0553,   0.483333));
1000                 p->push_back (PresetPoint (0.170507, 0.233333));
1001                 p->push_back (PresetPoint (0.370968, 0.0861111));
1002                 p->push_back (PresetPoint (0.610599, 0.0333333));
1003                 p->push_back (PresetPoint (1, 0));
1004                 fade_out_presets->push_back (p);
1005                 
1006                 // p = new Preset ("regout2.xpm");
1007                 p = new Preset ("Slow Fade", "crossfade_out_slow-fade");
1008                 p->push_back (PresetPoint (0, 1));
1009                 p->push_back (PresetPoint (0.080645, 0.730556));
1010                 p->push_back (PresetPoint (0.277778, 0.289256));
1011                 p->push_back (PresetPoint (0.470046, 0.152778));
1012                 p->push_back (PresetPoint (0.695853, 0.0694444));
1013                 p->push_back (PresetPoint (1, 0));
1014                 fade_out_presets->push_back (p);
1015         }
1016 }
1017
1018 void
1019 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1020 {
1021         current = wf;
1022         
1023         if (wf == In) {
1024                 
1025                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1026                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1027                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1028                 }
1029
1030                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1031                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1032                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1033                 }
1034
1035                 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1036                 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1037                 fade[Out].shading->hide();
1038                 fade[In].shading->show();
1039
1040                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1041                         (*i)->box->hide();
1042                 }
1043
1044                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1045                         (*i)->box->show ();
1046                 }
1047
1048         } else {
1049
1050                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1051                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1052                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1053                 }
1054
1055                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1056                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1057                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1058                 }
1059
1060                 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1061                 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1062                 fade[In].shading->hide();
1063                 fade[Out].shading->show();
1064
1065                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1066                         (*i)->box->hide();
1067                 }
1068                 
1069                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1070                         (*i)->box->show();
1071                 }
1072
1073         }
1074 }
1075
1076 double 
1077 CrossfadeEditor::x_coordinate (double& xfract) const
1078 {
1079         xfract = min (1.0, xfract);
1080         xfract = max (0.0, xfract);
1081
1082         return canvas_border + (xfract * effective_width());
1083 }
1084
1085 double
1086 CrossfadeEditor::y_coordinate (double& yfract) const
1087 {
1088         yfract = min (1.0, yfract);
1089         yfract = max (0.0, yfract);
1090
1091         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1092 }
1093
1094 void
1095 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1096 {
1097         gdouble ht;
1098         uint32_t nchans = region->n_channels();
1099         guint32 color;
1100         double spu;
1101
1102         if (which == In) {
1103                 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1104         } else {
1105                 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1106         }
1107
1108         ht = canvas->get_allocation().get_height() / (double) nchans;
1109         spu = xfade->length() / (double) effective_width();
1110
1111         for (uint32_t n = 0; n < nchans; ++n) {
1112                 
1113                 gdouble yoff = n * ht;
1114                 
1115                 if (region->audio_source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1116                         WaveView* waveview = new WaveView (*(canvas->root()));
1117
1118                         waveview->property_data_src() = region.get();
1119                         waveview->property_cache_updater() =  true;
1120                         waveview->property_cache() = WaveView::create_cache();
1121                         waveview->property_channel() = n;
1122                         waveview->property_length_function() = (void*) region_length_from_c;
1123                         waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1124                         waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1125                         waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1126                         waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1127                         waveview->property_x() = canvas_border;
1128                         waveview->property_y() = yoff;
1129                         waveview->property_height() = ht;
1130                         waveview->property_samples_per_unit() = spu;
1131                         waveview->property_amplitude_above_axis() = 2.0;
1132                         waveview->property_wave_color() = color;
1133                         waveview->property_fill_color() = color;
1134                         
1135                         if (which==In)
1136                                 waveview->property_region_start() = region->start();
1137                         else
1138                                 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1139
1140                         waveview->lower_to_bottom();
1141                         fade[which].waves.push_back (waveview);
1142                 }
1143         }
1144
1145         toplevel->lower_to_bottom();
1146 }
1147
1148 void
1149 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1150 {
1151         /* this should never be called, because the peak files for an xfade
1152            will be ready by the time we want them. but our API forces us
1153            to provide this, so ..
1154         */
1155         peaks_ready_connection.disconnect ();
1156         make_waves (r, which);
1157 }
1158
1159 void
1160 CrossfadeEditor::audition (Audition which)
1161 {
1162         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1163         nframes_t preroll;
1164         nframes_t postroll;
1165         nframes_t left_start_offset;
1166         nframes_t right_length;
1167         nframes_t left_length;
1168
1169         if (which != Right && preroll_button.get_active()) {
1170                 preroll = session.frame_rate() * 2;  //2 second hardcoded preroll for now
1171         } else {
1172                 preroll = 0;
1173         }
1174
1175         if (which != Left && postroll_button.get_active()) {
1176                 postroll = session.frame_rate() * 2;  //2 second hardcoded postroll for now
1177         } else {
1178                 postroll = 0;
1179         }
1180
1181         // Is there enough data for the whole preroll?
1182         left_length = xfade->length();
1183         if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1184                 left_start_offset -= preroll;
1185         } else {
1186                 preroll = left_start_offset;
1187                 left_start_offset = 0;
1188         }
1189         left_length += preroll;
1190
1191         // Is there enough data for the whole postroll?
1192         right_length = xfade->length();
1193         if ((xfade->in()->length() - right_length) > postroll) {
1194                 right_length += postroll;
1195         } else {
1196                 right_length = xfade->in()->length();
1197         }
1198
1199         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out", 
1200                                                                                                               0, Region::DefaultFlags, false)));
1201         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, right_length, "xfade in", 
1202                                                                                                                0, Region::DefaultFlags, false)));
1203         
1204         //apply a 20ms declicking fade at the start and end of auditioning
1205         left->set_fade_in_active(true);
1206         left->set_fade_in_length(session.frame_rate() / 50);
1207         right->set_fade_out_active(true);
1208         right->set_fade_out_length(session.frame_rate() / 50);
1209
1210         pl.add_region (left, 0);
1211         pl.add_region (right, 1 + preroll);
1212         
1213         if (which == Left) {
1214                 right->set_scale_amplitude (0.0);
1215         } else if (which == Right) {
1216                 left->set_scale_amplitude (0.0);
1217         }
1218
1219         /* there is only one ... */
1220         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1221
1222         session.audition_playlist ();
1223 }
1224
1225 void
1226 CrossfadeEditor::audition_both ()
1227 {
1228         audition (Both);
1229 }
1230
1231 void
1232 CrossfadeEditor::audition_left_dry ()
1233 {
1234         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left", 
1235                                                                                                               0, Region::DefaultFlags, false)));
1236         
1237         session.audition_region (left);
1238 }
1239
1240 void
1241 CrossfadeEditor::audition_left ()
1242 {
1243         audition (Left);
1244 }
1245
1246 void
1247 CrossfadeEditor::audition_right_dry ()
1248 {
1249         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in", 
1250                                                                                                                0, Region::DefaultFlags, false)));
1251         session.audition_region (right);
1252 }
1253
1254 void
1255 CrossfadeEditor::audition_right ()
1256 {
1257         audition (Right);
1258 }
1259         
1260 void
1261 CrossfadeEditor::cancel_audition ()
1262 {
1263         session.cancel_audition ();
1264 }
1265
1266 void
1267 CrossfadeEditor::audition_toggled ()
1268 {
1269         bool x;
1270
1271         if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1272
1273                 if (x) {
1274                         audition_both ();
1275                 } else {
1276                         cancel_audition ();
1277                 }
1278         }
1279 }
1280
1281 void
1282 CrossfadeEditor::audition_right_toggled ()
1283 {
1284         bool x;
1285         
1286         if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1287
1288                 if (x) {
1289                         audition_right ();
1290                 } else {
1291                         cancel_audition ();
1292                 }
1293         }
1294 }
1295
1296 void
1297 CrossfadeEditor::audition_right_dry_toggled ()
1298 {
1299         bool x;
1300
1301         if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1302
1303                 if (x) {
1304                         audition_right_dry ();
1305                 } else {
1306                         cancel_audition ();
1307                 }
1308         }
1309 }
1310
1311 void
1312 CrossfadeEditor::audition_left_toggled ()
1313 {
1314         bool x;
1315
1316         if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1317
1318                 if (x) {
1319                         audition_left ();
1320                 } else {
1321                         cancel_audition ();
1322                 }
1323         }
1324 }
1325
1326 void
1327 CrossfadeEditor::audition_left_dry_toggled ()
1328 {
1329         bool x;
1330
1331         if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1332                 
1333                 if (x) {
1334                         audition_left_dry ();
1335                 } else {
1336                         cancel_audition ();
1337                 }
1338         }
1339 }
1340
1341 bool
1342 CrossfadeEditor::on_key_press_event (GdkEventKey *ev)
1343 {
1344         return true;
1345 }
1346
1347 bool
1348 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1349 {
1350         switch (ev->keyval) {
1351         case GDK_Right:
1352                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1353                         audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1354                 } else {
1355                         audition_right_button.set_active (!audition_right_button.get_active());
1356                 }
1357                 break;
1358
1359         case GDK_Left:
1360                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1361                         audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1362                 } else {
1363                         audition_left_button.set_active (!audition_left_button.get_active());
1364                 }
1365                 break;
1366
1367         case GDK_space:
1368                 if (session.is_auditioning()) {
1369                         cancel_audition ();
1370                 } else {
1371                         audition_both_button.set_active (!audition_both_button.get_active());
1372                 }
1373                 break;
1374
1375         default:
1376                 break;
1377         }
1378
1379         return true;
1380 }