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