Zoom session when the mouse pointer is moved up and down during a playhead drag.
[ardour2.git] / gtk2_ardour / crossfade_edit.cc
blob0c8daafb045995826673acdb50616d103a4c61db
1 /*
2 Copyright (C) 2004 Paul Davis
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.
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.
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.
20 #include <cmath>
22 #include <sigc++/bind.h>
24 #include <gtkmm/frame.h>
25 #include <gtkmm/image.h>
26 #include <gtkmm/scrolledwindow.h>
28 #include <libgnomecanvasmm/line.h>
30 #include "pbd/memento_command.h"
31 #include "ardour/automation_list.h"
32 #include "evoral/Curve.hpp"
33 #include "ardour/crossfade.h"
34 #include "ardour/session.h"
35 #include "ardour/auditioner.h"
36 #include "ardour/audioplaylist.h"
37 #include "ardour/audiosource.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/profile.h"
41 #include <gtkmm2ext/gtk_ui.h>
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"
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57 using namespace Gtk;
58 using namespace Editing;
60 using Gtkmm2ext::Keyboard;
62 #include "i18n.h"
64 const int32_t CrossfadeEditor::Point::size = 7;
65 const double CrossfadeEditor::canvas_border = 10;
66 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
67 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
69 CrossfadeEditor::Half::Half ()
70 : line (0)
71 , normative_curve (Evoral::Parameter(GainAutomation))
72 , gain_curve (Evoral::Parameter(GainAutomation))
76 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
77 : ArdourDialog (_("Edit Crossfade")),
78 xfade (xf),
79 clear_button (_("Clear")),
80 revert_button (_("Reset")),
81 audition_both_button (_("Fade")),
82 audition_left_dry_button (_("Out (dry)")),
83 audition_left_button (_("Out")),
84 audition_right_dry_button (_("In (dry)")),
85 audition_right_button (_("In")),
87 preroll_button (_("With Pre-roll")),
88 postroll_button (_("With Post-roll")),
90 miny (my),
91 maxy (mxy),
93 fade_in_table (3, 3),
94 fade_out_table (3, 3),
96 select_in_button (_("Fade In")),
97 select_out_button (_("Fade Out")),
99 _peaks_ready_connection (0)
102 set_session (s);
104 set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
105 set_name ("CrossfadeEditWindow");
106 set_position (Gtk::WIN_POS_MOUSE);
108 add_accel_group (ActionManager::ui_manager->get_accel_group());
110 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
112 RadioButtonGroup sel_but_group = select_in_button.get_group();
113 select_out_button.set_group (sel_but_group);
114 select_out_button.set_mode (false);
115 select_in_button.set_mode (false);
117 get_action_area()->set_layout(BUTTONBOX_SPREAD);
118 get_action_area()->pack_start(clear_button);
119 get_action_area()->pack_start(revert_button);
120 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
121 ok_button = add_button ("OK", RESPONSE_ACCEPT);
123 if (fade_in_presets == 0) {
124 build_presets ();
127 point_grabbed = false;
128 toplevel = 0;
130 canvas = new ArdourCanvas::CanvasAA ();
131 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
132 canvas->set_size_request (425, 200);
134 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
135 toplevel->property_x1() = 0.0;
136 toplevel->property_y1() = 0.0;
137 toplevel->property_x2() = 10.0;
138 toplevel->property_y2() = 10.0;
139 toplevel->property_fill() = true;
140 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
141 toplevel->property_outline_pixels() = 0;
142 toplevel->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
144 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
145 fade[Out].line->property_width_pixels() = 1;
146 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
148 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
149 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
151 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
152 fade[In].line->property_width_pixels() = 1;
153 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
155 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
156 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
158 fade[In].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
159 fade[In].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
160 fade[Out].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
161 fade[Out].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
163 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
164 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
166 select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
167 select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
169 HBox* acbox = manage (new HBox);
171 audition_box.set_border_width (7);
172 audition_box.set_spacing (5);
173 audition_box.set_homogeneous (false);
174 audition_box.pack_start (audition_left_dry_button, false, false);
175 audition_box.pack_start (audition_left_button, false, false);
176 audition_box.pack_start (audition_both_button, false, false);
177 audition_box.pack_start (audition_right_button, false, false);
178 audition_box.pack_start (audition_right_dry_button, false, false);
180 Frame* audition_frame = manage (new Frame (_("Audition")));
182 audition_frame->set_name (X_("CrossfadeEditFrame"));
183 audition_frame->add (audition_box);
185 acbox->pack_start (*audition_frame, true, false);
187 Frame* canvas_frame = manage (new Frame);
188 canvas_frame->add (*canvas);
189 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
191 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
192 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
194 Image *pxmap;
195 Button* pbutton;
196 int row;
197 int col;
199 row = 1;
200 col = 0;
202 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
204 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
205 pbutton = manage (new Button);
206 pbutton->add (*pxmap);
207 pbutton->set_name ("CrossfadeEditButton");
208 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
209 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
210 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
211 fade_in_buttons.push_back (pbutton);
213 col++;
215 if (col == 2) {
216 col = 0;
217 row++;
221 row = 1;
222 col = 0;
224 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
226 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
227 pbutton = manage (new Button);
228 pbutton->add (*pxmap);
229 pbutton->set_name ("CrossfadeEditButton");
230 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
231 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
232 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
233 fade_out_buttons.push_back (pbutton);
235 col++;
237 if (col == 2) {
238 col = 0;
239 row++;
243 clear_button.set_name ("CrossfadeEditButton");
244 revert_button.set_name ("CrossfadeEditButton");
245 ok_button->set_name ("CrossfadeEditButton");
246 cancel_button->set_name ("CrossfadeEditButton");
247 preroll_button.set_name ("CrossfadeEditButton");
248 postroll_button.set_name ("CrossfadeEditButton");
249 audition_both_button.set_name ("CrossfadeEditAuditionButton");
250 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
251 audition_left_button.set_name ("CrossfadeEditAuditionButton");
252 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
253 audition_right_button.set_name ("CrossfadeEditAuditionButton");
255 clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
256 revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
257 audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
258 audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
259 audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
260 audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
261 audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
263 roll_box.pack_start (preroll_button, false, false);
264 roll_box.pack_start (postroll_button, false, false);
266 Gtk::HBox* rcenter_box = manage (new HBox);
267 rcenter_box->pack_start (roll_box, true, false);
269 VBox* vpacker2 = manage (new (VBox));
271 vpacker2->set_border_width (12);
272 vpacker2->set_spacing (7);
273 vpacker2->pack_start (*acbox, false, false);
274 vpacker2->pack_start (*rcenter_box, false, false);
276 curve_button_box.set_spacing (7);
277 curve_button_box.pack_start (fade_out_table, false, false, 12);
278 curve_button_box.pack_start (*vpacker2, false, false, 12);
279 curve_button_box.pack_start (fade_in_table, false, false, 12);
281 get_vbox()->pack_start (*canvas_frame, true, true);
282 get_vbox()->pack_start (curve_button_box, false, false);
284 /* button to allow hackers to check the actual curve values */
286 // Button* foobut = manage (new Button ("dump"));
287 // foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
288 // vpacker.pack_start (*foobut, false, false);
290 current = In;
291 set (xfade->fade_in(), In);
293 current = Out;
294 set (xfade->fade_out(), Out);
296 curve_select_clicked (In);
298 xfade->PropertyChanged.connect (state_connection, invalidator (*this), ui_bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
300 _session->AuditionActive.connect (_session_connections, invalidator (*this), ui_bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
301 show_all_children();
304 CrossfadeEditor::~CrossfadeEditor()
306 /* most objects will be destroyed when the toplevel window is. */
308 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
309 delete *i;
312 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
313 delete *i;
316 delete _peaks_ready_connection;
319 void
320 CrossfadeEditor::dump ()
322 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
323 cerr << (*i)->when << ' ' << (*i)->value << endl;
327 void
328 CrossfadeEditor::audition_state_changed (bool yn)
330 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
332 if (!yn) {
333 audition_both_button.set_active (false);
334 audition_left_button.set_active (false);
335 audition_right_button.set_active (false);
336 audition_left_dry_button.set_active (false);
337 audition_right_dry_button.set_active (false);
341 void
342 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
344 double firstx, endx;
345 ARDOUR::AutomationList::const_iterator the_end;
347 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
348 delete *i;
351 fade[which].points.clear ();
352 fade[which].gain_curve.clear ();
353 fade[which].normative_curve.clear ();
355 if (curve.empty()) {
356 goto out;
359 the_end = curve.end();
360 --the_end;
362 firstx = (*curve.begin())->when;
363 endx = (*the_end)->when;
365 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
367 double xfract = ((*i)->when - firstx) / (endx - firstx);
368 double yfract = ((*i)->value - miny) / (maxy - miny);
370 Point* p = make_point ();
372 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
373 xfract, yfract);
375 fade[which].points.push_back (p);
378 /* no need to sort because curve is already time-ordered */
380 out:
382 swap (which, current);
383 redraw ();
384 swap (which, current);
387 bool
388 CrossfadeEditor::curve_event (GdkEvent* event)
390 /* treat it like a toplevel event */
392 return canvas_event (event);
395 bool
396 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
399 if (point->curve != fade[current].line) {
400 return FALSE;
403 switch (event->type) {
404 case GDK_BUTTON_PRESS:
405 point_grabbed = true;
406 break;
407 case GDK_BUTTON_RELEASE:
408 point_grabbed = false;
410 if (Keyboard::is_delete_event (&event->button)) {
411 fade[current].points.remove (point);
412 delete point;
415 redraw ();
416 break;
418 case GDK_MOTION_NOTIFY:
419 if (point_grabbed) {
420 double new_x, new_y;
422 /* can't drag first or last points horizontally or vertically */
424 if (point == fade[current].points.front() || point == fade[current].points.back()) {
425 new_x = point->x;
426 new_y = point->y;
427 } else {
428 new_x = (event->motion.x - canvas_border)/effective_width();
429 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
432 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
433 new_x, new_y);
434 redraw ();
436 break;
437 default:
438 break;
440 return TRUE;
443 bool
444 CrossfadeEditor::canvas_event (GdkEvent* event)
446 switch (event->type) {
447 case GDK_BUTTON_PRESS:
448 add_control_point ((event->button.x - canvas_border)/effective_width(),
449 1.0 - ((event->button.y - canvas_border)/effective_height()));
450 return true;
451 break;
452 default:
453 break;
455 return false;
458 CrossfadeEditor::Point::~Point()
460 delete box;
463 CrossfadeEditor::Point*
464 CrossfadeEditor::make_point ()
466 Point* p = new Point;
468 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
469 p->box->property_fill() = true;
470 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
471 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
472 p->box->property_outline_pixels() = 1;
474 p->curve = fade[current].line;
476 p->box->signal_event().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
478 return p;
481 void
482 CrossfadeEditor::add_control_point (double x, double y)
484 PointSorter cmp;
486 /* enforce end point x location */
488 if (fade[current].points.empty()) {
489 x = 0.0;
490 } else if (fade[current].points.size() == 1) {
491 x = 1.0;
494 Point* p = make_point ();
496 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
498 fade[current].points.push_back (p);
499 fade[current].points.sort (cmp);
501 redraw ();
504 void
505 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
507 if ( xfract < 0.0 ) {
508 xfract = 0.0;
509 } else if ( xfract > 1.0 ) {
510 xfract = 1.0;
513 if ( yfract < 0.0 ) {
514 yfract = 0.0;
515 } else if ( yfract > 1.0 ) {
516 yfract = 1.0;
519 const double half_size = rint(size/2.0);
520 double x1 = nx - half_size;
521 double x2 = nx + half_size;
523 box->property_x1() = x1;
524 box->property_x2() = x2;
526 box->property_y1() = ny - half_size;
527 box->property_y2() = ny + half_size;
529 x = xfract;
530 y = yfract;
533 void
534 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
536 if (toplevel) {
537 toplevel->property_x1() = 0.0;
538 toplevel->property_y1() = 0.0;
539 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
540 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
543 canvas->set_scroll_region (0.0, 0.0,
544 canvas->get_allocation().get_width(),
545 canvas->get_allocation().get_height());
547 Point* end = make_point ();
548 PointSorter cmp;
550 if (fade[In].points.size() > 1) {
551 Point* old_end = fade[In].points.back();
552 fade[In].points.pop_back ();
553 end->move_to (x_coordinate (old_end->x),
554 y_coordinate (old_end->y),
555 old_end->x, old_end->y);
556 delete old_end;
557 } else {
558 double x = 1.0;
559 double y = 0.5;
560 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
564 fade[In].points.push_back (end);
565 fade[In].points.sort (cmp);
567 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
568 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
569 (*i)->x, (*i)->y);
572 end = make_point ();
574 if (fade[Out].points.size() > 1) {
575 Point* old_end = fade[Out].points.back();
576 fade[Out].points.pop_back ();
577 end->move_to (x_coordinate (old_end->x),
578 y_coordinate (old_end->y),
579 old_end->x, old_end->y);
580 delete old_end;
581 } else {
582 double x = 1.0;
583 double y = 0.5;
584 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
588 fade[Out].points.push_back (end);
589 fade[Out].points.sort (cmp);
591 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
592 (*i)->move_to (x_coordinate ((*i)->x),
593 y_coordinate ((*i)->y),
594 (*i)->x, (*i)->y);
597 WhichFade old_current = current;
598 current = In;
599 redraw ();
600 current = Out;
601 redraw ();
602 current = old_current;
604 double spu = xfade->length() / (double) effective_width();
606 if (fade[In].waves.empty()) {
607 make_waves (xfade->in(), In);
610 if (fade[Out].waves.empty()) {
611 make_waves (xfade->out(), Out);
614 double ht;
615 vector<ArdourCanvas::WaveView*>::iterator i;
616 uint32_t n;
618 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
620 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
621 double yoff;
623 yoff = n * ht;
625 (*i)->property_y() = yoff;
626 (*i)->property_height() = ht;
627 (*i)->property_samples_per_unit() = spu;
630 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
632 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
633 double yoff;
635 yoff = n * ht;
637 (*i)->property_y() = yoff;
638 (*i)->property_height() = ht;
639 (*i)->property_samples_per_unit() = spu;
645 void
646 CrossfadeEditor::xfade_changed (const PropertyChange&)
648 set (xfade->fade_in(), In);
649 set (xfade->fade_out(), Out);
652 void
653 CrossfadeEditor::redraw ()
655 if (canvas->get_allocation().get_width() < 2) {
656 return;
659 framecnt_t len = xfade->length ();
661 fade[current].normative_curve.clear ();
662 fade[current].gain_curve.clear ();
664 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
665 fade[current].normative_curve.add ((*i)->x, (*i)->y);
666 double offset;
667 if (current==In)
668 offset = xfade->in()->start();
669 else
670 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
671 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
675 size_t npoints = (size_t) effective_width();
676 float vec[npoints];
678 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
680 ArdourCanvas::Points pts;
681 ArdourCanvas::Points spts;
683 while (pts.size() < npoints) {
684 pts.push_back (Gnome::Art::Point (0,0));
687 while (spts.size() < npoints + 3) {
688 spts.push_back (Gnome::Art::Point (0,0));
691 /* the shade coordinates *MUST* be in anti-clockwise order.
694 if (current == In) {
696 /* lower left */
698 spts[0].set_x (canvas_border);
699 spts[0].set_y (effective_height() + canvas_border);
701 /* lower right */
703 spts[1].set_x (effective_width() + canvas_border);
704 spts[1].set_y (effective_height() + canvas_border);
706 /* upper right */
708 spts[2].set_x (effective_width() + canvas_border);
709 spts[2].set_y (canvas_border);
712 } else {
714 /* upper left */
716 spts[0].set_x (canvas_border);
717 spts[0].set_y (canvas_border);
719 /* lower left */
721 spts[1].set_x (canvas_border);
722 spts[1].set_y (effective_height() + canvas_border);
724 /* lower right */
726 spts[2].set_x (effective_width() + canvas_border);
727 spts[2].set_y (effective_height() + canvas_border);
731 size_t last_spt = (npoints + 3) - 1;
733 for (size_t i = 0; i < npoints; ++i) {
735 double y = vec[i];
737 pts[i].set_x (canvas_border + i);
738 pts[i].set_y (y_coordinate (y));
740 spts[last_spt - i].set_x (canvas_border + i);
741 spts[last_spt - i].set_y (pts[i].get_y());
744 fade[current].line->property_points() = pts;
745 fade[current].shading->property_points() = spts;
747 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
748 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
752 void
753 CrossfadeEditor::apply_preset (Preset *preset)
756 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
758 if (current != wf) {
760 if (wf == In) {
761 select_in_button.clicked();
762 } else {
763 select_out_button.clicked();
766 curve_select_clicked (wf);
769 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
770 delete *i;
773 fade[current].points.clear ();
775 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
776 Point* p = make_point ();
777 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
778 (*i).x, (*i).y);
779 fade[current].points.push_back (p);
782 redraw ();
785 void
786 CrossfadeEditor::apply ()
788 _session->begin_reversible_command (_("Edit crossfade"));
790 XMLNode& before = xfade->get_state ();
792 _apply_to (xfade);
794 _session->add_command (new MementoCommand<Crossfade> (*xfade.get(), &before, &xfade->get_state ()));
795 _session->commit_reversible_command ();
798 void
799 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
801 ARDOUR::AutomationList& in (xf->fade_in());
802 ARDOUR::AutomationList& out (xf->fade_out());
804 /* IN */
807 ARDOUR::AutomationList::const_iterator the_end = in.end();
808 --the_end;
810 double firstx = (*in.begin())->when;
811 double endx = (*the_end)->when;
812 double miny = in.get_min_y ();
813 double maxy = in.get_max_y ();
815 in.freeze ();
816 in.clear ();
818 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
820 double when = firstx + ((*i)->x * (endx - firstx));
821 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
822 in.add (when, value);
825 /* OUT */
827 the_end = out.end();
828 --the_end;
830 firstx = (*out.begin())->when;
831 endx = (*the_end)->when;
832 miny = out.get_min_y ();
833 maxy = out.get_max_y ();
835 out.freeze ();
836 out.clear ();
838 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
840 double when = firstx + ((*i)->x * (endx - firstx));
841 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
842 out.add (when, value);
845 in.thaw ();
846 out.thaw ();
849 void
850 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
852 _apply_to (xfade);
853 xfade->set_active (true);
854 xfade->fade_in().curve().solve ();
855 xfade->fade_out().curve().solve ();
858 void
859 CrossfadeEditor::clear ()
861 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
862 delete *i;
865 fade[current].points.clear ();
867 redraw ();
870 void
871 CrossfadeEditor::reset ()
873 set (xfade->fade_in(), In);
874 set (xfade->fade_out(), Out);
876 curve_select_clicked (current);
879 void
880 CrossfadeEditor::build_presets ()
882 Preset* p;
884 fade_in_presets = new Presets;
885 fade_out_presets = new Presets;
887 /* FADE IN */
889 p = new Preset ("Linear (-6dB)", "crossfade-in-linear");
890 p->push_back (PresetPoint (0, 0));
891 p->push_back (PresetPoint (0.000000, 0.000000));
892 p->push_back (PresetPoint (0.166667, 0.166366));
893 p->push_back (PresetPoint (0.333333, 0.332853));
894 p->push_back (PresetPoint (0.500000, 0.499459));
895 p->push_back (PresetPoint (0.666667, 0.666186));
896 p->push_back (PresetPoint (0.833333, 0.833033));
897 p->push_back (PresetPoint (1.000000, 1.000000));
898 fade_in_presets->push_back (p);
900 p = new Preset ("S(1)-curve", "crossfade-in-S1");
901 p->push_back (PresetPoint (0, 0));
902 p->push_back (PresetPoint (0.1, 0.01));
903 p->push_back (PresetPoint (0.2, 0.03));
904 p->push_back (PresetPoint (0.8, 0.97));
905 p->push_back (PresetPoint (0.9, 0.99));
906 p->push_back (PresetPoint (1, 1));
907 fade_in_presets->push_back (p);
909 p = new Preset ("S(2)-curve", "crossfade-in-S2");
910 p->push_back (PresetPoint (0.0, 0.0));
911 p->push_back (PresetPoint (0.055, 0.222));
912 p->push_back (PresetPoint (0.163, 0.35));
913 p->push_back (PresetPoint (0.837, 0.678));
914 p->push_back (PresetPoint (0.945, 0.783));
915 p->push_back (PresetPoint (1.0, 1.0));
916 fade_in_presets->push_back (p);
918 p = new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
920 p->push_back (PresetPoint (0.000000, 0.000000));
921 p->push_back (PresetPoint (0.166667, 0.282192));
922 p->push_back (PresetPoint (0.333333, 0.518174));
923 p->push_back (PresetPoint (0.500000, 0.707946));
924 p->push_back (PresetPoint (0.666667, 0.851507));
925 p->push_back (PresetPoint (0.833333, 0.948859));
926 p->push_back (PresetPoint (1.000000, 1.000000));
928 fade_in_presets->push_back (p);
930 if (!Profile->get_sae()) {
932 p = new Preset ("Short cut", "crossfade-in-short-cut");
933 p->push_back (PresetPoint (0, 0));
934 p->push_back (PresetPoint (0.389401, 0.0333333));
935 p->push_back (PresetPoint (0.629032, 0.0861111));
936 p->push_back (PresetPoint (0.829493, 0.233333));
937 p->push_back (PresetPoint (0.9447, 0.483333));
938 p->push_back (PresetPoint (0.976959, 0.697222));
939 p->push_back (PresetPoint (1, 1));
940 fade_in_presets->push_back (p);
942 p = new Preset ("Slow cut", "crossfade-in-slow-cut");
943 p->push_back (PresetPoint (0, 0));
944 p->push_back (PresetPoint (0.304147, 0.0694444));
945 p->push_back (PresetPoint (0.529954, 0.152778));
946 p->push_back (PresetPoint (0.725806, 0.333333));
947 p->push_back (PresetPoint (0.847926, 0.558333));
948 p->push_back (PresetPoint (0.919355, 0.730556));
949 p->push_back (PresetPoint (1, 1));
950 fade_in_presets->push_back (p);
952 p = new Preset ("Fast cut", "crossfade-in-fast-cut");
953 p->push_back (PresetPoint (0, 0));
954 p->push_back (PresetPoint (0.0737327, 0.308333));
955 p->push_back (PresetPoint (0.246544, 0.658333));
956 p->push_back (PresetPoint (0.470046, 0.886111));
957 p->push_back (PresetPoint (0.652074, 0.972222));
958 p->push_back (PresetPoint (0.771889, 0.988889));
959 p->push_back (PresetPoint (1, 1));
960 fade_in_presets->push_back (p);
962 p = new Preset ("Long cut", "crossfade-in-long-cut");
963 p->push_back (PresetPoint (0, 0));
964 p->push_back (PresetPoint (0.0207373, 0.197222));
965 p->push_back (PresetPoint (0.0645161, 0.525));
966 p->push_back (PresetPoint (0.152074, 0.802778));
967 p->push_back (PresetPoint (0.276498, 0.919444));
968 p->push_back (PresetPoint (0.481567, 0.980556));
969 p->push_back (PresetPoint (0.767281, 1));
970 p->push_back (PresetPoint (1, 1));
971 fade_in_presets->push_back (p);
974 /* FADE OUT */
976 // p = new Preset ("regout.xpm");
977 p = new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
978 p->push_back (PresetPoint (0, 1));
979 p->push_back (PresetPoint (0.000000, 1.000000));
980 p->push_back (PresetPoint (0.166667, 0.833033));
981 p->push_back (PresetPoint (0.333333, 0.666186));
982 p->push_back (PresetPoint (0.500000, 0.499459));
983 p->push_back (PresetPoint (0.666667, 0.332853));
984 p->push_back (PresetPoint (0.833333, 0.166366));
985 p->push_back (PresetPoint (1.000000, 0.000000));
986 fade_out_presets->push_back (p);
988 p = new Preset ("S(1)-Curve", "crossfade-out-S1");
989 p->push_back (PresetPoint (0, 1));
990 p->push_back (PresetPoint (0.1, 0.99));
991 p->push_back (PresetPoint (0.2, 0.97));
992 p->push_back (PresetPoint (0.8, 0.03));
993 p->push_back (PresetPoint (0.9, 0.01));
994 p->push_back (PresetPoint (1, 0));
995 fade_out_presets->push_back (p);
997 p = new Preset ("S(2)-Curve", "crossfade-out-S2");
998 p->push_back (PresetPoint (0.0, 1.0));
999 p->push_back (PresetPoint (0.163, 0.678));
1000 p->push_back (PresetPoint (0.055, 0.783));
1001 p->push_back (PresetPoint (0.837, 0.35));
1002 p->push_back (PresetPoint (0.945, 0.222));
1003 p->push_back (PresetPoint (1.0, 0.0));
1004 fade_out_presets->push_back (p);
1006 // p = new Preset ("linout.xpm");
1007 p = new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
1008 p->push_back (PresetPoint (0.000000, 1.000000));
1009 p->push_back (PresetPoint (0.166667, 0.948859));
1010 p->push_back (PresetPoint (0.333333, 0.851507));
1011 p->push_back (PresetPoint (0.500000, 0.707946));
1012 p->push_back (PresetPoint (0.666667, 0.518174));
1013 p->push_back (PresetPoint (0.833333, 0.282192));
1014 p->push_back (PresetPoint (1.000000, 0.000000));
1015 fade_out_presets->push_back (p);
1017 if (!Profile->get_sae()) {
1018 // p = new Preset ("hiout.xpm");
1019 p = new Preset ("Short cut", "crossfade-out-short-cut");
1020 p->push_back (PresetPoint (0, 1));
1021 p->push_back (PresetPoint (0.305556, 1));
1022 p->push_back (PresetPoint (0.548611, 0.991736));
1023 p->push_back (PresetPoint (0.759259, 0.931129));
1024 p->push_back (PresetPoint (0.918981, 0.68595));
1025 p->push_back (PresetPoint (0.976852, 0.22865));
1026 p->push_back (PresetPoint (1, 0));
1027 fade_out_presets->push_back (p);
1029 p = new Preset ("Slow cut", "crossfade-out-slow-cut");
1030 p->push_back (PresetPoint (0, 1));
1031 p->push_back (PresetPoint (0.228111, 0.988889));
1032 p->push_back (PresetPoint (0.347926, 0.972222));
1033 p->push_back (PresetPoint (0.529954, 0.886111));
1034 p->push_back (PresetPoint (0.753456, 0.658333));
1035 p->push_back (PresetPoint (0.9262673, 0.308333));
1036 p->push_back (PresetPoint (1, 0));
1037 fade_out_presets->push_back (p);
1039 p = new Preset ("Fast cut", "crossfade-out-fast-cut");
1040 p->push_back (PresetPoint (0, 1));
1041 p->push_back (PresetPoint (0.080645, 0.730556));
1042 p->push_back (PresetPoint (0.277778, 0.289256));
1043 p->push_back (PresetPoint (0.470046, 0.152778));
1044 p->push_back (PresetPoint (0.695853, 0.0694444));
1045 p->push_back (PresetPoint (1, 0));
1046 fade_out_presets->push_back (p);
1048 // p = new Preset ("loout.xpm");
1049 p = new Preset ("Long cut", "crossfade-out-long-cut");
1050 p->push_back (PresetPoint (0, 1));
1051 p->push_back (PresetPoint (0.023041, 0.697222));
1052 p->push_back (PresetPoint (0.0553, 0.483333));
1053 p->push_back (PresetPoint (0.170507, 0.233333));
1054 p->push_back (PresetPoint (0.370968, 0.0861111));
1055 p->push_back (PresetPoint (0.610599, 0.0333333));
1056 p->push_back (PresetPoint (1, 0));
1057 fade_out_presets->push_back (p);
1062 void
1063 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1065 current = wf;
1067 if (wf == In) {
1069 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1070 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1071 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1074 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1075 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1076 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1079 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1080 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1081 fade[Out].shading->hide();
1082 fade[In].shading->show();
1084 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1085 (*i)->box->hide();
1088 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1089 (*i)->box->show ();
1092 } else {
1094 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1095 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1096 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1099 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1100 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1101 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1104 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1105 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1106 fade[In].shading->hide();
1107 fade[Out].shading->show();
1109 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1110 (*i)->box->hide();
1113 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1114 (*i)->box->show();
1120 double
1121 CrossfadeEditor::x_coordinate (double& xfract) const
1123 xfract = min (1.0, xfract);
1124 xfract = max (0.0, xfract);
1126 return canvas_border + (xfract * effective_width());
1129 double
1130 CrossfadeEditor::y_coordinate (double& yfract) const
1132 yfract = min (1.0, yfract);
1133 yfract = max (0.0, yfract);
1135 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1138 void
1139 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1141 gdouble ht;
1142 uint32_t nchans = region->n_channels();
1143 guint32 color;
1144 double spu;
1146 if (which == In) {
1147 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1148 } else {
1149 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1152 ht = canvas->get_allocation().get_height() / (double) nchans;
1153 spu = xfade->length() / (double) effective_width();
1155 delete _peaks_ready_connection;
1156 _peaks_ready_connection = 0;
1158 for (uint32_t n = 0; n < nchans; ++n) {
1160 gdouble yoff = n * ht;
1162 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1163 WaveView* waveview = new WaveView (*(canvas->root()));
1165 waveview->property_data_src() = region.get();
1166 waveview->property_cache_updater() = true;
1167 waveview->property_cache() = WaveView::create_cache();
1168 waveview->property_channel() = n;
1169 waveview->property_length_function() = (void*) region_length_from_c;
1170 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1171 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1172 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1173 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1174 waveview->property_x() = canvas_border;
1175 waveview->property_y() = yoff;
1176 waveview->property_height() = ht;
1177 waveview->property_samples_per_unit() = spu;
1178 waveview->property_amplitude_above_axis() = 2.0;
1179 waveview->property_wave_color() = color;
1180 waveview->property_fill_color() = color;
1182 if (which==In)
1183 waveview->property_region_start() = region->start();
1184 else
1185 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1187 waveview->lower_to_bottom();
1188 fade[which].waves.push_back (waveview);
1192 toplevel->lower_to_bottom();
1195 void
1196 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1198 boost::shared_ptr<AudioRegion> r (wr.lock());
1200 if (!r) {
1201 return;
1204 /* this should never be called, because the peak files for an xfade
1205 will be ready by the time we want them. but our API forces us
1206 to provide this, so ..
1208 delete _peaks_ready_connection;
1209 _peaks_ready_connection = 0;
1211 make_waves (r, which);
1214 void
1215 CrossfadeEditor::audition (Audition which)
1217 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1218 framecnt_t preroll;
1219 framecnt_t postroll;
1220 framecnt_t left_start_offset;
1221 framecnt_t right_length;
1222 framecnt_t left_length;
1224 if (which != Right && preroll_button.get_active()) {
1225 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1226 } else {
1227 preroll = 0;
1230 if (which != Left && postroll_button.get_active()) {
1231 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1232 } else {
1233 postroll = 0;
1236 // Is there enough data for the whole preroll?
1237 left_length = xfade->length();
1238 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1239 left_start_offset -= preroll;
1240 } else {
1241 preroll = left_start_offset;
1242 left_start_offset = 0;
1244 left_length += preroll;
1246 // Is there enough data for the whole postroll?
1247 right_length = xfade->length();
1248 if ((xfade->in()->length() - right_length) > postroll) {
1249 right_length += postroll;
1250 } else {
1251 right_length = xfade->in()->length();
1254 PropertyList left_plist;
1255 PropertyList right_plist;
1258 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1259 left_plist.add (ARDOUR::Properties::length, left_length);
1260 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1261 left_plist.add (ARDOUR::Properties::layer, 0);
1262 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1264 right_plist.add (ARDOUR::Properties::start, 0);
1265 right_plist.add (ARDOUR::Properties::length, right_length);
1266 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1267 right_plist.add (ARDOUR::Properties::layer, 0);
1268 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1270 if (which == Left) {
1271 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1272 } else if (which == Right) {
1273 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1276 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1277 (RegionFactory::create (xfade->out(), left_plist, false)));
1278 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1279 (RegionFactory::create (xfade->in(), right_plist, false)));
1281 // apply a 20ms declicking fade at the start and end of auditioning
1282 // XXX this should really be a property
1284 left->set_fade_in_length (_session->frame_rate() / 50);
1285 right->set_fade_out_length (_session->frame_rate() / 50);
1287 pl.add_region (left, 0);
1288 pl.add_region (right, 1 + preroll);
1290 /* there is only one ... */
1291 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1293 _session->audition_playlist ();
1296 void
1297 CrossfadeEditor::audition_both ()
1299 audition (Both);
1302 void
1303 CrossfadeEditor::audition_left_dry ()
1305 PropertyList plist;
1307 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1308 plist.add (ARDOUR::Properties::length, xfade->length());
1309 plist.add (ARDOUR::Properties::name, string("xfade left"));
1310 plist.add (ARDOUR::Properties::layer, 0);
1312 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1313 (RegionFactory::create (xfade->out(), plist, false)));
1315 _session->audition_region (left);
1318 void
1319 CrossfadeEditor::audition_left ()
1321 audition (Left);
1324 void
1325 CrossfadeEditor::audition_right_dry ()
1327 PropertyList plist;
1329 plist.add (ARDOUR::Properties::start, 0);
1330 plist.add (ARDOUR::Properties::length, xfade->length());
1331 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1332 plist.add (ARDOUR::Properties::layer, 0);
1334 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1335 (RegionFactory::create (xfade->in(), plist, false)));
1337 _session->audition_region (right);
1340 void
1341 CrossfadeEditor::audition_right ()
1343 audition (Right);
1346 void
1347 CrossfadeEditor::cancel_audition ()
1349 _session->cancel_audition ();
1352 void
1353 CrossfadeEditor::audition_toggled ()
1355 bool x;
1357 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1359 if (x) {
1360 audition_both ();
1361 } else {
1362 cancel_audition ();
1367 void
1368 CrossfadeEditor::audition_right_toggled ()
1370 bool x;
1372 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1374 if (x) {
1375 audition_right ();
1376 } else {
1377 cancel_audition ();
1382 void
1383 CrossfadeEditor::audition_right_dry_toggled ()
1385 bool x;
1387 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1389 if (x) {
1390 audition_right_dry ();
1391 } else {
1392 cancel_audition ();
1397 void
1398 CrossfadeEditor::audition_left_toggled ()
1400 bool x;
1402 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1404 if (x) {
1405 audition_left ();
1406 } else {
1407 cancel_audition ();
1412 void
1413 CrossfadeEditor::audition_left_dry_toggled ()
1415 bool x;
1417 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1419 if (x) {
1420 audition_left_dry ();
1421 } else {
1422 cancel_audition ();
1427 bool
1428 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1430 return true;
1433 bool
1434 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1436 switch (ev->keyval) {
1437 case GDK_Right:
1438 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1439 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1440 } else {
1441 audition_right_button.set_active (!audition_right_button.get_active());
1443 break;
1445 case GDK_Left:
1446 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1447 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1448 } else {
1449 audition_left_button.set_active (!audition_left_button.get_active());
1451 break;
1453 case GDK_space:
1454 if (_session->is_auditioning()) {
1455 cancel_audition ();
1456 } else {
1457 audition_both_button.set_active (!audition_both_button.get_active());
1459 break;
1461 default:
1462 break;
1465 return true;