Remove erroneous assert which I added earlier.
[ardour2.git] / gtk2_ardour / crossfade_edit.cc
blob7ec19e97ad27a1bdf40e8cfe8a87a1abc542ea89
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;
813 in.freeze ();
814 in.clear ();
816 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
818 double when = firstx + ((*i)->x * (endx - firstx));
819 double value = (*i)->y;
820 in.add (when, value);
823 /* OUT */
825 the_end = out.end();
826 --the_end;
828 firstx = (*out.begin())->when;
829 endx = (*the_end)->when;
831 out.freeze ();
832 out.clear ();
834 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
836 double when = firstx + ((*i)->x * (endx - firstx));
837 double value = (*i)->y;
838 out.add (when, value);
841 in.thaw ();
842 out.thaw ();
845 void
846 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
848 _apply_to (xfade);
849 xfade->set_active (true);
850 xfade->fade_in().curve().solve ();
851 xfade->fade_out().curve().solve ();
854 void
855 CrossfadeEditor::clear ()
857 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
858 delete *i;
861 fade[current].points.clear ();
863 redraw ();
866 void
867 CrossfadeEditor::reset ()
869 set (xfade->fade_in(), In);
870 set (xfade->fade_out(), Out);
872 curve_select_clicked (current);
875 void
876 CrossfadeEditor::build_presets ()
878 Preset* p;
880 fade_in_presets = new Presets;
881 fade_out_presets = new Presets;
883 /* FADE IN */
885 p = new Preset ("Linear (-6dB)", "crossfade-in-linear");
886 p->push_back (PresetPoint (0, 0));
887 p->push_back (PresetPoint (0.000000, 0.000000));
888 p->push_back (PresetPoint (0.166667, 0.166366));
889 p->push_back (PresetPoint (0.333333, 0.332853));
890 p->push_back (PresetPoint (0.500000, 0.499459));
891 p->push_back (PresetPoint (0.666667, 0.666186));
892 p->push_back (PresetPoint (0.833333, 0.833033));
893 p->push_back (PresetPoint (1.000000, 1.000000));
894 fade_in_presets->push_back (p);
896 p = new Preset ("S(1)-curve", "crossfade-in-S1");
897 p->push_back (PresetPoint (0, 0));
898 p->push_back (PresetPoint (0.1, 0.01));
899 p->push_back (PresetPoint (0.2, 0.03));
900 p->push_back (PresetPoint (0.8, 0.97));
901 p->push_back (PresetPoint (0.9, 0.99));
902 p->push_back (PresetPoint (1, 1));
903 fade_in_presets->push_back (p);
905 p = new Preset ("S(2)-curve", "crossfade-in-S2");
906 p->push_back (PresetPoint (0.0, 0.0));
907 p->push_back (PresetPoint (0.055, 0.222));
908 p->push_back (PresetPoint (0.163, 0.35));
909 p->push_back (PresetPoint (0.837, 0.678));
910 p->push_back (PresetPoint (0.945, 0.783));
911 p->push_back (PresetPoint (1.0, 1.0));
912 fade_in_presets->push_back (p);
914 p = new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
916 p->push_back (PresetPoint (0.000000, 0.000000));
917 p->push_back (PresetPoint (0.166667, 0.282192));
918 p->push_back (PresetPoint (0.333333, 0.518174));
919 p->push_back (PresetPoint (0.500000, 0.707946));
920 p->push_back (PresetPoint (0.666667, 0.851507));
921 p->push_back (PresetPoint (0.833333, 0.948859));
922 p->push_back (PresetPoint (1.000000, 1.000000));
924 fade_in_presets->push_back (p);
926 if (!Profile->get_sae()) {
928 p = new Preset ("Short cut", "crossfade-in-short-cut");
929 p->push_back (PresetPoint (0, 0));
930 p->push_back (PresetPoint (0.389401, 0.0333333));
931 p->push_back (PresetPoint (0.629032, 0.0861111));
932 p->push_back (PresetPoint (0.829493, 0.233333));
933 p->push_back (PresetPoint (0.9447, 0.483333));
934 p->push_back (PresetPoint (0.976959, 0.697222));
935 p->push_back (PresetPoint (1, 1));
936 fade_in_presets->push_back (p);
938 p = new Preset ("Slow cut", "crossfade-in-slow-cut");
939 p->push_back (PresetPoint (0, 0));
940 p->push_back (PresetPoint (0.304147, 0.0694444));
941 p->push_back (PresetPoint (0.529954, 0.152778));
942 p->push_back (PresetPoint (0.725806, 0.333333));
943 p->push_back (PresetPoint (0.847926, 0.558333));
944 p->push_back (PresetPoint (0.919355, 0.730556));
945 p->push_back (PresetPoint (1, 1));
946 fade_in_presets->push_back (p);
948 p = new Preset ("Fast cut", "crossfade-in-fast-cut");
949 p->push_back (PresetPoint (0, 0));
950 p->push_back (PresetPoint (0.0737327, 0.308333));
951 p->push_back (PresetPoint (0.246544, 0.658333));
952 p->push_back (PresetPoint (0.470046, 0.886111));
953 p->push_back (PresetPoint (0.652074, 0.972222));
954 p->push_back (PresetPoint (0.771889, 0.988889));
955 p->push_back (PresetPoint (1, 1));
956 fade_in_presets->push_back (p);
958 p = new Preset ("Long cut", "crossfade-in-long-cut");
959 p->push_back (PresetPoint (0, 0));
960 p->push_back (PresetPoint (0.0207373, 0.197222));
961 p->push_back (PresetPoint (0.0645161, 0.525));
962 p->push_back (PresetPoint (0.152074, 0.802778));
963 p->push_back (PresetPoint (0.276498, 0.919444));
964 p->push_back (PresetPoint (0.481567, 0.980556));
965 p->push_back (PresetPoint (0.767281, 1));
966 p->push_back (PresetPoint (1, 1));
967 fade_in_presets->push_back (p);
970 /* FADE OUT */
972 // p = new Preset ("regout.xpm");
973 p = new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
974 p->push_back (PresetPoint (0, 1));
975 p->push_back (PresetPoint (0.000000, 1.000000));
976 p->push_back (PresetPoint (0.166667, 0.833033));
977 p->push_back (PresetPoint (0.333333, 0.666186));
978 p->push_back (PresetPoint (0.500000, 0.499459));
979 p->push_back (PresetPoint (0.666667, 0.332853));
980 p->push_back (PresetPoint (0.833333, 0.166366));
981 p->push_back (PresetPoint (1.000000, 0.000000));
982 fade_out_presets->push_back (p);
984 p = new Preset ("S(1)-Curve", "crossfade-out-S1");
985 p->push_back (PresetPoint (0, 1));
986 p->push_back (PresetPoint (0.1, 0.99));
987 p->push_back (PresetPoint (0.2, 0.97));
988 p->push_back (PresetPoint (0.8, 0.03));
989 p->push_back (PresetPoint (0.9, 0.01));
990 p->push_back (PresetPoint (1, 0));
991 fade_out_presets->push_back (p);
993 p = new Preset ("S(2)-Curve", "crossfade-out-S2");
994 p->push_back (PresetPoint (0.0, 1.0));
995 p->push_back (PresetPoint (0.163, 0.678));
996 p->push_back (PresetPoint (0.055, 0.783));
997 p->push_back (PresetPoint (0.837, 0.35));
998 p->push_back (PresetPoint (0.945, 0.222));
999 p->push_back (PresetPoint (1.0, 0.0));
1000 fade_out_presets->push_back (p);
1002 // p = new Preset ("linout.xpm");
1003 p = new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
1004 p->push_back (PresetPoint (0.000000, 1.000000));
1005 p->push_back (PresetPoint (0.166667, 0.948859));
1006 p->push_back (PresetPoint (0.333333, 0.851507));
1007 p->push_back (PresetPoint (0.500000, 0.707946));
1008 p->push_back (PresetPoint (0.666667, 0.518174));
1009 p->push_back (PresetPoint (0.833333, 0.282192));
1010 p->push_back (PresetPoint (1.000000, 0.000000));
1011 fade_out_presets->push_back (p);
1013 if (!Profile->get_sae()) {
1014 // p = new Preset ("hiout.xpm");
1015 p = new Preset ("Short cut", "crossfade-out-short-cut");
1016 p->push_back (PresetPoint (0, 1));
1017 p->push_back (PresetPoint (0.305556, 1));
1018 p->push_back (PresetPoint (0.548611, 0.991736));
1019 p->push_back (PresetPoint (0.759259, 0.931129));
1020 p->push_back (PresetPoint (0.918981, 0.68595));
1021 p->push_back (PresetPoint (0.976852, 0.22865));
1022 p->push_back (PresetPoint (1, 0));
1023 fade_out_presets->push_back (p);
1025 p = new Preset ("Slow cut", "crossfade-out-slow-cut");
1026 p->push_back (PresetPoint (0, 1));
1027 p->push_back (PresetPoint (0.228111, 0.988889));
1028 p->push_back (PresetPoint (0.347926, 0.972222));
1029 p->push_back (PresetPoint (0.529954, 0.886111));
1030 p->push_back (PresetPoint (0.753456, 0.658333));
1031 p->push_back (PresetPoint (0.9262673, 0.308333));
1032 p->push_back (PresetPoint (1, 0));
1033 fade_out_presets->push_back (p);
1035 p = new Preset ("Fast cut", "crossfade-out-fast-cut");
1036 p->push_back (PresetPoint (0, 1));
1037 p->push_back (PresetPoint (0.080645, 0.730556));
1038 p->push_back (PresetPoint (0.277778, 0.289256));
1039 p->push_back (PresetPoint (0.470046, 0.152778));
1040 p->push_back (PresetPoint (0.695853, 0.0694444));
1041 p->push_back (PresetPoint (1, 0));
1042 fade_out_presets->push_back (p);
1044 // p = new Preset ("loout.xpm");
1045 p = new Preset ("Long cut", "crossfade-out-long-cut");
1046 p->push_back (PresetPoint (0, 1));
1047 p->push_back (PresetPoint (0.023041, 0.697222));
1048 p->push_back (PresetPoint (0.0553, 0.483333));
1049 p->push_back (PresetPoint (0.170507, 0.233333));
1050 p->push_back (PresetPoint (0.370968, 0.0861111));
1051 p->push_back (PresetPoint (0.610599, 0.0333333));
1052 p->push_back (PresetPoint (1, 0));
1053 fade_out_presets->push_back (p);
1058 void
1059 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1061 current = wf;
1063 if (wf == In) {
1065 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1066 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1067 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1070 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1071 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1072 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1075 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1076 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1077 fade[Out].shading->hide();
1078 fade[In].shading->show();
1080 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1081 (*i)->box->hide();
1084 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1085 (*i)->box->show ();
1088 } else {
1090 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1091 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1092 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1095 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1096 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1097 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1100 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1101 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1102 fade[In].shading->hide();
1103 fade[Out].shading->show();
1105 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1106 (*i)->box->hide();
1109 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1110 (*i)->box->show();
1116 double
1117 CrossfadeEditor::x_coordinate (double& xfract) const
1119 xfract = min (1.0, xfract);
1120 xfract = max (0.0, xfract);
1122 return canvas_border + (xfract * effective_width());
1125 double
1126 CrossfadeEditor::y_coordinate (double& yfract) const
1128 yfract = min (1.0, yfract);
1129 yfract = max (0.0, yfract);
1131 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1134 void
1135 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1137 gdouble ht;
1138 uint32_t nchans = region->n_channels();
1139 guint32 color;
1140 double spu;
1142 if (which == In) {
1143 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1144 } else {
1145 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1148 ht = canvas->get_allocation().get_height() / (double) nchans;
1149 spu = xfade->length() / (double) effective_width();
1151 delete _peaks_ready_connection;
1152 _peaks_ready_connection = 0;
1154 for (uint32_t n = 0; n < nchans; ++n) {
1156 gdouble yoff = n * ht;
1158 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1159 WaveView* waveview = new WaveView (*(canvas->root()));
1161 waveview->property_data_src() = region.get();
1162 waveview->property_cache_updater() = true;
1163 waveview->property_cache() = WaveView::create_cache();
1164 waveview->property_channel() = n;
1165 waveview->property_length_function() = (void*) region_length_from_c;
1166 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1167 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1168 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1169 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1170 waveview->property_x() = canvas_border;
1171 waveview->property_y() = yoff;
1172 waveview->property_height() = ht;
1173 waveview->property_samples_per_unit() = spu;
1174 waveview->property_amplitude_above_axis() = 2.0;
1175 waveview->property_wave_color() = color;
1176 waveview->property_fill_color() = color;
1178 if (which==In)
1179 waveview->property_region_start() = region->start();
1180 else
1181 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1183 waveview->lower_to_bottom();
1184 fade[which].waves.push_back (waveview);
1188 toplevel->lower_to_bottom();
1191 void
1192 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1194 boost::shared_ptr<AudioRegion> r (wr.lock());
1196 if (!r) {
1197 return;
1200 /* this should never be called, because the peak files for an xfade
1201 will be ready by the time we want them. but our API forces us
1202 to provide this, so ..
1204 delete _peaks_ready_connection;
1205 _peaks_ready_connection = 0;
1207 make_waves (r, which);
1210 void
1211 CrossfadeEditor::audition (Audition which)
1213 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1214 framecnt_t preroll;
1215 framecnt_t postroll;
1216 framecnt_t left_start_offset;
1217 framecnt_t right_length;
1218 framecnt_t left_length;
1220 if (which != Right && preroll_button.get_active()) {
1221 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1222 } else {
1223 preroll = 0;
1226 if (which != Left && postroll_button.get_active()) {
1227 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1228 } else {
1229 postroll = 0;
1232 // Is there enough data for the whole preroll?
1233 left_length = xfade->length();
1234 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1235 left_start_offset -= preroll;
1236 } else {
1237 preroll = left_start_offset;
1238 left_start_offset = 0;
1240 left_length += preroll;
1242 // Is there enough data for the whole postroll?
1243 right_length = xfade->length();
1244 if ((xfade->in()->length() - right_length) > postroll) {
1245 right_length += postroll;
1246 } else {
1247 right_length = xfade->in()->length();
1250 PropertyList left_plist;
1251 PropertyList right_plist;
1254 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1255 left_plist.add (ARDOUR::Properties::length, left_length);
1256 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1257 left_plist.add (ARDOUR::Properties::layer, 0);
1258 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1260 right_plist.add (ARDOUR::Properties::start, 0);
1261 right_plist.add (ARDOUR::Properties::length, right_length);
1262 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1263 right_plist.add (ARDOUR::Properties::layer, 0);
1264 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1266 if (which == Left) {
1267 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1268 } else if (which == Right) {
1269 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1272 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1273 (RegionFactory::create (xfade->out(), left_plist, false)));
1274 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1275 (RegionFactory::create (xfade->in(), right_plist, false)));
1277 // apply a 20ms declicking fade at the start and end of auditioning
1278 // XXX this should really be a property
1280 left->set_fade_in_length (_session->frame_rate() / 50);
1281 right->set_fade_out_length (_session->frame_rate() / 50);
1283 pl.add_region (left, 0);
1284 pl.add_region (right, 1 + preroll);
1286 /* there is only one ... */
1287 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1289 _session->audition_playlist ();
1292 void
1293 CrossfadeEditor::audition_both ()
1295 audition (Both);
1298 void
1299 CrossfadeEditor::audition_left_dry ()
1301 PropertyList plist;
1303 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1304 plist.add (ARDOUR::Properties::length, xfade->length());
1305 plist.add (ARDOUR::Properties::name, string("xfade left"));
1306 plist.add (ARDOUR::Properties::layer, 0);
1308 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1309 (RegionFactory::create (xfade->out(), plist, false)));
1311 _session->audition_region (left);
1314 void
1315 CrossfadeEditor::audition_left ()
1317 audition (Left);
1320 void
1321 CrossfadeEditor::audition_right_dry ()
1323 PropertyList plist;
1325 plist.add (ARDOUR::Properties::start, 0);
1326 plist.add (ARDOUR::Properties::length, xfade->length());
1327 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1328 plist.add (ARDOUR::Properties::layer, 0);
1330 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1331 (RegionFactory::create (xfade->in(), plist, false)));
1333 _session->audition_region (right);
1336 void
1337 CrossfadeEditor::audition_right ()
1339 audition (Right);
1342 void
1343 CrossfadeEditor::cancel_audition ()
1345 _session->cancel_audition ();
1348 void
1349 CrossfadeEditor::audition_toggled ()
1351 bool x;
1353 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1355 if (x) {
1356 audition_both ();
1357 } else {
1358 cancel_audition ();
1363 void
1364 CrossfadeEditor::audition_right_toggled ()
1366 bool x;
1368 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1370 if (x) {
1371 audition_right ();
1372 } else {
1373 cancel_audition ();
1378 void
1379 CrossfadeEditor::audition_right_dry_toggled ()
1381 bool x;
1383 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1385 if (x) {
1386 audition_right_dry ();
1387 } else {
1388 cancel_audition ();
1393 void
1394 CrossfadeEditor::audition_left_toggled ()
1396 bool x;
1398 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1400 if (x) {
1401 audition_left ();
1402 } else {
1403 cancel_audition ();
1408 void
1409 CrossfadeEditor::audition_left_dry_toggled ()
1411 bool x;
1413 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1415 if (x) {
1416 audition_left_dry ();
1417 } else {
1418 cancel_audition ();
1423 bool
1424 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1426 return true;
1429 bool
1430 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1432 switch (ev->keyval) {
1433 case GDK_Right:
1434 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1435 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1436 } else {
1437 audition_right_button.set_active (!audition_right_button.get_active());
1439 break;
1441 case GDK_Left:
1442 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1443 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1444 } else {
1445 audition_left_button.set_active (!audition_left_button.get_active());
1447 break;
1449 case GDK_space:
1450 if (_session->is_auditioning()) {
1451 cancel_audition ();
1452 } else {
1453 audition_both_button.set_active (!audition_both_button.get_active());
1455 break;
1457 default:
1458 break;
1461 return true;