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.
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"
47 #include "gui_thread.h"
48 #include "canvas_impl.h"
49 #include "simplerect.h"
54 using namespace ARDOUR
;
57 using namespace Editing
;
59 using Gtkmm2ext::Keyboard
;
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 ()
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")),
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")),
93 fade_out_table (3, 3),
95 select_in_button (_("Fade In")),
96 select_out_button (_("Fade Out")),
98 _peaks_ready_connection (0)
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) {
126 point_grabbed
= false;
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
);
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
);
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
);
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);
290 set (xfade
->fade_in(), In
);
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());
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
) {
311 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
315 delete _peaks_ready_connection
;
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
;
327 CrossfadeEditor::audition_state_changed (bool yn
)
329 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed
, 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);
341 CrossfadeEditor::set (const ARDOUR::AutomationList
& curve
, WhichFade which
)
344 ARDOUR::AutomationList::const_iterator the_end
;
346 for (list
<Point
*>::iterator i
= fade
[which
].points
.begin(); i
!= fade
[which
].points
.end(); ++i
) {
350 fade
[which
].points
.clear ();
351 fade
[which
].gain_curve
.clear ();
352 fade
[which
].normative_curve
.clear ();
358 the_end
= curve
.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
),
374 fade
[which
].points
.push_back (p
);
377 /* no need to sort because curve is already time-ordered */
381 swap (which
, current
);
383 swap (which
, current
);
387 CrossfadeEditor::curve_event (GdkEvent
* event
)
389 /* treat it like a toplevel event */
391 return canvas_event (event
);
395 CrossfadeEditor::point_event (GdkEvent
* event
, Point
* point
)
398 if (point
->curve
!= fade
[current
].line
) {
402 switch (event
->type
) {
403 case GDK_BUTTON_PRESS
:
404 point_grabbed
= true;
406 case GDK_BUTTON_RELEASE
:
407 point_grabbed
= false;
409 if (Keyboard::is_delete_event (&event
->button
)) {
410 fade
[current
].points
.remove (point
);
417 case GDK_MOTION_NOTIFY
:
421 /* can't drag first or last points horizontally */
423 if (point
== fade
[current
].points
.front() || point
== fade
[current
].points
.back()) {
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
),
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()));
456 CrossfadeEditor::Point::~Point()
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
));
480 CrossfadeEditor::add_control_point (double x
, double y
)
484 /* enforce end point x location */
486 if (fade
[current
].points
.empty()) {
488 } else if (fade
[current
].points
.size() == 1) {
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
);
503 CrossfadeEditor::Point::move_to (double nx
, double ny
, double xfract
, double yfract
)
505 if ( xfract
< 0.0 ) {
507 } else if ( xfract
> 1.0 ) {
511 if ( yfract
< 0.0 ) {
513 } else if ( 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
;
532 CrossfadeEditor::canvas_allocation (Gtk::Allocation
& /*alloc*/)
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 ();
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
);
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
),
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
);
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
),
595 WhichFade old_current
= current
;
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
);
613 vector
<ArdourCanvas::WaveView
*>::iterator i
;
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
) {
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
) {
635 (*i
)->property_y() = yoff
;
636 (*i
)->property_height() = ht
;
637 (*i
)->property_samples_per_unit() = spu
;
644 CrossfadeEditor::xfade_changed (const PropertyChange
&)
646 set (xfade
->fade_in(), In
);
647 set (xfade
->fade_out(), Out
);
651 CrossfadeEditor::redraw ()
653 if (canvas
->get_allocation().get_width() < 2) {
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
);
666 offset
= xfade
->in()->start();
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();
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.
696 spts
[0].set_x (canvas_border
);
697 spts
[0].set_y (effective_height() + canvas_border
);
701 spts
[1].set_x (effective_width() + canvas_border
);
702 spts
[1].set_y (effective_height() + canvas_border
);
706 spts
[2].set_x (effective_width() + canvas_border
);
707 spts
[2].set_y (canvas_border
);
714 spts
[0].set_x (canvas_border
);
715 spts
[0].set_y (canvas_border
);
719 spts
[1].set_x (canvas_border
);
720 spts
[1].set_y (effective_height() + canvas_border
);
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
) {
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());
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
;
759 select_in_button
.clicked();
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
) {
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
),
777 fade
[current
].points
.push_back (p
);
784 CrossfadeEditor::apply ()
790 CrossfadeEditor::_apply_to (boost::shared_ptr
<Crossfade
> xf
)
792 ARDOUR::AutomationList
& in (xf
->fade_in());
793 ARDOUR::AutomationList
& out (xf
->fade_out());
798 ARDOUR::AutomationList::const_iterator the_end
= in
.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 ();
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
);
821 firstx
= (*out
.begin())->when
;
822 endx
= (*the_end
)->when
;
823 miny
= out
.get_min_y ();
824 maxy
= out
.get_max_y ();
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
);
841 CrossfadeEditor::setup (boost::shared_ptr
<Crossfade
> xfade
)
844 xfade
->set_active (true);
845 xfade
->fade_in().curve().solve ();
846 xfade
->fade_out().curve().solve ();
850 CrossfadeEditor::clear ()
852 for (list
<Point
*>::iterator i
= fade
[current
].points
.begin(); i
!= fade
[current
].points
.end(); ++i
) {
856 fade
[current
].points
.clear ();
862 CrossfadeEditor::reset ()
864 set (xfade
->fade_in(), In
);
865 set (xfade
->fade_out(), Out
);
867 curve_select_clicked (current
);
871 CrossfadeEditor::build_presets ()
875 fade_in_presets
= new Presets
;
876 fade_out_presets
= new Presets
;
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
);
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
);
1054 CrossfadeEditor::curve_select_clicked (WhichFade wf
)
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
) {
1079 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
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
) {
1104 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
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());
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());
1130 CrossfadeEditor::make_waves (boost::shared_ptr
<AudioRegion
> region
, WhichFade which
)
1133 uint32_t nchans
= region
->n_channels();
1138 color
= ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
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
;
1174 waveview
->property_region_start() = region
->start();
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();
1187 CrossfadeEditor::peaks_ready (boost::weak_ptr
<AudioRegion
> wr
, WhichFade which
)
1189 boost::shared_ptr
<AudioRegion
> r (wr
.lock());
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
);
1206 CrossfadeEditor::audition (Audition which
)
1208 AudioPlaylist
& pl (_session
->the_auditioner()->prepare_playlist());
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
1221 if (which
!= Left
&& postroll_button
.get_active()) {
1222 postroll
= _session
->frame_rate() * 2; //2 second hardcoded postroll for now
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
;
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
;
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 ();
1288 CrossfadeEditor::audition_both ()
1294 CrossfadeEditor::audition_left_dry ()
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
);
1310 CrossfadeEditor::audition_left ()
1316 CrossfadeEditor::audition_right_dry ()
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
);
1332 CrossfadeEditor::audition_right ()
1338 CrossfadeEditor::cancel_audition ()
1340 _session
->cancel_audition ();
1344 CrossfadeEditor::audition_toggled ()
1348 if ((x
= audition_both_button
.get_active ()) != _session
->is_auditioning()) {
1359 CrossfadeEditor::audition_right_toggled ()
1363 if ((x
= audition_right_button
.get_active ()) != _session
->is_auditioning()) {
1374 CrossfadeEditor::audition_right_dry_toggled ()
1378 if ((x
= audition_right_dry_button
.get_active ()) != _session
->is_auditioning()) {
1381 audition_right_dry ();
1389 CrossfadeEditor::audition_left_toggled ()
1393 if ((x
= audition_left_button
.get_active ()) != _session
->is_auditioning()) {
1404 CrossfadeEditor::audition_left_dry_toggled ()
1408 if ((x
= audition_left_dry_button
.get_active ()) != _session
->is_auditioning()) {
1411 audition_left_dry ();
1419 CrossfadeEditor::on_key_press_event (GdkEventKey */
*ev*/
)
1425 CrossfadeEditor::on_key_release_event (GdkEventKey
* ev
)
1427 switch (ev
->keyval
) {
1429 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1430 audition_right_dry_button
.set_active (!audition_right_dry_button
.get_active());
1432 audition_right_button
.set_active (!audition_right_button
.get_active());
1437 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1438 audition_left_dry_button
.set_active (!audition_left_dry_button
.get_active());
1440 audition_left_button
.set_active (!audition_left_button
.get_active());
1445 if (_session
->is_auditioning()) {
1448 audition_both_button
.set_active (!audition_both_button
.get_active());