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
;
58 using namespace Editing
;
62 const int32_t CrossfadeEditor::Point::size
= 7;
63 const double CrossfadeEditor::canvas_border
= 10;
64 CrossfadeEditor::Presets
* CrossfadeEditor::fade_in_presets
= 0;
65 CrossfadeEditor::Presets
* CrossfadeEditor::fade_out_presets
= 0;
67 CrossfadeEditor::Half::Half ()
69 , normative_curve (Evoral::Parameter(GainAutomation
))
70 , gain_curve (Evoral::Parameter(GainAutomation
))
74 CrossfadeEditor::CrossfadeEditor (Session
& s
, boost::shared_ptr
<Crossfade
> xf
, double my
, double mxy
)
75 : ArdourDialog (_("ardour: x-fade edit")),
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 set_wmclass (X_("ardour_automationedit"), "Ardour");
99 set_name ("CrossfadeEditWindow");
100 set_position (Gtk::WIN_POS_MOUSE
);
102 add_accel_group (ActionManager::ui_manager
->get_accel_group());
104 add_events (Gdk::KEY_PRESS_MASK
|Gdk::KEY_RELEASE_MASK
|Gdk::POINTER_MOTION_MASK
);
106 RadioButtonGroup sel_but_group
= select_in_button
.get_group();
107 select_out_button
.set_group (sel_but_group
);
108 select_out_button
.set_mode (false);
109 select_in_button
.set_mode (false);
111 get_action_area()->set_layout(BUTTONBOX_SPREAD
);
112 get_action_area()->pack_start(clear_button
);
113 get_action_area()->pack_start(revert_button
);
114 cancel_button
= add_button ("Cancel", RESPONSE_CANCEL
);
115 ok_button
= add_button ("OK", RESPONSE_ACCEPT
);
117 if (fade_in_presets
== 0) {
121 point_grabbed
= false;
124 canvas
= new ArdourCanvas::CanvasAA ();
125 canvas
->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation
));
126 canvas
->set_size_request (425, 200);
128 toplevel
= new ArdourCanvas::SimpleRect (*(canvas
->root()));
129 toplevel
->property_x1() = 0.0;
130 toplevel
->property_y1() = 0.0;
131 toplevel
->property_x2() = 10.0;
132 toplevel
->property_y2() = 10.0;
133 toplevel
->property_fill() = true;
134 toplevel
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase
.get();
135 toplevel
->property_outline_pixels() = 0;
136 toplevel
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event
));
138 fade
[Out
].line
= new ArdourCanvas::Line (*(canvas
->root()));
139 fade
[Out
].line
->property_width_pixels() = 1;
140 fade
[Out
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
142 fade
[Out
].shading
= new ArdourCanvas::Polygon (*(canvas
->root()));
143 fade
[Out
].shading
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading
.get();
145 fade
[In
].line
= new ArdourCanvas::Line (*(canvas
->root()));
146 fade
[In
].line
->property_width_pixels() = 1;
147 fade
[In
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
149 fade
[In
].shading
= new ArdourCanvas::Polygon (*(canvas
->root()));
150 fade
[In
].shading
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading
.get();
152 fade
[In
].shading
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event
));
153 fade
[In
].line
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event
));
154 fade
[Out
].shading
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event
));
155 fade
[Out
].line
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event
));
157 select_in_button
.set_name (X_("CrossfadeEditCurveButton"));
158 select_out_button
.set_name (X_("CrossfadeEditCurveButton"));
160 select_in_button
.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked
), In
));
161 select_out_button
.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked
), Out
));
163 HBox
* acbox
= manage (new HBox
);
165 audition_box
.set_border_width (7);
166 audition_box
.set_spacing (5);
167 audition_box
.set_homogeneous (false);
168 audition_box
.pack_start (audition_left_dry_button
, false, false);
169 audition_box
.pack_start (audition_left_button
, false, false);
170 audition_box
.pack_start (audition_both_button
, false, false);
171 audition_box
.pack_start (audition_right_button
, false, false);
172 audition_box
.pack_start (audition_right_dry_button
, false, false);
174 Frame
* audition_frame
= manage (new Frame (_("Audition")));
176 audition_frame
->set_name (X_("CrossfadeEditFrame"));
177 audition_frame
->add (audition_box
);
179 acbox
->pack_start (*audition_frame
, true, false);
181 Frame
* canvas_frame
= manage (new Frame
);
182 canvas_frame
->add (*canvas
);
183 canvas_frame
->set_shadow_type (Gtk::SHADOW_IN
);
185 fade_in_table
.attach (select_in_button
, 0, 2, 0, 1, Gtk::FILL
|Gtk::EXPAND
);
186 fade_out_table
.attach (select_out_button
, 0, 2, 0, 1, Gtk::FILL
|Gtk::EXPAND
);
196 for (list
<Preset
*>::iterator i
= fade_in_presets
->begin(); i
!= fade_in_presets
->end(); ++i
) {
198 pxmap
= manage (new Image (::get_icon ((*i
)->image_name
)));
199 pbutton
= manage (new Button
);
200 pbutton
->add (*pxmap
);
201 pbutton
->set_name ("CrossfadeEditButton");
202 pbutton
->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset
), *i
));
203 ARDOUR_UI::instance()->set_tip (pbutton
, (*i
)->name
, "");
204 fade_in_table
.attach (*pbutton
, col
, col
+1, row
, row
+1);
205 fade_in_buttons
.push_back (pbutton
);
218 for (list
<Preset
*>::iterator i
= fade_out_presets
->begin(); i
!= fade_out_presets
->end(); ++i
) {
220 pxmap
= manage (new Image (::get_icon ((*i
)->image_name
)));
221 pbutton
= manage (new Button
);
222 pbutton
->add (*pxmap
);
223 pbutton
->set_name ("CrossfadeEditButton");
224 pbutton
->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset
), *i
));
225 ARDOUR_UI::instance()->set_tip (pbutton
, (*i
)->name
, "");
226 fade_out_table
.attach (*pbutton
, col
, col
+1, row
, row
+1);
227 fade_out_buttons
.push_back (pbutton
);
237 clear_button
.set_name ("CrossfadeEditButton");
238 revert_button
.set_name ("CrossfadeEditButton");
239 ok_button
->set_name ("CrossfadeEditButton");
240 cancel_button
->set_name ("CrossfadeEditButton");
241 preroll_button
.set_name ("CrossfadeEditButton");
242 postroll_button
.set_name ("CrossfadeEditButton");
243 audition_both_button
.set_name ("CrossfadeEditAuditionButton");
244 audition_left_dry_button
.set_name ("CrossfadeEditAuditionButton");
245 audition_left_button
.set_name ("CrossfadeEditAuditionButton");
246 audition_right_dry_button
.set_name ("CrossfadeEditAuditionButton");
247 audition_right_button
.set_name ("CrossfadeEditAuditionButton");
249 clear_button
.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear
));
250 revert_button
.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset
));
251 audition_both_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled
));
252 audition_right_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled
));
253 audition_right_dry_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled
));
254 audition_left_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled
));
255 audition_left_dry_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled
));
257 roll_box
.pack_start (preroll_button
, false, false);
258 roll_box
.pack_start (postroll_button
, false, false);
260 Gtk::HBox
* rcenter_box
= manage (new HBox
);
261 rcenter_box
->pack_start (roll_box
, true, false);
263 VBox
* vpacker2
= manage (new (VBox
));
265 vpacker2
->set_border_width (12);
266 vpacker2
->set_spacing (7);
267 vpacker2
->pack_start (*acbox
, false, false);
268 vpacker2
->pack_start (*rcenter_box
, false, false);
270 curve_button_box
.set_spacing (7);
271 curve_button_box
.pack_start (fade_out_table
, false, false, 12);
272 curve_button_box
.pack_start (*vpacker2
, false, false, 12);
273 curve_button_box
.pack_start (fade_in_table
, false, false, 12);
275 get_vbox()->pack_start (*canvas_frame
, true, true);
276 get_vbox()->pack_start (curve_button_box
, false, false);
278 /* button to allow hackers to check the actual curve values */
280 // Button* foobut = manage (new Button ("dump"));
281 // foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
282 // vpacker.pack_start (*foobut, false, false);
285 set (xfade
->fade_in(), In
);
288 set (xfade
->fade_out(), Out
);
290 curve_select_clicked (In
);
292 xfade
->StateChanged
.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed
));
294 session
.AuditionActive
.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed
));
298 CrossfadeEditor::~CrossfadeEditor()
300 /* most objects will be destroyed when the toplevel window is. */
302 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
306 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
312 CrossfadeEditor::dump ()
314 for (AutomationList::iterator i
= fade
[Out
].normative_curve
.begin(); i
!= fade
[Out
].normative_curve
.end(); ++i
) {
315 cerr
<< (*i
)->when
<< ' ' << (*i
)->value
<< endl
;
320 CrossfadeEditor::audition_state_changed (bool yn
)
322 ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed
), yn
));
325 audition_both_button
.set_active (false);
326 audition_left_button
.set_active (false);
327 audition_right_button
.set_active (false);
328 audition_left_dry_button
.set_active (false);
329 audition_right_dry_button
.set_active (false);
334 CrossfadeEditor::set (const ARDOUR::AutomationList
& curve
, WhichFade which
)
337 ARDOUR::AutomationList::const_iterator the_end
;
339 for (list
<Point
*>::iterator i
= fade
[which
].points
.begin(); i
!= fade
[which
].points
.end(); ++i
) {
343 fade
[which
].points
.clear ();
344 fade
[which
].gain_curve
.clear ();
345 fade
[which
].normative_curve
.clear ();
351 the_end
= curve
.end();
354 firstx
= (*curve
.begin())->when
;
355 endx
= (*the_end
)->when
;
357 for (ARDOUR::AutomationList::const_iterator i
= curve
.begin(); i
!= curve
.end(); ++i
) {
359 double xfract
= ((*i
)->when
- firstx
) / (endx
- firstx
);
360 double yfract
= ((*i
)->value
- miny
) / (maxy
- miny
);
362 Point
* p
= make_point ();
364 p
->move_to (x_coordinate (xfract
), y_coordinate (yfract
),
367 fade
[which
].points
.push_back (p
);
370 /* no need to sort because curve is already time-ordered */
374 swap (which
, current
);
376 swap (which
, current
);
380 CrossfadeEditor::curve_event (GdkEvent
* event
)
382 /* treat it like a toplevel event */
384 return canvas_event (event
);
388 CrossfadeEditor::point_event (GdkEvent
* event
, Point
* point
)
391 if (point
->curve
!= fade
[current
].line
) {
395 switch (event
->type
) {
396 case GDK_BUTTON_PRESS
:
397 point_grabbed
= true;
399 case GDK_BUTTON_RELEASE
:
400 point_grabbed
= false;
402 if (Keyboard::is_delete_event (&event
->button
)) {
403 fade
[current
].points
.remove (point
);
410 case GDK_MOTION_NOTIFY
:
414 /* can't drag first or last points horizontally */
416 if (point
== fade
[current
].points
.front() || point
== fade
[current
].points
.back()) {
419 new_x
= (event
->motion
.x
- canvas_border
)/effective_width();
422 new_y
= 1.0 - ((event
->motion
.y
- canvas_border
)/effective_height());
423 point
->move_to (x_coordinate (new_x
), y_coordinate (new_y
),
435 CrossfadeEditor::canvas_event (GdkEvent
* event
)
437 switch (event
->type
) {
438 case GDK_BUTTON_PRESS
:
439 add_control_point ((event
->button
.x
- canvas_border
)/effective_width(),
440 1.0 - ((event
->button
.y
- canvas_border
)/effective_height()));
449 CrossfadeEditor::Point::~Point()
454 CrossfadeEditor::Point
*
455 CrossfadeEditor::make_point ()
457 Point
* p
= new Point
;
459 p
->box
= new ArdourCanvas::SimpleRect (*(canvas
->root()));
460 p
->box
->property_fill() = true;
461 p
->box
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill
.get();
462 p
->box
->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline
.get();
463 p
->box
->property_outline_pixels() = 1;
465 p
->curve
= fade
[current
].line
;
467 p
->box
->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event
), p
));
473 CrossfadeEditor::add_control_point (double x
, double y
)
477 /* enforce end point x location */
479 if (fade
[current
].points
.empty()) {
481 } else if (fade
[current
].points
.size() == 1) {
485 Point
* p
= make_point ();
487 p
->move_to (x_coordinate (x
), y_coordinate (y
), x
, y
);
489 fade
[current
].points
.push_back (p
);
490 fade
[current
].points
.sort (cmp
);
496 CrossfadeEditor::Point::move_to (double nx
, double ny
, double xfract
, double yfract
)
498 const double half_size
= rint(size
/2.0);
499 double x1
= nx
- half_size
;
500 double x2
= nx
+ half_size
;
502 box
->property_x1() = x1
;
503 box
->property_x2() = x2
;
505 box
->property_y1() = ny
- half_size
;
506 box
->property_y2() = ny
+ half_size
;
513 CrossfadeEditor::canvas_allocation (Gtk::Allocation
& /*alloc*/)
516 toplevel
->property_x1() = 0.0;
517 toplevel
->property_y1() = 0.0;
518 toplevel
->property_x2() = (double) canvas
->get_allocation().get_width() + canvas_border
;
519 toplevel
->property_y2() = (double) canvas
->get_allocation().get_height() + canvas_border
;
522 canvas
->set_scroll_region (0.0, 0.0,
523 canvas
->get_allocation().get_width(),
524 canvas
->get_allocation().get_height());
526 Point
* end
= make_point ();
529 if (fade
[In
].points
.size() > 1) {
530 Point
* old_end
= fade
[In
].points
.back();
531 fade
[In
].points
.pop_back ();
532 end
->move_to (x_coordinate (old_end
->x
),
533 y_coordinate (old_end
->y
),
534 old_end
->x
, old_end
->y
);
539 end
->move_to (x_coordinate (x
), y_coordinate (y
), x
, y
);
543 fade
[In
].points
.push_back (end
);
544 fade
[In
].points
.sort (cmp
);
546 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
547 (*i
)->move_to (x_coordinate((*i
)->x
), y_coordinate((*i
)->y
),
553 if (fade
[Out
].points
.size() > 1) {
554 Point
* old_end
= fade
[Out
].points
.back();
555 fade
[Out
].points
.pop_back ();
556 end
->move_to (x_coordinate (old_end
->x
),
557 y_coordinate (old_end
->y
),
558 old_end
->x
, old_end
->y
);
563 end
->move_to (x_coordinate (x
), y_coordinate (y
), x
, y
);
567 fade
[Out
].points
.push_back (end
);
568 fade
[Out
].points
.sort (cmp
);
570 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
571 (*i
)->move_to (x_coordinate ((*i
)->x
),
572 y_coordinate ((*i
)->y
),
576 WhichFade old_current
= current
;
581 current
= old_current
;
583 double spu
= xfade
->length() / (double) effective_width();
585 if (fade
[In
].waves
.empty()) {
586 make_waves (xfade
->in(), In
);
589 if (fade
[Out
].waves
.empty()) {
590 make_waves (xfade
->out(), Out
);
594 vector
<ArdourCanvas::WaveView
*>::iterator i
;
597 ht
= canvas
->get_allocation().get_height() / xfade
->in()->n_channels();
599 for (n
= 0, i
= fade
[In
].waves
.begin(); i
!= fade
[In
].waves
.end(); ++i
, ++n
) {
604 (*i
)->property_y() = yoff
;
605 (*i
)->property_height() = ht
;
606 (*i
)->property_samples_per_unit() = spu
;
609 ht
= canvas
->get_allocation().get_height() / xfade
->out()->n_channels();
611 for (n
= 0, i
= fade
[Out
].waves
.begin(); i
!= fade
[Out
].waves
.end(); ++i
, ++n
) {
616 (*i
)->property_y() = yoff
;
617 (*i
)->property_height() = ht
;
618 (*i
)->property_samples_per_unit() = spu
;
625 CrossfadeEditor::xfade_changed (Change
)
627 set (xfade
->fade_in(), In
);
628 set (xfade
->fade_out(), Out
);
632 CrossfadeEditor::redraw ()
634 if (canvas
->get_allocation().get_width() < 2) {
638 nframes_t len
= xfade
->length ();
640 fade
[current
].normative_curve
.clear ();
641 fade
[current
].gain_curve
.clear ();
643 for (list
<Point
*>::iterator i
= fade
[current
].points
.begin(); i
!= fade
[current
].points
.end(); ++i
) {
644 fade
[current
].normative_curve
.add ((*i
)->x
, (*i
)->y
);
647 offset
= xfade
->in()->start();
649 offset
= xfade
->out()->start()+xfade
->out()->length()-xfade
->length();
650 fade
[current
].gain_curve
.add (((*i
)->x
* len
) + offset
, (*i
)->y
);
654 size_t npoints
= (size_t) effective_width();
657 fade
[current
].normative_curve
.curve().get_vector (0, 1.0, vec
, npoints
);
659 ArdourCanvas::Points pts
;
660 ArdourCanvas::Points spts
;
662 while (pts
.size() < npoints
) {
663 pts
.push_back (Gnome::Art::Point (0,0));
666 while (spts
.size() < npoints
+ 3) {
667 spts
.push_back (Gnome::Art::Point (0,0));
670 /* the shade coordinates *MUST* be in anti-clockwise order.
677 spts
[0].set_x (canvas_border
);
678 spts
[0].set_y (effective_height() + canvas_border
);
682 spts
[1].set_x (effective_width() + canvas_border
);
683 spts
[1].set_y (effective_height() + canvas_border
);
687 spts
[2].set_x (effective_width() + canvas_border
);
688 spts
[2].set_y (canvas_border
);
695 spts
[0].set_x (canvas_border
);
696 spts
[0].set_y (canvas_border
);
700 spts
[1].set_x (canvas_border
);
701 spts
[1].set_y (effective_height() + canvas_border
);
705 spts
[2].set_x (effective_width() + canvas_border
);
706 spts
[2].set_y (effective_height() + canvas_border
);
710 size_t last_spt
= (npoints
+ 3) - 1;
712 for (size_t i
= 0; i
< npoints
; ++i
) {
716 pts
[i
].set_x (canvas_border
+ i
);
717 pts
[i
].set_y (y_coordinate (y
));
719 spts
[last_spt
- i
].set_x (canvas_border
+ i
);
720 spts
[last_spt
- i
].set_y (pts
[i
].get_y());
723 fade
[current
].line
->property_points() = pts
;
724 fade
[current
].shading
->property_points() = spts
;
726 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[current
].waves
.begin(); i
!= fade
[current
].waves
.end(); ++i
) {
727 (*i
)->property_gain_src() = static_cast<Evoral::Curve
*>(&fade
[current
].gain_curve
.curve());
732 CrossfadeEditor::apply_preset (Preset
*preset
)
735 WhichFade wf
= find(fade_in_presets
->begin(), fade_in_presets
->end(), preset
) != fade_in_presets
->end() ? In
: Out
;
740 select_in_button
.clicked();
742 select_out_button
.clicked();
745 curve_select_clicked (wf
);
748 for (list
<Point
*>::iterator i
= fade
[current
].points
.begin(); i
!= fade
[current
].points
.end(); ++i
) {
752 fade
[current
].points
.clear ();
754 for (Preset::iterator i
= preset
->begin(); i
!= preset
->end(); ++i
) {
755 Point
* p
= make_point ();
756 p
->move_to (x_coordinate ((*i
).x
), y_coordinate ((*i
).y
),
758 fade
[current
].points
.push_back (p
);
765 CrossfadeEditor::apply ()
771 CrossfadeEditor::_apply_to (boost::shared_ptr
<Crossfade
> xf
)
773 ARDOUR::AutomationList
& in (xf
->fade_in());
774 ARDOUR::AutomationList
& out (xf
->fade_out());
779 ARDOUR::AutomationList::const_iterator the_end
= in
.end();
782 double firstx
= (*in
.begin())->when
;
783 double endx
= (*the_end
)->when
;
784 double miny
= in
.get_min_y ();
785 double maxy
= in
.get_max_y ();
790 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
792 double when
= firstx
+ ((*i
)->x
* (endx
- firstx
));
793 double value
= (*i
)->y
; // miny + ((*i)->y * (maxy - miny));
794 in
.add (when
, value
);
802 firstx
= (*out
.begin())->when
;
803 endx
= (*the_end
)->when
;
804 miny
= out
.get_min_y ();
805 maxy
= out
.get_max_y ();
810 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
812 double when
= firstx
+ ((*i
)->x
* (endx
- firstx
));
813 double value
= (*i
)->y
; // miny + ((*i)->y * (maxy - miny));
814 out
.add (when
, value
);
822 CrossfadeEditor::setup (boost::shared_ptr
<Crossfade
> xfade
)
825 xfade
->set_active (true);
826 xfade
->fade_in().curve().solve ();
827 xfade
->fade_out().curve().solve ();
831 CrossfadeEditor::clear ()
833 for (list
<Point
*>::iterator i
= fade
[current
].points
.begin(); i
!= fade
[current
].points
.end(); ++i
) {
837 fade
[current
].points
.clear ();
843 CrossfadeEditor::reset ()
845 set (xfade
->fade_in(), In
);
846 set (xfade
->fade_out(), Out
);
848 curve_select_clicked (current
);
852 CrossfadeEditor::build_presets ()
856 fade_in_presets
= new Presets
;
857 fade_out_presets
= new Presets
;
861 p
= new Preset ("Linear (-6dB)", "crossfade-in-linear");
862 p
->push_back (PresetPoint (0, 0));
863 p
->push_back (PresetPoint (0.000000, 0.000000));
864 p
->push_back (PresetPoint (0.166667, 0.166366));
865 p
->push_back (PresetPoint (0.333333, 0.332853));
866 p
->push_back (PresetPoint (0.500000, 0.499459));
867 p
->push_back (PresetPoint (0.666667, 0.666186));
868 p
->push_back (PresetPoint (0.833333, 0.833033));
869 p
->push_back (PresetPoint (1.000000, 1.000000));
870 fade_in_presets
->push_back (p
);
872 p
= new Preset ("S(1)-curve", "crossfade-in-S1");
873 p
->push_back (PresetPoint (0, 0));
874 p
->push_back (PresetPoint (0.1, 0.01));
875 p
->push_back (PresetPoint (0.2, 0.03));
876 p
->push_back (PresetPoint (0.8, 0.97));
877 p
->push_back (PresetPoint (0.9, 0.99));
878 p
->push_back (PresetPoint (1, 1));
879 fade_in_presets
->push_back (p
);
881 p
= new Preset ("S(2)-curve", "crossfade-in-S2");
882 p
->push_back (PresetPoint (0.0, 0.0));
883 p
->push_back (PresetPoint (0.055, 0.222));
884 p
->push_back (PresetPoint (0.163, 0.35));
885 p
->push_back (PresetPoint (0.837, 0.678));
886 p
->push_back (PresetPoint (0.945, 0.783));
887 p
->push_back (PresetPoint (1.0, 1.0));
888 fade_in_presets
->push_back (p
);
890 p
= new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
892 p
->push_back (PresetPoint (0.000000, 0.000000));
893 p
->push_back (PresetPoint (0.166667, 0.282192));
894 p
->push_back (PresetPoint (0.333333, 0.518174));
895 p
->push_back (PresetPoint (0.500000, 0.707946));
896 p
->push_back (PresetPoint (0.666667, 0.851507));
897 p
->push_back (PresetPoint (0.833333, 0.948859));
898 p
->push_back (PresetPoint (1.000000, 1.000000));
900 fade_in_presets
->push_back (p
);
902 if (!Profile
->get_sae()) {
904 p
= new Preset ("Short cut", "crossfade-in-short-cut");
905 p
->push_back (PresetPoint (0, 0));
906 p
->push_back (PresetPoint (0.389401, 0.0333333));
907 p
->push_back (PresetPoint (0.629032, 0.0861111));
908 p
->push_back (PresetPoint (0.829493, 0.233333));
909 p
->push_back (PresetPoint (0.9447, 0.483333));
910 p
->push_back (PresetPoint (0.976959, 0.697222));
911 p
->push_back (PresetPoint (1, 1));
912 fade_in_presets
->push_back (p
);
914 p
= new Preset ("Slow cut", "crossfade-in-slow-cut");
915 p
->push_back (PresetPoint (0, 0));
916 p
->push_back (PresetPoint (0.304147, 0.0694444));
917 p
->push_back (PresetPoint (0.529954, 0.152778));
918 p
->push_back (PresetPoint (0.725806, 0.333333));
919 p
->push_back (PresetPoint (0.847926, 0.558333));
920 p
->push_back (PresetPoint (0.919355, 0.730556));
921 p
->push_back (PresetPoint (1, 1));
922 fade_in_presets
->push_back (p
);
924 p
= new Preset ("Fast cut", "crossfade-in-fast-cut");
925 p
->push_back (PresetPoint (0, 0));
926 p
->push_back (PresetPoint (0.0737327, 0.308333));
927 p
->push_back (PresetPoint (0.246544, 0.658333));
928 p
->push_back (PresetPoint (0.470046, 0.886111));
929 p
->push_back (PresetPoint (0.652074, 0.972222));
930 p
->push_back (PresetPoint (0.771889, 0.988889));
931 p
->push_back (PresetPoint (1, 1));
932 fade_in_presets
->push_back (p
);
934 p
= new Preset ("Long cut", "crossfade-in-long-cut");
935 p
->push_back (PresetPoint (0, 0));
936 p
->push_back (PresetPoint (0.0207373, 0.197222));
937 p
->push_back (PresetPoint (0.0645161, 0.525));
938 p
->push_back (PresetPoint (0.152074, 0.802778));
939 p
->push_back (PresetPoint (0.276498, 0.919444));
940 p
->push_back (PresetPoint (0.481567, 0.980556));
941 p
->push_back (PresetPoint (0.767281, 1));
942 p
->push_back (PresetPoint (1, 1));
943 fade_in_presets
->push_back (p
);
948 // p = new Preset ("regout.xpm");
949 p
= new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
950 p
->push_back (PresetPoint (0, 1));
951 p
->push_back (PresetPoint (0.000000, 1.000000));
952 p
->push_back (PresetPoint (0.166667, 0.833033));
953 p
->push_back (PresetPoint (0.333333, 0.666186));
954 p
->push_back (PresetPoint (0.500000, 0.499459));
955 p
->push_back (PresetPoint (0.666667, 0.332853));
956 p
->push_back (PresetPoint (0.833333, 0.166366));
957 p
->push_back (PresetPoint (1.000000, 0.000000));
958 fade_out_presets
->push_back (p
);
960 p
= new Preset ("S(1)-Curve", "crossfade-out-S1");
961 p
->push_back (PresetPoint (0, 1));
962 p
->push_back (PresetPoint (0.1, 0.99));
963 p
->push_back (PresetPoint (0.2, 0.97));
964 p
->push_back (PresetPoint (0.8, 0.03));
965 p
->push_back (PresetPoint (0.9, 0.01));
966 p
->push_back (PresetPoint (1, 0));
967 fade_out_presets
->push_back (p
);
969 p
= new Preset ("S(2)-Curve", "crossfade-out-S2");
970 p
->push_back (PresetPoint (0.0, 1.0));
971 p
->push_back (PresetPoint (0.163, 0.678));
972 p
->push_back (PresetPoint (0.055, 0.783));
973 p
->push_back (PresetPoint (0.837, 0.35));
974 p
->push_back (PresetPoint (0.945, 0.222));
975 p
->push_back (PresetPoint (1.0, 0.0));
976 fade_out_presets
->push_back (p
);
978 // p = new Preset ("linout.xpm");
979 p
= new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
980 p
->push_back (PresetPoint (0.000000, 1.000000));
981 p
->push_back (PresetPoint (0.166667, 0.948859));
982 p
->push_back (PresetPoint (0.333333, 0.851507));
983 p
->push_back (PresetPoint (0.500000, 0.707946));
984 p
->push_back (PresetPoint (0.666667, 0.518174));
985 p
->push_back (PresetPoint (0.833333, 0.282192));
986 p
->push_back (PresetPoint (1.000000, 0.000000));
987 fade_out_presets
->push_back (p
);
989 if (!Profile
->get_sae()) {
990 // p = new Preset ("hiout.xpm");
991 p
= new Preset ("Short cut", "crossfade-out-short-cut");
992 p
->push_back (PresetPoint (0, 1));
993 p
->push_back (PresetPoint (0.305556, 1));
994 p
->push_back (PresetPoint (0.548611, 0.991736));
995 p
->push_back (PresetPoint (0.759259, 0.931129));
996 p
->push_back (PresetPoint (0.918981, 0.68595));
997 p
->push_back (PresetPoint (0.976852, 0.22865));
998 p
->push_back (PresetPoint (1, 0));
999 fade_out_presets
->push_back (p
);
1001 p
= new Preset ("Slow cut", "crossfade-out-slow-cut");
1002 p
->push_back (PresetPoint (0, 1));
1003 p
->push_back (PresetPoint (0.228111, 0.988889));
1004 p
->push_back (PresetPoint (0.347926, 0.972222));
1005 p
->push_back (PresetPoint (0.529954, 0.886111));
1006 p
->push_back (PresetPoint (0.753456, 0.658333));
1007 p
->push_back (PresetPoint (0.9262673, 0.308333));
1008 p
->push_back (PresetPoint (1, 0));
1009 fade_out_presets
->push_back (p
);
1011 p
= new Preset ("Fast cut", "crossfade-out-fast-cut");
1012 p
->push_back (PresetPoint (0, 1));
1013 p
->push_back (PresetPoint (0.080645, 0.730556));
1014 p
->push_back (PresetPoint (0.277778, 0.289256));
1015 p
->push_back (PresetPoint (0.470046, 0.152778));
1016 p
->push_back (PresetPoint (0.695853, 0.0694444));
1017 p
->push_back (PresetPoint (1, 0));
1018 fade_out_presets
->push_back (p
);
1020 // p = new Preset ("loout.xpm");
1021 p
= new Preset ("Long cut", "crossfade-out-long-cut");
1022 p
->push_back (PresetPoint (0, 1));
1023 p
->push_back (PresetPoint (0.023041, 0.697222));
1024 p
->push_back (PresetPoint (0.0553, 0.483333));
1025 p
->push_back (PresetPoint (0.170507, 0.233333));
1026 p
->push_back (PresetPoint (0.370968, 0.0861111));
1027 p
->push_back (PresetPoint (0.610599, 0.0333333));
1028 p
->push_back (PresetPoint (1, 0));
1029 fade_out_presets
->push_back (p
);
1035 CrossfadeEditor::curve_select_clicked (WhichFade wf
)
1041 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[In
].waves
.begin(); i
!= fade
[In
].waves
.end(); ++i
) {
1042 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1043 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1046 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[Out
].waves
.begin(); i
!= fade
[Out
].waves
.end(); ++i
) {
1047 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1048 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1051 fade
[In
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine
.get();
1052 fade
[Out
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
1053 fade
[Out
].shading
->hide();
1054 fade
[In
].shading
->show();
1056 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
1060 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
1066 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[In
].waves
.begin(); i
!= fade
[In
].waves
.end(); ++i
) {
1067 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1068 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1071 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[Out
].waves
.begin(); i
!= fade
[Out
].waves
.end(); ++i
) {
1072 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1073 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1076 fade
[Out
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine
.get();
1077 fade
[In
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
1078 fade
[In
].shading
->hide();
1079 fade
[Out
].shading
->show();
1081 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
1085 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
1093 CrossfadeEditor::x_coordinate (double& xfract
) const
1095 xfract
= min (1.0, xfract
);
1096 xfract
= max (0.0, xfract
);
1098 return canvas_border
+ (xfract
* effective_width());
1102 CrossfadeEditor::y_coordinate (double& yfract
) const
1104 yfract
= min (1.0, yfract
);
1105 yfract
= max (0.0, yfract
);
1107 return (canvas
->get_allocation().get_height() - (canvas_border
)) - (yfract
* effective_height());
1111 CrossfadeEditor::make_waves (boost::shared_ptr
<AudioRegion
> region
, WhichFade which
)
1114 uint32_t nchans
= region
->n_channels();
1119 color
= ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1121 color
= ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1124 ht
= canvas
->get_allocation().get_height() / (double) nchans
;
1125 spu
= xfade
->length() / (double) effective_width();
1127 for (uint32_t n
= 0; n
< nchans
; ++n
) {
1129 gdouble yoff
= n
* ht
;
1131 if (region
->audio_source(n
)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready
), region
, which
), peaks_ready_connection
)) {
1132 WaveView
* waveview
= new WaveView (*(canvas
->root()));
1134 waveview
->property_data_src() = region
.get();
1135 waveview
->property_cache_updater() = true;
1136 waveview
->property_cache() = WaveView::create_cache();
1137 waveview
->property_channel() = n
;
1138 waveview
->property_length_function() = (void*) region_length_from_c
;
1139 waveview
->property_sourcefile_length_function() = (void*) sourcefile_length_from_c
;
1140 waveview
->property_peak_function() = (void*) region_read_peaks_from_c
;
1141 waveview
->property_gain_function() = (void*) curve_get_vector_from_c
;
1142 waveview
->property_gain_src() = static_cast<Evoral::Curve
*>(&fade
[which
].gain_curve
.curve());
1143 waveview
->property_x() = canvas_border
;
1144 waveview
->property_y() = yoff
;
1145 waveview
->property_height() = ht
;
1146 waveview
->property_samples_per_unit() = spu
;
1147 waveview
->property_amplitude_above_axis() = 2.0;
1148 waveview
->property_wave_color() = color
;
1149 waveview
->property_fill_color() = color
;
1152 waveview
->property_region_start() = region
->start();
1154 waveview
->property_region_start() = region
->start()+region
->length()-xfade
->length();
1156 waveview
->lower_to_bottom();
1157 fade
[which
].waves
.push_back (waveview
);
1161 toplevel
->lower_to_bottom();
1165 CrossfadeEditor::peaks_ready (boost::shared_ptr
<AudioRegion
> r
, WhichFade which
)
1167 /* this should never be called, because the peak files for an xfade
1168 will be ready by the time we want them. but our API forces us
1169 to provide this, so ..
1171 peaks_ready_connection
.disconnect ();
1172 make_waves (r
, which
);
1176 CrossfadeEditor::audition (Audition which
)
1178 AudioPlaylist
& pl (session
.the_auditioner()->prepare_playlist());
1181 nframes_t left_start_offset
;
1182 nframes_t right_length
;
1183 nframes_t left_length
;
1185 if (which
!= Right
&& preroll_button
.get_active()) {
1186 preroll
= session
.frame_rate() * 2; //2 second hardcoded preroll for now
1191 if (which
!= Left
&& postroll_button
.get_active()) {
1192 postroll
= session
.frame_rate() * 2; //2 second hardcoded postroll for now
1197 // Is there enough data for the whole preroll?
1198 left_length
= xfade
->length();
1199 if ((left_start_offset
= xfade
->out()->length() - xfade
->length()) > preroll
) {
1200 left_start_offset
-= preroll
;
1202 preroll
= left_start_offset
;
1203 left_start_offset
= 0;
1205 left_length
+= preroll
;
1207 // Is there enough data for the whole postroll?
1208 right_length
= xfade
->length();
1209 if ((xfade
->in()->length() - right_length
) > postroll
) {
1210 right_length
+= postroll
;
1212 right_length
= xfade
->in()->length();
1215 boost::shared_ptr
<AudioRegion
> left (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->out(), left_start_offset
, left_length
, "xfade out",
1216 0, Region::DefaultFlags
, false)));
1217 boost::shared_ptr
<AudioRegion
> right (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->in(), 0, right_length
, "xfade in",
1218 0, Region::DefaultFlags
, false)));
1220 //apply a 20ms declicking fade at the start and end of auditioning
1221 left
->set_fade_in_active(true);
1222 left
->set_fade_in_length(session
.frame_rate() / 50);
1223 right
->set_fade_out_active(true);
1224 right
->set_fade_out_length(session
.frame_rate() / 50);
1226 pl
.add_region (left
, 0);
1227 pl
.add_region (right
, 1 + preroll
);
1229 if (which
== Left
) {
1230 right
->set_scale_amplitude (0.0);
1231 } else if (which
== Right
) {
1232 left
->set_scale_amplitude (0.0);
1235 /* there is only one ... */
1236 pl
.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup
));
1238 session
.audition_playlist ();
1242 CrossfadeEditor::audition_both ()
1248 CrossfadeEditor::audition_left_dry ()
1250 boost::shared_ptr
<AudioRegion
> left (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->out(), xfade
->out()->length() - xfade
->length(), xfade
->length(), "xfade left",
1251 0, Region::DefaultFlags
, false)));
1253 session
.audition_region (left
);
1257 CrossfadeEditor::audition_left ()
1263 CrossfadeEditor::audition_right_dry ()
1265 boost::shared_ptr
<AudioRegion
> right (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->in(), 0, xfade
->length(), "xfade in",
1266 0, Region::DefaultFlags
, false)));
1267 session
.audition_region (right
);
1271 CrossfadeEditor::audition_right ()
1277 CrossfadeEditor::cancel_audition ()
1279 session
.cancel_audition ();
1283 CrossfadeEditor::audition_toggled ()
1287 if ((x
= audition_both_button
.get_active ()) != session
.is_auditioning()) {
1298 CrossfadeEditor::audition_right_toggled ()
1302 if ((x
= audition_right_button
.get_active ()) != session
.is_auditioning()) {
1313 CrossfadeEditor::audition_right_dry_toggled ()
1317 if ((x
= audition_right_dry_button
.get_active ()) != session
.is_auditioning()) {
1320 audition_right_dry ();
1328 CrossfadeEditor::audition_left_toggled ()
1332 if ((x
= audition_left_button
.get_active ()) != session
.is_auditioning()) {
1343 CrossfadeEditor::audition_left_dry_toggled ()
1347 if ((x
= audition_left_dry_button
.get_active ()) != session
.is_auditioning()) {
1350 audition_left_dry ();
1358 CrossfadeEditor::on_key_press_event (GdkEventKey */
*ev*/
)
1364 CrossfadeEditor::on_key_release_event (GdkEventKey
* ev
)
1366 switch (ev
->keyval
) {
1368 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1369 audition_right_dry_button
.set_active (!audition_right_dry_button
.get_active());
1371 audition_right_button
.set_active (!audition_right_button
.get_active());
1376 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1377 audition_left_dry_button
.set_active (!audition_left_dry_button
.get_active());
1379 audition_left_button
.set_active (!audition_left_button
.get_active());
1384 if (session
.is_auditioning()) {
1387 audition_both_button
.set_active (!audition_both_button
.get_active());