fix inverse solo push to work properly in both exclusive and non-exclusive solo modes
[ardour2.git] / gtk2_ardour / crossfade_edit.cc
blob382f6afd09b114b5ad0392a39f64811d03ae3751
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 "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/region_factory.h"
38 #include "ardour/profile.h"
40 #include <gtkmm2ext/gtk_ui.h>
42 #include "ardour_ui.h"
43 #include "crossfade_edit.h"
44 #include "rgb_macros.h"
45 #include "keyboard.h"
46 #include "utils.h"
47 #include "gui_thread.h"
48 #include "canvas_impl.h"
49 #include "simplerect.h"
50 #include "waveview.h"
51 #include "actions.h"
53 using namespace std;
54 using namespace ARDOUR;
55 using namespace PBD;
56 using namespace Gtk;
57 using namespace Editing;
59 using Gtkmm2ext::Keyboard;
61 #include "i18n.h"
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;
68 CrossfadeEditor::Half::Half ()
69 : line (0)
70 , normative_curve (Evoral::Parameter(GainAutomation))
71 , gain_curve (Evoral::Parameter(GainAutomation))
75 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
76 : ArdourDialog (_("Edit Crossfade")),
77 xfade (xf),
78 clear_button (_("Clear")),
79 revert_button (_("Reset")),
80 audition_both_button (_("Fade")),
81 audition_left_dry_button (_("Out (dry)")),
82 audition_left_button (_("Out")),
83 audition_right_dry_button (_("In (dry)")),
84 audition_right_button (_("In")),
86 preroll_button (_("With Pre-roll")),
87 postroll_button (_("With Post-roll")),
89 miny (my),
90 maxy (mxy),
92 fade_in_table (3, 3),
93 fade_out_table (3, 3),
95 select_in_button (_("Fade In")),
96 select_out_button (_("Fade Out")),
98 _peaks_ready_connection (0)
101 set_session (s);
103 set_wmclass (X_("ardour_automationedit"), "Ardour");
104 set_name ("CrossfadeEditWindow");
105 set_position (Gtk::WIN_POS_MOUSE);
107 add_accel_group (ActionManager::ui_manager->get_accel_group());
109 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
111 RadioButtonGroup sel_but_group = select_in_button.get_group();
112 select_out_button.set_group (sel_but_group);
113 select_out_button.set_mode (false);
114 select_in_button.set_mode (false);
116 get_action_area()->set_layout(BUTTONBOX_SPREAD);
117 get_action_area()->pack_start(clear_button);
118 get_action_area()->pack_start(revert_button);
119 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
120 ok_button = add_button ("OK", RESPONSE_ACCEPT);
122 if (fade_in_presets == 0) {
123 build_presets ();
126 point_grabbed = false;
127 toplevel = 0;
129 canvas = new ArdourCanvas::CanvasAA ();
130 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
131 canvas->set_size_request (425, 200);
133 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
134 toplevel->property_x1() = 0.0;
135 toplevel->property_y1() = 0.0;
136 toplevel->property_x2() = 10.0;
137 toplevel->property_y2() = 10.0;
138 toplevel->property_fill() = true;
139 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
140 toplevel->property_outline_pixels() = 0;
141 toplevel->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
143 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
144 fade[Out].line->property_width_pixels() = 1;
145 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
147 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
148 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
150 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
151 fade[In].line->property_width_pixels() = 1;
152 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
154 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
155 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
157 fade[In].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
158 fade[In].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
159 fade[Out].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
160 fade[Out].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
162 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
163 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
165 select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
166 select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
168 HBox* acbox = manage (new HBox);
170 audition_box.set_border_width (7);
171 audition_box.set_spacing (5);
172 audition_box.set_homogeneous (false);
173 audition_box.pack_start (audition_left_dry_button, false, false);
174 audition_box.pack_start (audition_left_button, false, false);
175 audition_box.pack_start (audition_both_button, false, false);
176 audition_box.pack_start (audition_right_button, false, false);
177 audition_box.pack_start (audition_right_dry_button, false, false);
179 Frame* audition_frame = manage (new Frame (_("Audition")));
181 audition_frame->set_name (X_("CrossfadeEditFrame"));
182 audition_frame->add (audition_box);
184 acbox->pack_start (*audition_frame, true, false);
186 Frame* canvas_frame = manage (new Frame);
187 canvas_frame->add (*canvas);
188 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
190 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
191 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
193 Image *pxmap;
194 Button* pbutton;
195 int row;
196 int col;
198 row = 1;
199 col = 0;
201 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
203 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
204 pbutton = manage (new Button);
205 pbutton->add (*pxmap);
206 pbutton->set_name ("CrossfadeEditButton");
207 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
208 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
209 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
210 fade_in_buttons.push_back (pbutton);
212 col++;
214 if (col == 2) {
215 col = 0;
216 row++;
220 row = 1;
221 col = 0;
223 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
225 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
226 pbutton = manage (new Button);
227 pbutton->add (*pxmap);
228 pbutton->set_name ("CrossfadeEditButton");
229 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
230 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
231 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
232 fade_out_buttons.push_back (pbutton);
234 col++;
236 if (col == 2) {
237 col = 0;
238 row++;
242 clear_button.set_name ("CrossfadeEditButton");
243 revert_button.set_name ("CrossfadeEditButton");
244 ok_button->set_name ("CrossfadeEditButton");
245 cancel_button->set_name ("CrossfadeEditButton");
246 preroll_button.set_name ("CrossfadeEditButton");
247 postroll_button.set_name ("CrossfadeEditButton");
248 audition_both_button.set_name ("CrossfadeEditAuditionButton");
249 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
250 audition_left_button.set_name ("CrossfadeEditAuditionButton");
251 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
252 audition_right_button.set_name ("CrossfadeEditAuditionButton");
254 clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
255 revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
256 audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
257 audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
258 audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
259 audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
260 audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
262 roll_box.pack_start (preroll_button, false, false);
263 roll_box.pack_start (postroll_button, false, false);
265 Gtk::HBox* rcenter_box = manage (new HBox);
266 rcenter_box->pack_start (roll_box, true, false);
268 VBox* vpacker2 = manage (new (VBox));
270 vpacker2->set_border_width (12);
271 vpacker2->set_spacing (7);
272 vpacker2->pack_start (*acbox, false, false);
273 vpacker2->pack_start (*rcenter_box, false, false);
275 curve_button_box.set_spacing (7);
276 curve_button_box.pack_start (fade_out_table, false, false, 12);
277 curve_button_box.pack_start (*vpacker2, false, false, 12);
278 curve_button_box.pack_start (fade_in_table, false, false, 12);
280 get_vbox()->pack_start (*canvas_frame, true, true);
281 get_vbox()->pack_start (curve_button_box, false, false);
283 /* button to allow hackers to check the actual curve values */
285 // Button* foobut = manage (new Button ("dump"));
286 // foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
287 // vpacker.pack_start (*foobut, false, false);
289 current = In;
290 set (xfade->fade_in(), In);
292 current = Out;
293 set (xfade->fade_out(), Out);
295 curve_select_clicked (In);
297 xfade->PropertyChanged.connect (state_connection, invalidator (*this), ui_bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
299 _session->AuditionActive.connect (_session_connections, invalidator (*this), ui_bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
300 show_all_children();
303 CrossfadeEditor::~CrossfadeEditor()
305 /* most objects will be destroyed when the toplevel window is. */
307 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
308 delete *i;
311 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
312 delete *i;
315 delete _peaks_ready_connection;
318 void
319 CrossfadeEditor::dump ()
321 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
322 cerr << (*i)->when << ' ' << (*i)->value << endl;
326 void
327 CrossfadeEditor::audition_state_changed (bool yn)
329 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
331 if (!yn) {
332 audition_both_button.set_active (false);
333 audition_left_button.set_active (false);
334 audition_right_button.set_active (false);
335 audition_left_dry_button.set_active (false);
336 audition_right_dry_button.set_active (false);
340 void
341 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
343 double firstx, endx;
344 ARDOUR::AutomationList::const_iterator the_end;
346 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
347 delete *i;
350 fade[which].points.clear ();
351 fade[which].gain_curve.clear ();
352 fade[which].normative_curve.clear ();
354 if (curve.empty()) {
355 goto out;
358 the_end = curve.end();
359 --the_end;
361 firstx = (*curve.begin())->when;
362 endx = (*the_end)->when;
364 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
366 double xfract = ((*i)->when - firstx) / (endx - firstx);
367 double yfract = ((*i)->value - miny) / (maxy - miny);
369 Point* p = make_point ();
371 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
372 xfract, yfract);
374 fade[which].points.push_back (p);
377 /* no need to sort because curve is already time-ordered */
379 out:
381 swap (which, current);
382 redraw ();
383 swap (which, current);
386 bool
387 CrossfadeEditor::curve_event (GdkEvent* event)
389 /* treat it like a toplevel event */
391 return canvas_event (event);
394 bool
395 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
398 if (point->curve != fade[current].line) {
399 return FALSE;
402 switch (event->type) {
403 case GDK_BUTTON_PRESS:
404 point_grabbed = true;
405 break;
406 case GDK_BUTTON_RELEASE:
407 point_grabbed = false;
409 if (Keyboard::is_delete_event (&event->button)) {
410 fade[current].points.remove (point);
411 delete point;
414 redraw ();
415 break;
417 case GDK_MOTION_NOTIFY:
418 if (point_grabbed) {
419 double new_x, new_y;
421 /* can't drag first or last points horizontally */
423 if (point == fade[current].points.front() || point == fade[current].points.back()) {
424 new_x = point->x;
425 } else {
426 new_x = (event->motion.x - canvas_border)/effective_width();
429 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
430 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
431 new_x, new_y);
432 redraw ();
434 break;
435 default:
436 break;
438 return TRUE;
441 bool
442 CrossfadeEditor::canvas_event (GdkEvent* event)
444 switch (event->type) {
445 case GDK_BUTTON_PRESS:
446 add_control_point ((event->button.x - canvas_border)/effective_width(),
447 1.0 - ((event->button.y - canvas_border)/effective_height()));
448 return true;
449 break;
450 default:
451 break;
453 return false;
456 CrossfadeEditor::Point::~Point()
458 delete box;
461 CrossfadeEditor::Point*
462 CrossfadeEditor::make_point ()
464 Point* p = new Point;
466 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
467 p->box->property_fill() = true;
468 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
469 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
470 p->box->property_outline_pixels() = 1;
472 p->curve = fade[current].line;
474 p->box->signal_event().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
476 return p;
479 void
480 CrossfadeEditor::add_control_point (double x, double y)
482 PointSorter cmp;
484 /* enforce end point x location */
486 if (fade[current].points.empty()) {
487 x = 0.0;
488 } else if (fade[current].points.size() == 1) {
489 x = 1.0;
492 Point* p = make_point ();
494 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
496 fade[current].points.push_back (p);
497 fade[current].points.sort (cmp);
499 redraw ();
502 void
503 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
505 if ( xfract < 0.0 ) {
506 xfract = 0.0;
507 } else if ( xfract > 1.0 ) {
508 xfract = 1.0;
511 if ( yfract < 0.0 ) {
512 yfract = 0.0;
513 } else if ( yfract > 1.0 ) {
514 yfract = 1.0;
517 const double half_size = rint(size/2.0);
518 double x1 = nx - half_size;
519 double x2 = nx + half_size;
521 box->property_x1() = x1;
522 box->property_x2() = x2;
524 box->property_y1() = ny - half_size;
525 box->property_y2() = ny + half_size;
527 x = xfract;
528 y = yfract;
531 void
532 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
534 if (toplevel) {
535 toplevel->property_x1() = 0.0;
536 toplevel->property_y1() = 0.0;
537 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
538 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
541 canvas->set_scroll_region (0.0, 0.0,
542 canvas->get_allocation().get_width(),
543 canvas->get_allocation().get_height());
545 Point* end = make_point ();
546 PointSorter cmp;
548 if (fade[In].points.size() > 1) {
549 Point* old_end = fade[In].points.back();
550 fade[In].points.pop_back ();
551 end->move_to (x_coordinate (old_end->x),
552 y_coordinate (old_end->y),
553 old_end->x, old_end->y);
554 delete old_end;
555 } else {
556 double x = 1.0;
557 double y = 0.5;
558 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
562 fade[In].points.push_back (end);
563 fade[In].points.sort (cmp);
565 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
566 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
567 (*i)->x, (*i)->y);
570 end = make_point ();
572 if (fade[Out].points.size() > 1) {
573 Point* old_end = fade[Out].points.back();
574 fade[Out].points.pop_back ();
575 end->move_to (x_coordinate (old_end->x),
576 y_coordinate (old_end->y),
577 old_end->x, old_end->y);
578 delete old_end;
579 } else {
580 double x = 1.0;
581 double y = 0.5;
582 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
586 fade[Out].points.push_back (end);
587 fade[Out].points.sort (cmp);
589 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
590 (*i)->move_to (x_coordinate ((*i)->x),
591 y_coordinate ((*i)->y),
592 (*i)->x, (*i)->y);
595 WhichFade old_current = current;
596 current = In;
597 redraw ();
598 current = Out;
599 redraw ();
600 current = old_current;
602 double spu = xfade->length() / (double) effective_width();
604 if (fade[In].waves.empty()) {
605 make_waves (xfade->in(), In);
608 if (fade[Out].waves.empty()) {
609 make_waves (xfade->out(), Out);
612 double ht;
613 vector<ArdourCanvas::WaveView*>::iterator i;
614 uint32_t n;
616 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
618 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
619 double yoff;
621 yoff = n * ht;
623 (*i)->property_y() = yoff;
624 (*i)->property_height() = ht;
625 (*i)->property_samples_per_unit() = spu;
628 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
630 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
631 double yoff;
633 yoff = n * ht;
635 (*i)->property_y() = yoff;
636 (*i)->property_height() = ht;
637 (*i)->property_samples_per_unit() = spu;
643 void
644 CrossfadeEditor::xfade_changed (const PropertyChange&)
646 set (xfade->fade_in(), In);
647 set (xfade->fade_out(), Out);
650 void
651 CrossfadeEditor::redraw ()
653 if (canvas->get_allocation().get_width() < 2) {
654 return;
657 nframes_t len = xfade->length ();
659 fade[current].normative_curve.clear ();
660 fade[current].gain_curve.clear ();
662 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
663 fade[current].normative_curve.add ((*i)->x, (*i)->y);
664 double offset;
665 if (current==In)
666 offset = xfade->in()->start();
667 else
668 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
669 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
673 size_t npoints = (size_t) effective_width();
674 float vec[npoints];
676 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
678 ArdourCanvas::Points pts;
679 ArdourCanvas::Points spts;
681 while (pts.size() < npoints) {
682 pts.push_back (Gnome::Art::Point (0,0));
685 while (spts.size() < npoints + 3) {
686 spts.push_back (Gnome::Art::Point (0,0));
689 /* the shade coordinates *MUST* be in anti-clockwise order.
692 if (current == In) {
694 /* lower left */
696 spts[0].set_x (canvas_border);
697 spts[0].set_y (effective_height() + canvas_border);
699 /* lower right */
701 spts[1].set_x (effective_width() + canvas_border);
702 spts[1].set_y (effective_height() + canvas_border);
704 /* upper right */
706 spts[2].set_x (effective_width() + canvas_border);
707 spts[2].set_y (canvas_border);
710 } else {
712 /* upper left */
714 spts[0].set_x (canvas_border);
715 spts[0].set_y (canvas_border);
717 /* lower left */
719 spts[1].set_x (canvas_border);
720 spts[1].set_y (effective_height() + canvas_border);
722 /* lower right */
724 spts[2].set_x (effective_width() + canvas_border);
725 spts[2].set_y (effective_height() + canvas_border);
729 size_t last_spt = (npoints + 3) - 1;
731 for (size_t i = 0; i < npoints; ++i) {
733 double y = vec[i];
735 pts[i].set_x (canvas_border + i);
736 pts[i].set_y (y_coordinate (y));
738 spts[last_spt - i].set_x (canvas_border + i);
739 spts[last_spt - i].set_y (pts[i].get_y());
742 fade[current].line->property_points() = pts;
743 fade[current].shading->property_points() = spts;
745 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
746 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
750 void
751 CrossfadeEditor::apply_preset (Preset *preset)
754 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
756 if (current != wf) {
758 if (wf == In) {
759 select_in_button.clicked();
760 } else {
761 select_out_button.clicked();
764 curve_select_clicked (wf);
767 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
768 delete *i;
771 fade[current].points.clear ();
773 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
774 Point* p = make_point ();
775 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
776 (*i).x, (*i).y);
777 fade[current].points.push_back (p);
780 redraw ();
783 void
784 CrossfadeEditor::apply ()
786 _apply_to (xfade);
789 void
790 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
792 ARDOUR::AutomationList& in (xf->fade_in());
793 ARDOUR::AutomationList& out (xf->fade_out());
795 /* IN */
798 ARDOUR::AutomationList::const_iterator the_end = in.end();
799 --the_end;
801 double firstx = (*in.begin())->when;
802 double endx = (*the_end)->when;
803 double miny = in.get_min_y ();
804 double maxy = in.get_max_y ();
806 in.freeze ();
807 in.clear ();
809 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
811 double when = firstx + ((*i)->x * (endx - firstx));
812 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
813 in.add (when, value);
816 /* OUT */
818 the_end = out.end();
819 --the_end;
821 firstx = (*out.begin())->when;
822 endx = (*the_end)->when;
823 miny = out.get_min_y ();
824 maxy = out.get_max_y ();
826 out.freeze ();
827 out.clear ();
829 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
831 double when = firstx + ((*i)->x * (endx - firstx));
832 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
833 out.add (when, value);
836 in.thaw ();
837 out.thaw ();
840 void
841 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
843 _apply_to (xfade);
844 xfade->set_active (true);
845 xfade->fade_in().curve().solve ();
846 xfade->fade_out().curve().solve ();
849 void
850 CrossfadeEditor::clear ()
852 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
853 delete *i;
856 fade[current].points.clear ();
858 redraw ();
861 void
862 CrossfadeEditor::reset ()
864 set (xfade->fade_in(), In);
865 set (xfade->fade_out(), Out);
867 curve_select_clicked (current);
870 void
871 CrossfadeEditor::build_presets ()
873 Preset* p;
875 fade_in_presets = new Presets;
876 fade_out_presets = new Presets;
878 /* FADE IN */
880 p = new Preset ("Linear (-6dB)", "crossfade-in-linear");
881 p->push_back (PresetPoint (0, 0));
882 p->push_back (PresetPoint (0.000000, 0.000000));
883 p->push_back (PresetPoint (0.166667, 0.166366));
884 p->push_back (PresetPoint (0.333333, 0.332853));
885 p->push_back (PresetPoint (0.500000, 0.499459));
886 p->push_back (PresetPoint (0.666667, 0.666186));
887 p->push_back (PresetPoint (0.833333, 0.833033));
888 p->push_back (PresetPoint (1.000000, 1.000000));
889 fade_in_presets->push_back (p);
891 p = new Preset ("S(1)-curve", "crossfade-in-S1");
892 p->push_back (PresetPoint (0, 0));
893 p->push_back (PresetPoint (0.1, 0.01));
894 p->push_back (PresetPoint (0.2, 0.03));
895 p->push_back (PresetPoint (0.8, 0.97));
896 p->push_back (PresetPoint (0.9, 0.99));
897 p->push_back (PresetPoint (1, 1));
898 fade_in_presets->push_back (p);
900 p = new Preset ("S(2)-curve", "crossfade-in-S2");
901 p->push_back (PresetPoint (0.0, 0.0));
902 p->push_back (PresetPoint (0.055, 0.222));
903 p->push_back (PresetPoint (0.163, 0.35));
904 p->push_back (PresetPoint (0.837, 0.678));
905 p->push_back (PresetPoint (0.945, 0.783));
906 p->push_back (PresetPoint (1.0, 1.0));
907 fade_in_presets->push_back (p);
909 p = new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
911 p->push_back (PresetPoint (0.000000, 0.000000));
912 p->push_back (PresetPoint (0.166667, 0.282192));
913 p->push_back (PresetPoint (0.333333, 0.518174));
914 p->push_back (PresetPoint (0.500000, 0.707946));
915 p->push_back (PresetPoint (0.666667, 0.851507));
916 p->push_back (PresetPoint (0.833333, 0.948859));
917 p->push_back (PresetPoint (1.000000, 1.000000));
919 fade_in_presets->push_back (p);
921 if (!Profile->get_sae()) {
923 p = new Preset ("Short cut", "crossfade-in-short-cut");
924 p->push_back (PresetPoint (0, 0));
925 p->push_back (PresetPoint (0.389401, 0.0333333));
926 p->push_back (PresetPoint (0.629032, 0.0861111));
927 p->push_back (PresetPoint (0.829493, 0.233333));
928 p->push_back (PresetPoint (0.9447, 0.483333));
929 p->push_back (PresetPoint (0.976959, 0.697222));
930 p->push_back (PresetPoint (1, 1));
931 fade_in_presets->push_back (p);
933 p = new Preset ("Slow cut", "crossfade-in-slow-cut");
934 p->push_back (PresetPoint (0, 0));
935 p->push_back (PresetPoint (0.304147, 0.0694444));
936 p->push_back (PresetPoint (0.529954, 0.152778));
937 p->push_back (PresetPoint (0.725806, 0.333333));
938 p->push_back (PresetPoint (0.847926, 0.558333));
939 p->push_back (PresetPoint (0.919355, 0.730556));
940 p->push_back (PresetPoint (1, 1));
941 fade_in_presets->push_back (p);
943 p = new Preset ("Fast cut", "crossfade-in-fast-cut");
944 p->push_back (PresetPoint (0, 0));
945 p->push_back (PresetPoint (0.0737327, 0.308333));
946 p->push_back (PresetPoint (0.246544, 0.658333));
947 p->push_back (PresetPoint (0.470046, 0.886111));
948 p->push_back (PresetPoint (0.652074, 0.972222));
949 p->push_back (PresetPoint (0.771889, 0.988889));
950 p->push_back (PresetPoint (1, 1));
951 fade_in_presets->push_back (p);
953 p = new Preset ("Long cut", "crossfade-in-long-cut");
954 p->push_back (PresetPoint (0, 0));
955 p->push_back (PresetPoint (0.0207373, 0.197222));
956 p->push_back (PresetPoint (0.0645161, 0.525));
957 p->push_back (PresetPoint (0.152074, 0.802778));
958 p->push_back (PresetPoint (0.276498, 0.919444));
959 p->push_back (PresetPoint (0.481567, 0.980556));
960 p->push_back (PresetPoint (0.767281, 1));
961 p->push_back (PresetPoint (1, 1));
962 fade_in_presets->push_back (p);
965 /* FADE OUT */
967 // p = new Preset ("regout.xpm");
968 p = new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
969 p->push_back (PresetPoint (0, 1));
970 p->push_back (PresetPoint (0.000000, 1.000000));
971 p->push_back (PresetPoint (0.166667, 0.833033));
972 p->push_back (PresetPoint (0.333333, 0.666186));
973 p->push_back (PresetPoint (0.500000, 0.499459));
974 p->push_back (PresetPoint (0.666667, 0.332853));
975 p->push_back (PresetPoint (0.833333, 0.166366));
976 p->push_back (PresetPoint (1.000000, 0.000000));
977 fade_out_presets->push_back (p);
979 p = new Preset ("S(1)-Curve", "crossfade-out-S1");
980 p->push_back (PresetPoint (0, 1));
981 p->push_back (PresetPoint (0.1, 0.99));
982 p->push_back (PresetPoint (0.2, 0.97));
983 p->push_back (PresetPoint (0.8, 0.03));
984 p->push_back (PresetPoint (0.9, 0.01));
985 p->push_back (PresetPoint (1, 0));
986 fade_out_presets->push_back (p);
988 p = new Preset ("S(2)-Curve", "crossfade-out-S2");
989 p->push_back (PresetPoint (0.0, 1.0));
990 p->push_back (PresetPoint (0.163, 0.678));
991 p->push_back (PresetPoint (0.055, 0.783));
992 p->push_back (PresetPoint (0.837, 0.35));
993 p->push_back (PresetPoint (0.945, 0.222));
994 p->push_back (PresetPoint (1.0, 0.0));
995 fade_out_presets->push_back (p);
997 // p = new Preset ("linout.xpm");
998 p = new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
999 p->push_back (PresetPoint (0.000000, 1.000000));
1000 p->push_back (PresetPoint (0.166667, 0.948859));
1001 p->push_back (PresetPoint (0.333333, 0.851507));
1002 p->push_back (PresetPoint (0.500000, 0.707946));
1003 p->push_back (PresetPoint (0.666667, 0.518174));
1004 p->push_back (PresetPoint (0.833333, 0.282192));
1005 p->push_back (PresetPoint (1.000000, 0.000000));
1006 fade_out_presets->push_back (p);
1008 if (!Profile->get_sae()) {
1009 // p = new Preset ("hiout.xpm");
1010 p = new Preset ("Short cut", "crossfade-out-short-cut");
1011 p->push_back (PresetPoint (0, 1));
1012 p->push_back (PresetPoint (0.305556, 1));
1013 p->push_back (PresetPoint (0.548611, 0.991736));
1014 p->push_back (PresetPoint (0.759259, 0.931129));
1015 p->push_back (PresetPoint (0.918981, 0.68595));
1016 p->push_back (PresetPoint (0.976852, 0.22865));
1017 p->push_back (PresetPoint (1, 0));
1018 fade_out_presets->push_back (p);
1020 p = new Preset ("Slow cut", "crossfade-out-slow-cut");
1021 p->push_back (PresetPoint (0, 1));
1022 p->push_back (PresetPoint (0.228111, 0.988889));
1023 p->push_back (PresetPoint (0.347926, 0.972222));
1024 p->push_back (PresetPoint (0.529954, 0.886111));
1025 p->push_back (PresetPoint (0.753456, 0.658333));
1026 p->push_back (PresetPoint (0.9262673, 0.308333));
1027 p->push_back (PresetPoint (1, 0));
1028 fade_out_presets->push_back (p);
1030 p = new Preset ("Fast cut", "crossfade-out-fast-cut");
1031 p->push_back (PresetPoint (0, 1));
1032 p->push_back (PresetPoint (0.080645, 0.730556));
1033 p->push_back (PresetPoint (0.277778, 0.289256));
1034 p->push_back (PresetPoint (0.470046, 0.152778));
1035 p->push_back (PresetPoint (0.695853, 0.0694444));
1036 p->push_back (PresetPoint (1, 0));
1037 fade_out_presets->push_back (p);
1039 // p = new Preset ("loout.xpm");
1040 p = new Preset ("Long cut", "crossfade-out-long-cut");
1041 p->push_back (PresetPoint (0, 1));
1042 p->push_back (PresetPoint (0.023041, 0.697222));
1043 p->push_back (PresetPoint (0.0553, 0.483333));
1044 p->push_back (PresetPoint (0.170507, 0.233333));
1045 p->push_back (PresetPoint (0.370968, 0.0861111));
1046 p->push_back (PresetPoint (0.610599, 0.0333333));
1047 p->push_back (PresetPoint (1, 0));
1048 fade_out_presets->push_back (p);
1053 void
1054 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1056 current = wf;
1058 if (wf == In) {
1060 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1061 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1062 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1065 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1066 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1067 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1070 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1071 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1072 fade[Out].shading->hide();
1073 fade[In].shading->show();
1075 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1076 (*i)->box->hide();
1079 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1080 (*i)->box->show ();
1083 } else {
1085 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1086 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1087 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1090 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1091 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1092 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1095 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1096 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1097 fade[In].shading->hide();
1098 fade[Out].shading->show();
1100 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1101 (*i)->box->hide();
1104 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1105 (*i)->box->show();
1111 double
1112 CrossfadeEditor::x_coordinate (double& xfract) const
1114 xfract = min (1.0, xfract);
1115 xfract = max (0.0, xfract);
1117 return canvas_border + (xfract * effective_width());
1120 double
1121 CrossfadeEditor::y_coordinate (double& yfract) const
1123 yfract = min (1.0, yfract);
1124 yfract = max (0.0, yfract);
1126 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1129 void
1130 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1132 gdouble ht;
1133 uint32_t nchans = region->n_channels();
1134 guint32 color;
1135 double spu;
1137 if (which == In) {
1138 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1139 } else {
1140 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1143 ht = canvas->get_allocation().get_height() / (double) nchans;
1144 spu = xfade->length() / (double) effective_width();
1146 delete _peaks_ready_connection;
1147 _peaks_ready_connection = 0;
1149 for (uint32_t n = 0; n < nchans; ++n) {
1151 gdouble yoff = n * ht;
1153 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1154 WaveView* waveview = new WaveView (*(canvas->root()));
1156 waveview->property_data_src() = region.get();
1157 waveview->property_cache_updater() = true;
1158 waveview->property_cache() = WaveView::create_cache();
1159 waveview->property_channel() = n;
1160 waveview->property_length_function() = (void*) region_length_from_c;
1161 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1162 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1163 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1164 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1165 waveview->property_x() = canvas_border;
1166 waveview->property_y() = yoff;
1167 waveview->property_height() = ht;
1168 waveview->property_samples_per_unit() = spu;
1169 waveview->property_amplitude_above_axis() = 2.0;
1170 waveview->property_wave_color() = color;
1171 waveview->property_fill_color() = color;
1173 if (which==In)
1174 waveview->property_region_start() = region->start();
1175 else
1176 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1178 waveview->lower_to_bottom();
1179 fade[which].waves.push_back (waveview);
1183 toplevel->lower_to_bottom();
1186 void
1187 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1189 boost::shared_ptr<AudioRegion> r (wr.lock());
1191 if (!r) {
1192 return;
1195 /* this should never be called, because the peak files for an xfade
1196 will be ready by the time we want them. but our API forces us
1197 to provide this, so ..
1199 delete _peaks_ready_connection;
1200 _peaks_ready_connection = 0;
1202 make_waves (r, which);
1205 void
1206 CrossfadeEditor::audition (Audition which)
1208 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1209 nframes_t preroll;
1210 nframes_t postroll;
1211 nframes_t left_start_offset;
1212 nframes_t right_length;
1213 nframes_t left_length;
1215 if (which != Right && preroll_button.get_active()) {
1216 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1217 } else {
1218 preroll = 0;
1221 if (which != Left && postroll_button.get_active()) {
1222 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1223 } else {
1224 postroll = 0;
1227 // Is there enough data for the whole preroll?
1228 left_length = xfade->length();
1229 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1230 left_start_offset -= preroll;
1231 } else {
1232 preroll = left_start_offset;
1233 left_start_offset = 0;
1235 left_length += preroll;
1237 // Is there enough data for the whole postroll?
1238 right_length = xfade->length();
1239 if ((xfade->in()->length() - right_length) > postroll) {
1240 right_length += postroll;
1241 } else {
1242 right_length = xfade->in()->length();
1245 PropertyList left_plist;
1246 PropertyList right_plist;
1249 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1250 left_plist.add (ARDOUR::Properties::length, left_length);
1251 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1252 left_plist.add (ARDOUR::Properties::layer, 0);
1253 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1255 right_plist.add (ARDOUR::Properties::start, 0);
1256 right_plist.add (ARDOUR::Properties::length, right_length);
1257 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1258 right_plist.add (ARDOUR::Properties::layer, 0);
1259 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1261 if (which == Left) {
1262 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1263 } else if (which == Right) {
1264 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1267 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1268 (RegionFactory::create (xfade->out(), left_plist, false)));
1269 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1270 (RegionFactory::create (xfade->in(), right_plist, false)));
1272 // apply a 20ms declicking fade at the start and end of auditioning
1273 // XXX this should really be a property
1275 left->set_fade_in_length (_session->frame_rate() / 50);
1276 right->set_fade_out_length (_session->frame_rate() / 50);
1278 pl.add_region (left, 0);
1279 pl.add_region (right, 1 + preroll);
1281 /* there is only one ... */
1282 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1284 _session->audition_playlist ();
1287 void
1288 CrossfadeEditor::audition_both ()
1290 audition (Both);
1293 void
1294 CrossfadeEditor::audition_left_dry ()
1296 PropertyList plist;
1298 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1299 plist.add (ARDOUR::Properties::length, xfade->length());
1300 plist.add (ARDOUR::Properties::name, string("xfade left"));
1301 plist.add (ARDOUR::Properties::layer, 0);
1303 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1304 (RegionFactory::create (xfade->out(), plist, false)));
1306 _session->audition_region (left);
1309 void
1310 CrossfadeEditor::audition_left ()
1312 audition (Left);
1315 void
1316 CrossfadeEditor::audition_right_dry ()
1318 PropertyList plist;
1320 plist.add (ARDOUR::Properties::start, 0);
1321 plist.add (ARDOUR::Properties::length, xfade->length());
1322 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1323 plist.add (ARDOUR::Properties::layer, 0);
1325 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1326 (RegionFactory::create (xfade->in(), plist, false)));
1328 _session->audition_region (right);
1331 void
1332 CrossfadeEditor::audition_right ()
1334 audition (Right);
1337 void
1338 CrossfadeEditor::cancel_audition ()
1340 _session->cancel_audition ();
1343 void
1344 CrossfadeEditor::audition_toggled ()
1346 bool x;
1348 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1350 if (x) {
1351 audition_both ();
1352 } else {
1353 cancel_audition ();
1358 void
1359 CrossfadeEditor::audition_right_toggled ()
1361 bool x;
1363 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1365 if (x) {
1366 audition_right ();
1367 } else {
1368 cancel_audition ();
1373 void
1374 CrossfadeEditor::audition_right_dry_toggled ()
1376 bool x;
1378 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1380 if (x) {
1381 audition_right_dry ();
1382 } else {
1383 cancel_audition ();
1388 void
1389 CrossfadeEditor::audition_left_toggled ()
1391 bool x;
1393 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1395 if (x) {
1396 audition_left ();
1397 } else {
1398 cancel_audition ();
1403 void
1404 CrossfadeEditor::audition_left_dry_toggled ()
1406 bool x;
1408 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1410 if (x) {
1411 audition_left_dry ();
1412 } else {
1413 cancel_audition ();
1418 bool
1419 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1421 return true;
1424 bool
1425 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1427 switch (ev->keyval) {
1428 case GDK_Right:
1429 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1430 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1431 } else {
1432 audition_right_button.set_active (!audition_right_button.get_active());
1434 break;
1436 case GDK_Left:
1437 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1438 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1439 } else {
1440 audition_left_button.set_active (!audition_left_button.get_active());
1442 break;
1444 case GDK_space:
1445 if (_session->is_auditioning()) {
1446 cancel_audition ();
1447 } else {
1448 audition_both_button.set_active (!audition_both_button.get_active());
1450 break;
1452 default:
1453 break;
1456 return true;