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_event.h>
31 #include <ardour/curve.h>
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/playlist_templates.h>
38 #include <ardour/region_factory.h>
39 #include <ardour/profile.h>
41 #include <gtkmm2ext/gtk_ui.h>
43 #include "ardour_ui.h"
44 #include "crossfade_edit.h"
45 #include "rgb_macros.h"
48 #include "gui_thread.h"
49 #include "canvas_impl.h"
50 #include "simplerect.h"
55 using namespace ARDOUR
;
59 using namespace Editing
;
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 (0.0, 1.0, 1.0, true),
71 gain_curve (0.0, 2.0, 1.0, true)
75 CrossfadeEditor::CrossfadeEditor (Session
& s
, boost::shared_ptr
<Crossfade
> xf
, double my
, double mxy
)
76 : ArdourDialog (_("ardour: x-fade edit")),
79 clear_button (_("Clear")),
80 revert_button (_("Reset")),
81 audition_both_button (_("Fade")),
82 audition_left_dry_button (_("Out (dry)")),
83 audition_left_button (_("Out")),
84 audition_right_dry_button (_("In (dry)")),
85 audition_right_button (_("In")),
87 preroll_button (_("With Pre-roll")),
88 postroll_button (_("With Post-roll")),
94 fade_out_table (3, 3),
96 select_in_button (_("Fade In")),
97 select_out_button (_("Fade Out"))
99 set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME
);
100 set_name ("CrossfadeEditWindow");
101 set_position (Gtk::WIN_POS_MOUSE
);
103 add_accel_group (ActionManager::ui_manager
->get_accel_group());
105 add_events (Gdk::KEY_PRESS_MASK
|Gdk::KEY_RELEASE_MASK
|Gdk::POINTER_MOTION_MASK
);
107 RadioButtonGroup sel_but_group
= select_in_button
.get_group();
108 select_out_button
.set_group (sel_but_group
);
109 select_out_button
.set_mode (false);
110 select_in_button
.set_mode (false);
112 get_action_area()->set_layout(BUTTONBOX_SPREAD
);
113 get_action_area()->pack_start(clear_button
);
114 get_action_area()->pack_start(revert_button
);
115 cancel_button
= add_button ("Cancel", RESPONSE_CANCEL
);
116 ok_button
= add_button ("OK", RESPONSE_ACCEPT
);
118 if (fade_in_presets
== 0) {
122 point_grabbed
= false;
125 canvas
= new ArdourCanvas::CanvasAA ();
126 canvas
->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation
));
127 canvas
->set_size_request (425, 200);
129 toplevel
= new ArdourCanvas::SimpleRect (*(canvas
->root()));
130 toplevel
->property_x1() = 0.0;
131 toplevel
->property_y1() = 0.0;
132 toplevel
->property_x2() = 10.0;
133 toplevel
->property_y2() = 10.0;
134 toplevel
->property_fill() = true;
135 toplevel
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase
.get();
136 toplevel
->property_outline_pixels() = 0;
137 toplevel
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event
));
139 fade
[Out
].line
= new ArdourCanvas::Line (*(canvas
->root()));
140 fade
[Out
].line
->property_width_pixels() = 1;
141 fade
[Out
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
143 fade
[Out
].shading
= new ArdourCanvas::Polygon (*(canvas
->root()));
144 fade
[Out
].shading
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading
.get();
146 fade
[In
].line
= new ArdourCanvas::Line (*(canvas
->root()));
147 fade
[In
].line
->property_width_pixels() = 1;
148 fade
[In
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
150 fade
[In
].shading
= new ArdourCanvas::Polygon (*(canvas
->root()));
151 fade
[In
].shading
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading
.get();
153 fade
[In
].shading
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event
));
154 fade
[In
].line
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event
));
155 fade
[Out
].shading
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event
));
156 fade
[Out
].line
->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event
));
158 select_in_button
.set_name (X_("CrossfadeEditCurveButton"));
159 select_out_button
.set_name (X_("CrossfadeEditCurveButton"));
161 select_in_button
.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked
), In
));
162 select_out_button
.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked
), Out
));
164 HBox
* acbox
= manage (new HBox
);
166 audition_box
.set_border_width (7);
167 audition_box
.set_spacing (5);
168 audition_box
.set_homogeneous (false);
169 audition_box
.pack_start (audition_left_dry_button
, false, false);
170 audition_box
.pack_start (audition_left_button
, false, false);
171 audition_box
.pack_start (audition_both_button
, false, false);
172 audition_box
.pack_start (audition_right_button
, false, false);
173 audition_box
.pack_start (audition_right_dry_button
, false, false);
175 Frame
* audition_frame
= manage (new Frame (_("Audition")));
177 audition_frame
->set_name (X_("CrossfadeEditFrame"));
178 audition_frame
->add (audition_box
);
180 acbox
->pack_start (*audition_frame
, true, false);
182 Frame
* canvas_frame
= manage (new Frame
);
183 canvas_frame
->add (*canvas
);
184 canvas_frame
->set_shadow_type (Gtk::SHADOW_IN
);
186 fade_in_table
.attach (select_in_button
, 0, 2, 0, 1, Gtk::FILL
|Gtk::EXPAND
);
187 fade_out_table
.attach (select_out_button
, 0, 2, 0, 1, Gtk::FILL
|Gtk::EXPAND
);
197 for (list
<Preset
*>::iterator i
= fade_in_presets
->begin(); i
!= fade_in_presets
->end(); ++i
) {
199 pxmap
= manage (new Image (::get_icon ((*i
)->image_name
)));
200 pbutton
= manage (new Button
);
201 pbutton
->add (*pxmap
);
202 pbutton
->set_name ("CrossfadeEditButton");
203 pbutton
->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset
), *i
));
204 ARDOUR_UI::instance()->set_tip (pbutton
, (*i
)->name
, "");
205 fade_in_table
.attach (*pbutton
, col
, col
+1, row
, row
+1);
206 fade_in_buttons
.push_back (pbutton
);
219 for (list
<Preset
*>::iterator i
= fade_out_presets
->begin(); i
!= fade_out_presets
->end(); ++i
) {
221 pxmap
= manage (new Image (::get_icon ((*i
)->image_name
)));
222 pbutton
= manage (new Button
);
223 pbutton
->add (*pxmap
);
224 pbutton
->set_name ("CrossfadeEditButton");
225 pbutton
->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset
), *i
));
226 ARDOUR_UI::instance()->set_tip (pbutton
, (*i
)->name
, "");
227 fade_out_table
.attach (*pbutton
, col
, col
+1, row
, row
+1);
228 fade_out_buttons
.push_back (pbutton
);
238 clear_button
.set_name ("CrossfadeEditButton");
239 revert_button
.set_name ("CrossfadeEditButton");
240 ok_button
->set_name ("CrossfadeEditButton");
241 cancel_button
->set_name ("CrossfadeEditButton");
242 preroll_button
.set_name ("CrossfadeEditButton");
243 postroll_button
.set_name ("CrossfadeEditButton");
244 audition_both_button
.set_name ("CrossfadeEditAuditionButton");
245 audition_left_dry_button
.set_name ("CrossfadeEditAuditionButton");
246 audition_left_button
.set_name ("CrossfadeEditAuditionButton");
247 audition_right_dry_button
.set_name ("CrossfadeEditAuditionButton");
248 audition_right_button
.set_name ("CrossfadeEditAuditionButton");
250 clear_button
.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear
));
251 revert_button
.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset
));
252 audition_both_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled
));
253 audition_right_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled
));
254 audition_right_dry_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled
));
255 audition_left_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled
));
256 audition_left_dry_button
.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled
));
258 roll_box
.pack_start (preroll_button
, false, false);
259 roll_box
.pack_start (postroll_button
, false, false);
261 Gtk::HBox
* rcenter_box
= manage (new HBox
);
262 rcenter_box
->pack_start (roll_box
, true, false);
264 VBox
* vpacker2
= manage (new (VBox
));
266 vpacker2
->set_border_width (12);
267 vpacker2
->set_spacing (7);
268 vpacker2
->pack_start (*acbox
, false, false);
269 vpacker2
->pack_start (*rcenter_box
, false, false);
271 curve_button_box
.set_spacing (7);
272 curve_button_box
.pack_start (fade_out_table
, false, false, 12);
273 curve_button_box
.pack_start (*vpacker2
, false, false, 12);
274 curve_button_box
.pack_start (fade_in_table
, false, false, 12);
276 get_vbox()->pack_start (*canvas_frame
, true, true);
277 get_vbox()->pack_start (curve_button_box
, false, false);
279 /* button to allow hackers to check the actual curve values */
281 // Button* foobut = manage (new Button ("dump"));
282 // foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
283 // vpacker.pack_start (*foobut, false, false);
286 set (xfade
->fade_in(), In
);
289 set (xfade
->fade_out(), Out
);
291 curve_select_clicked (In
);
293 xfade
->StateChanged
.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed
));
295 session
.AuditionActive
.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed
));
299 CrossfadeEditor::~CrossfadeEditor()
301 /* most objects will be destroyed when the toplevel window is. */
303 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
307 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
313 CrossfadeEditor::dump ()
315 for (AutomationList::iterator i
= fade
[Out
].normative_curve
.begin(); i
!= fade
[Out
].normative_curve
.end(); ++i
) {
316 cerr
<< (*i
)->when
<< ' ' << (*i
)->value
<< endl
;
321 CrossfadeEditor::audition_state_changed (bool yn
)
323 ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed
), yn
));
326 audition_both_button
.set_active (false);
327 audition_left_button
.set_active (false);
328 audition_right_button
.set_active (false);
329 audition_left_dry_button
.set_active (false);
330 audition_right_dry_button
.set_active (false);
335 CrossfadeEditor::set (const ARDOUR::Curve
& curve
, WhichFade which
)
338 ARDOUR::Curve::const_iterator the_end
;
340 for (list
<Point
*>::iterator i
= fade
[which
].points
.begin(); i
!= fade
[which
].points
.end(); ++i
) {
344 fade
[which
].points
.clear ();
345 fade
[which
].gain_curve
.clear ();
346 fade
[which
].normative_curve
.clear ();
352 the_end
= curve
.const_end();
355 firstx
= (*curve
.const_begin())->when
;
356 endx
= (*the_end
)->when
;
358 for (ARDOUR::Curve::const_iterator i
= curve
.const_begin(); i
!= curve
.const_end(); ++i
) {
360 double xfract
= ((*i
)->when
- firstx
) / (endx
- firstx
);
361 double yfract
= ((*i
)->value
- miny
) / (maxy
- miny
);
363 Point
* p
= make_point ();
365 p
->move_to (x_coordinate (xfract
), y_coordinate (yfract
),
368 fade
[which
].points
.push_back (p
);
371 /* no need to sort because curve is already time-ordered */
375 swap (which
, current
);
377 swap (which
, current
);
381 CrossfadeEditor::curve_event (GdkEvent
* event
)
383 /* treat it like a toplevel event */
385 return canvas_event (event
);
389 CrossfadeEditor::point_event (GdkEvent
* event
, Point
* point
)
392 if (point
->curve
!= fade
[current
].line
) {
396 switch (event
->type
) {
397 case GDK_BUTTON_PRESS
:
398 point_grabbed
= true;
400 case GDK_BUTTON_RELEASE
:
401 point_grabbed
= false;
403 if (Keyboard::is_delete_event (&event
->button
)) {
404 fade
[current
].points
.remove (point
);
411 case GDK_MOTION_NOTIFY
:
415 /* can't drag first or last points horizontally */
417 if (point
== fade
[current
].points
.front() || point
== fade
[current
].points
.back()) {
420 new_x
= (event
->motion
.x
- canvas_border
)/effective_width();
423 new_y
= 1.0 - ((event
->motion
.y
- canvas_border
)/effective_height());
424 point
->move_to (x_coordinate (new_x
), y_coordinate (new_y
),
436 CrossfadeEditor::canvas_event (GdkEvent
* event
)
438 switch (event
->type
) {
439 case GDK_BUTTON_PRESS
:
440 add_control_point ((event
->button
.x
- canvas_border
)/effective_width(),
441 1.0 - ((event
->button
.y
- canvas_border
)/effective_height()));
450 CrossfadeEditor::Point::~Point()
455 CrossfadeEditor::Point
*
456 CrossfadeEditor::make_point ()
458 Point
* p
= new Point
;
460 p
->box
= new ArdourCanvas::SimpleRect (*(canvas
->root()));
461 p
->box
->property_fill() = true;
462 p
->box
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill
.get();
463 p
->box
->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline
.get();
464 p
->box
->property_outline_pixels() = 1;
466 p
->curve
= fade
[current
].line
;
468 p
->box
->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event
), p
));
474 CrossfadeEditor::add_control_point (double x
, double y
)
478 /* enforce end point x location */
480 if (fade
[current
].points
.empty()) {
482 } else if (fade
[current
].points
.size() == 1) {
486 Point
* p
= make_point ();
488 p
->move_to (x_coordinate (x
), y_coordinate (y
), x
, y
);
490 fade
[current
].points
.push_back (p
);
491 fade
[current
].points
.sort (cmp
);
497 CrossfadeEditor::Point::move_to (double nx
, double ny
, double xfract
, double yfract
)
499 if ( xfract
< 0.0 ) {
501 } else if ( xfract
> 1.0 ) {
505 if ( yfract
< 0.0 ) {
507 } else if ( yfract
> 1.0 ) {
511 const double half_size
= rint(size
/2.0);
512 double x1
= nx
- half_size
;
513 double x2
= nx
+ half_size
;
515 box
->property_x1() = x1
;
516 box
->property_x2() = x2
;
518 box
->property_y1() = ny
- half_size
;
519 box
->property_y2() = ny
+ half_size
;
526 CrossfadeEditor::canvas_allocation (Gtk::Allocation
& alloc
)
529 toplevel
->property_x1() = 0.0;
530 toplevel
->property_y1() = 0.0;
531 toplevel
->property_x2() = (double) canvas
->get_allocation().get_width() + canvas_border
;
532 toplevel
->property_y2() = (double) canvas
->get_allocation().get_height() + canvas_border
;
535 canvas
->set_scroll_region (0.0, 0.0,
536 canvas
->get_allocation().get_width(),
537 canvas
->get_allocation().get_height());
539 Point
* end
= make_point ();
542 if (fade
[In
].points
.size() > 1) {
543 Point
* old_end
= fade
[In
].points
.back();
544 fade
[In
].points
.pop_back ();
545 end
->move_to (x_coordinate (old_end
->x
),
546 y_coordinate (old_end
->y
),
547 old_end
->x
, old_end
->y
);
552 end
->move_to (x_coordinate (x
), y_coordinate (y
), x
, y
);
556 fade
[In
].points
.push_back (end
);
557 fade
[In
].points
.sort (cmp
);
559 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
560 (*i
)->move_to (x_coordinate((*i
)->x
), y_coordinate((*i
)->y
),
566 if (fade
[Out
].points
.size() > 1) {
567 Point
* old_end
= fade
[Out
].points
.back();
568 fade
[Out
].points
.pop_back ();
569 end
->move_to (x_coordinate (old_end
->x
),
570 y_coordinate (old_end
->y
),
571 old_end
->x
, old_end
->y
);
576 end
->move_to (x_coordinate (x
), y_coordinate (y
), x
, y
);
580 fade
[Out
].points
.push_back (end
);
581 fade
[Out
].points
.sort (cmp
);
583 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
584 (*i
)->move_to (x_coordinate ((*i
)->x
),
585 y_coordinate ((*i
)->y
),
589 WhichFade old_current
= current
;
594 current
= old_current
;
596 double spu
= xfade
->length() / (double) effective_width();
598 if (fade
[In
].waves
.empty()) {
599 make_waves (xfade
->in(), In
);
602 if (fade
[Out
].waves
.empty()) {
603 make_waves (xfade
->out(), Out
);
607 vector
<ArdourCanvas::WaveView
*>::iterator i
;
610 ht
= canvas
->get_allocation().get_height() / xfade
->in()->n_channels();
612 for (n
= 0, i
= fade
[In
].waves
.begin(); i
!= fade
[In
].waves
.end(); ++i
, ++n
) {
617 (*i
)->property_y() = yoff
;
618 (*i
)->property_height() = ht
;
619 (*i
)->property_samples_per_unit() = spu
;
622 ht
= canvas
->get_allocation().get_height() / xfade
->out()->n_channels();
624 for (n
= 0, i
= fade
[Out
].waves
.begin(); i
!= fade
[Out
].waves
.end(); ++i
, ++n
) {
629 (*i
)->property_y() = yoff
;
630 (*i
)->property_height() = ht
;
631 (*i
)->property_samples_per_unit() = spu
;
638 CrossfadeEditor::xfade_changed (Change ignored
)
640 set (xfade
->fade_in(), In
);
641 set (xfade
->fade_out(), Out
);
645 CrossfadeEditor::redraw ()
647 if (canvas
->get_allocation().get_width() < 2) {
651 nframes_t len
= xfade
->length ();
653 fade
[current
].normative_curve
.clear ();
654 fade
[current
].gain_curve
.clear ();
656 for (list
<Point
*>::iterator i
= fade
[current
].points
.begin(); i
!= fade
[current
].points
.end(); ++i
) {
657 fade
[current
].normative_curve
.add ((*i
)->x
, (*i
)->y
);
660 offset
= xfade
->in()->start();
662 offset
= xfade
->out()->start()+xfade
->out()->length()-xfade
->length();
663 fade
[current
].gain_curve
.add (((*i
)->x
* len
) + offset
, (*i
)->y
);
667 size_t npoints
= (size_t) effective_width();
670 fade
[current
].normative_curve
.get_vector (0, 1.0, vec
, npoints
);
672 ArdourCanvas::Points pts
;
673 ArdourCanvas::Points spts
;
675 while (pts
.size() < npoints
) {
676 pts
.push_back (Gnome::Art::Point (0,0));
679 while (spts
.size() < npoints
+ 3) {
680 spts
.push_back (Gnome::Art::Point (0,0));
683 /* the shade coordinates *MUST* be in anti-clockwise order.
690 spts
[0].set_x (canvas_border
);
691 spts
[0].set_y (effective_height() + canvas_border
);
695 spts
[1].set_x (effective_width() + canvas_border
);
696 spts
[1].set_y (effective_height() + canvas_border
);
700 spts
[2].set_x (effective_width() + canvas_border
);
701 spts
[2].set_y (canvas_border
);
708 spts
[0].set_x (canvas_border
);
709 spts
[0].set_y (canvas_border
);
713 spts
[1].set_x (canvas_border
);
714 spts
[1].set_y (effective_height() + canvas_border
);
718 spts
[2].set_x (effective_width() + canvas_border
);
719 spts
[2].set_y (effective_height() + canvas_border
);
723 size_t last_spt
= (npoints
+ 3) - 1;
725 for (size_t i
= 0; i
< npoints
; ++i
) {
729 pts
[i
].set_x (canvas_border
+ i
);
730 pts
[i
].set_y (y_coordinate (y
));
732 spts
[last_spt
- i
].set_x (canvas_border
+ i
);
733 spts
[last_spt
- i
].set_y (pts
[i
].get_y());
736 fade
[current
].line
->property_points() = pts
;
737 fade
[current
].shading
->property_points() = spts
;
739 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[current
].waves
.begin(); i
!= fade
[current
].waves
.end(); ++i
) {
740 (*i
)->property_gain_src() = &fade
[current
].gain_curve
;
745 CrossfadeEditor::apply_preset (Preset
*preset
)
748 WhichFade wf
= find(fade_in_presets
->begin(), fade_in_presets
->end(), preset
) != fade_in_presets
->end() ? In
: Out
;
753 select_in_button
.clicked();
755 select_out_button
.clicked();
758 curve_select_clicked (wf
);
761 for (list
<Point
*>::iterator i
= fade
[current
].points
.begin(); i
!= fade
[current
].points
.end(); ++i
) {
765 fade
[current
].points
.clear ();
767 for (Preset::iterator i
= preset
->begin(); i
!= preset
->end(); ++i
) {
768 Point
* p
= make_point ();
769 p
->move_to (x_coordinate ((*i
).x
), y_coordinate ((*i
).y
),
771 fade
[current
].points
.push_back (p
);
778 CrossfadeEditor::apply ()
784 CrossfadeEditor::_apply_to (boost::shared_ptr
<Crossfade
> xf
)
786 ARDOUR::Curve
& in (xf
->fade_in());
787 ARDOUR::Curve
& out (xf
->fade_out());
792 ARDOUR::Curve::const_iterator the_end
= in
.const_end();
795 double firstx
= (*in
.begin())->when
;
796 double endx
= (*the_end
)->when
;
797 double miny
= in
.get_min_y ();
798 double maxy
= in
.get_max_y ();
803 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
805 double when
= firstx
+ ((*i
)->x
* (endx
- firstx
));
806 double value
= (*i
)->y
; // miny + ((*i)->y * (maxy - miny));
807 in
.add (when
, value
);
812 the_end
= out
.const_end();
815 firstx
= (*out
.begin())->when
;
816 endx
= (*the_end
)->when
;
817 miny
= out
.get_min_y ();
818 maxy
= out
.get_max_y ();
823 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
825 double when
= firstx
+ ((*i
)->x
* (endx
- firstx
));
826 double value
= (*i
)->y
; // miny + ((*i)->y * (maxy - miny));
827 out
.add (when
, value
);
835 CrossfadeEditor::setup (boost::shared_ptr
<Crossfade
> xfade
)
838 xfade
->set_active (true);
839 xfade
->fade_in().solve ();
840 xfade
->fade_out().solve ();
844 CrossfadeEditor::clear ()
846 for (list
<Point
*>::iterator i
= fade
[current
].points
.begin(); i
!= fade
[current
].points
.end(); ++i
) {
850 fade
[current
].points
.clear ();
856 CrossfadeEditor::reset ()
858 set (xfade
->fade_in(), In
);
859 set (xfade
->fade_out(), Out
);
861 curve_select_clicked (current
);
865 CrossfadeEditor::build_presets ()
869 fade_in_presets
= new Presets
;
870 fade_out_presets
= new Presets
;
874 p
= new Preset ("Linear (-6dB)", "crossfade-in-linear");
875 p
->push_back (PresetPoint (0, 0));
876 p
->push_back (PresetPoint (0.000000, 0.000000));
877 p
->push_back (PresetPoint (0.166667, 0.166366));
878 p
->push_back (PresetPoint (0.333333, 0.332853));
879 p
->push_back (PresetPoint (0.500000, 0.499459));
880 p
->push_back (PresetPoint (0.666667, 0.666186));
881 p
->push_back (PresetPoint (0.833333, 0.833033));
882 p
->push_back (PresetPoint (1.000000, 1.000000));
883 fade_in_presets
->push_back (p
);
885 p
= new Preset ("S(1)-curve", "crossfade-in-S1");
886 p
->push_back (PresetPoint (0, 0));
887 p
->push_back (PresetPoint (0.1, 0.01));
888 p
->push_back (PresetPoint (0.2, 0.03));
889 p
->push_back (PresetPoint (0.8, 0.97));
890 p
->push_back (PresetPoint (0.9, 0.99));
891 p
->push_back (PresetPoint (1, 1));
892 fade_in_presets
->push_back (p
);
894 p
= new Preset ("S(2)-curve", "crossfade-in-S2");
895 p
->push_back (PresetPoint (0.0, 0.0));
896 p
->push_back (PresetPoint (0.055, 0.222));
897 p
->push_back (PresetPoint (0.163, 0.35));
898 p
->push_back (PresetPoint (0.837, 0.678));
899 p
->push_back (PresetPoint (0.945, 0.783));
900 p
->push_back (PresetPoint (1.0, 1.0));
901 fade_in_presets
->push_back (p
);
903 p
= new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
905 p
->push_back (PresetPoint (0.000000, 0.000000));
906 p
->push_back (PresetPoint (0.166667, 0.282192));
907 p
->push_back (PresetPoint (0.333333, 0.518174));
908 p
->push_back (PresetPoint (0.500000, 0.707946));
909 p
->push_back (PresetPoint (0.666667, 0.851507));
910 p
->push_back (PresetPoint (0.833333, 0.948859));
911 p
->push_back (PresetPoint (1.000000, 1.000000));
913 fade_in_presets
->push_back (p
);
915 if (!Profile
->get_sae()) {
917 p
= new Preset ("Short cut", "crossfade-in-short-cut");
918 p
->push_back (PresetPoint (0, 0));
919 p
->push_back (PresetPoint (0.389401, 0.0333333));
920 p
->push_back (PresetPoint (0.629032, 0.0861111));
921 p
->push_back (PresetPoint (0.829493, 0.233333));
922 p
->push_back (PresetPoint (0.9447, 0.483333));
923 p
->push_back (PresetPoint (0.976959, 0.697222));
924 p
->push_back (PresetPoint (1, 1));
925 fade_in_presets
->push_back (p
);
927 p
= new Preset ("Slow cut", "crossfade-in-slow-cut");
928 p
->push_back (PresetPoint (0, 0));
929 p
->push_back (PresetPoint (0.304147, 0.0694444));
930 p
->push_back (PresetPoint (0.529954, 0.152778));
931 p
->push_back (PresetPoint (0.725806, 0.333333));
932 p
->push_back (PresetPoint (0.847926, 0.558333));
933 p
->push_back (PresetPoint (0.919355, 0.730556));
934 p
->push_back (PresetPoint (1, 1));
935 fade_in_presets
->push_back (p
);
937 p
= new Preset ("Fast cut", "crossfade-in-fast-cut");
938 p
->push_back (PresetPoint (0, 0));
939 p
->push_back (PresetPoint (0.0737327, 0.308333));
940 p
->push_back (PresetPoint (0.246544, 0.658333));
941 p
->push_back (PresetPoint (0.470046, 0.886111));
942 p
->push_back (PresetPoint (0.652074, 0.972222));
943 p
->push_back (PresetPoint (0.771889, 0.988889));
944 p
->push_back (PresetPoint (1, 1));
945 fade_in_presets
->push_back (p
);
947 p
= new Preset ("Long cut", "crossfade-in-long-cut");
948 p
->push_back (PresetPoint (0, 0));
949 p
->push_back (PresetPoint (0.0207373, 0.197222));
950 p
->push_back (PresetPoint (0.0645161, 0.525));
951 p
->push_back (PresetPoint (0.152074, 0.802778));
952 p
->push_back (PresetPoint (0.276498, 0.919444));
953 p
->push_back (PresetPoint (0.481567, 0.980556));
954 p
->push_back (PresetPoint (0.767281, 1));
955 p
->push_back (PresetPoint (1, 1));
956 fade_in_presets
->push_back (p
);
961 // p = new Preset ("regout.xpm");
962 p
= new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
963 p
->push_back (PresetPoint (0, 1));
964 p
->push_back (PresetPoint (0.000000, 1.000000));
965 p
->push_back (PresetPoint (0.166667, 0.833033));
966 p
->push_back (PresetPoint (0.333333, 0.666186));
967 p
->push_back (PresetPoint (0.500000, 0.499459));
968 p
->push_back (PresetPoint (0.666667, 0.332853));
969 p
->push_back (PresetPoint (0.833333, 0.166366));
970 p
->push_back (PresetPoint (1.000000, 0.000000));
971 fade_out_presets
->push_back (p
);
973 p
= new Preset ("S(1)-Curve", "crossfade-out-S1");
974 p
->push_back (PresetPoint (0, 1));
975 p
->push_back (PresetPoint (0.1, 0.99));
976 p
->push_back (PresetPoint (0.2, 0.97));
977 p
->push_back (PresetPoint (0.8, 0.03));
978 p
->push_back (PresetPoint (0.9, 0.01));
979 p
->push_back (PresetPoint (1, 0));
980 fade_out_presets
->push_back (p
);
982 p
= new Preset ("S(2)-Curve", "crossfade-out-S2");
983 p
->push_back (PresetPoint (0.0, 1.0));
984 p
->push_back (PresetPoint (0.163, 0.678));
985 p
->push_back (PresetPoint (0.055, 0.783));
986 p
->push_back (PresetPoint (0.837, 0.35));
987 p
->push_back (PresetPoint (0.945, 0.222));
988 p
->push_back (PresetPoint (1.0, 0.0));
989 fade_out_presets
->push_back (p
);
991 // p = new Preset ("linout.xpm");
992 p
= new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
993 p
->push_back (PresetPoint (0.000000, 1.000000));
994 p
->push_back (PresetPoint (0.166667, 0.948859));
995 p
->push_back (PresetPoint (0.333333, 0.851507));
996 p
->push_back (PresetPoint (0.500000, 0.707946));
997 p
->push_back (PresetPoint (0.666667, 0.518174));
998 p
->push_back (PresetPoint (0.833333, 0.282192));
999 p
->push_back (PresetPoint (1.000000, 0.000000));
1000 fade_out_presets
->push_back (p
);
1002 if (!Profile
->get_sae()) {
1003 // p = new Preset ("hiout.xpm");
1004 p
= new Preset ("Short cut", "crossfade-out-short-cut");
1005 p
->push_back (PresetPoint (0, 1));
1006 p
->push_back (PresetPoint (0.305556, 1));
1007 p
->push_back (PresetPoint (0.548611, 0.991736));
1008 p
->push_back (PresetPoint (0.759259, 0.931129));
1009 p
->push_back (PresetPoint (0.918981, 0.68595));
1010 p
->push_back (PresetPoint (0.976852, 0.22865));
1011 p
->push_back (PresetPoint (1, 0));
1012 fade_out_presets
->push_back (p
);
1014 p
= new Preset ("Slow cut", "crossfade-out-slow-cut");
1015 p
->push_back (PresetPoint (0, 1));
1016 p
->push_back (PresetPoint (0.228111, 0.988889));
1017 p
->push_back (PresetPoint (0.347926, 0.972222));
1018 p
->push_back (PresetPoint (0.529954, 0.886111));
1019 p
->push_back (PresetPoint (0.753456, 0.658333));
1020 p
->push_back (PresetPoint (0.9262673, 0.308333));
1021 p
->push_back (PresetPoint (1, 0));
1022 fade_out_presets
->push_back (p
);
1024 p
= new Preset ("Fast cut", "crossfade-out-fast-cut");
1025 p
->push_back (PresetPoint (0, 1));
1026 p
->push_back (PresetPoint (0.080645, 0.730556));
1027 p
->push_back (PresetPoint (0.277778, 0.289256));
1028 p
->push_back (PresetPoint (0.470046, 0.152778));
1029 p
->push_back (PresetPoint (0.695853, 0.0694444));
1030 p
->push_back (PresetPoint (1, 0));
1031 fade_out_presets
->push_back (p
);
1033 // p = new Preset ("loout.xpm");
1034 p
= new Preset ("Long cut", "crossfade-out-long-cut");
1035 p
->push_back (PresetPoint (0, 1));
1036 p
->push_back (PresetPoint (0.023041, 0.697222));
1037 p
->push_back (PresetPoint (0.0553, 0.483333));
1038 p
->push_back (PresetPoint (0.170507, 0.233333));
1039 p
->push_back (PresetPoint (0.370968, 0.0861111));
1040 p
->push_back (PresetPoint (0.610599, 0.0333333));
1041 p
->push_back (PresetPoint (1, 0));
1042 fade_out_presets
->push_back (p
);
1048 CrossfadeEditor::curve_select_clicked (WhichFade wf
)
1054 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[In
].waves
.begin(); i
!= fade
[In
].waves
.end(); ++i
) {
1055 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1056 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1059 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[Out
].waves
.begin(); i
!= fade
[Out
].waves
.end(); ++i
) {
1060 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1061 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1064 fade
[In
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine
.get();
1065 fade
[Out
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
1066 fade
[Out
].shading
->hide();
1067 fade
[In
].shading
->show();
1069 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
1073 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
1079 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[In
].waves
.begin(); i
!= fade
[In
].waves
.end(); ++i
) {
1080 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1081 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1084 for (vector
<ArdourCanvas::WaveView
*>::iterator i
= fade
[Out
].waves
.begin(); i
!= fade
[Out
].waves
.end(); ++i
) {
1085 (*i
)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1086 (*i
)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1089 fade
[Out
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine
.get();
1090 fade
[In
].line
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine
.get();
1091 fade
[In
].shading
->hide();
1092 fade
[Out
].shading
->show();
1094 for (list
<Point
*>::iterator i
= fade
[In
].points
.begin(); i
!= fade
[In
].points
.end(); ++i
) {
1098 for (list
<Point
*>::iterator i
= fade
[Out
].points
.begin(); i
!= fade
[Out
].points
.end(); ++i
) {
1106 CrossfadeEditor::x_coordinate (double& xfract
) const
1108 xfract
= min (1.0, xfract
);
1109 xfract
= max (0.0, xfract
);
1111 return canvas_border
+ (xfract
* effective_width());
1115 CrossfadeEditor::y_coordinate (double& yfract
) const
1117 yfract
= min (1.0, yfract
);
1118 yfract
= max (0.0, yfract
);
1120 return (canvas
->get_allocation().get_height() - (canvas_border
)) - (yfract
* effective_height());
1124 CrossfadeEditor::make_waves (boost::shared_ptr
<AudioRegion
> region
, WhichFade which
)
1127 uint32_t nchans
= region
->n_channels();
1132 color
= ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave
.get();
1134 color
= ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave
.get();
1137 ht
= canvas
->get_allocation().get_height() / (double) nchans
;
1138 spu
= xfade
->length() / (double) effective_width();
1140 for (uint32_t n
= 0; n
< nchans
; ++n
) {
1142 gdouble yoff
= n
* ht
;
1144 if (region
->source(n
)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready
), region
, which
), peaks_ready_connection
)) {
1146 WaveView
* waveview
= new WaveView (*(canvas
->root()));
1148 waveview
->property_data_src() = region
.get();
1149 waveview
->property_cache_updater() = true;
1150 waveview
->property_cache() = WaveView::create_cache();
1151 waveview
->property_channel() = n
;
1152 waveview
->property_length_function() = (void*) region_length_from_c
;
1153 waveview
->property_sourcefile_length_function() = (void*) sourcefile_length_from_c
;
1154 waveview
->property_peak_function() = (void*) region_read_peaks_from_c
;
1155 waveview
->property_gain_function() = (void*) curve_get_vector_from_c
;
1156 waveview
->property_gain_src() = &fade
[which
].gain_curve
;
1157 waveview
->property_x() = canvas_border
;
1158 waveview
->property_y() = yoff
;
1159 waveview
->property_height() = ht
;
1160 waveview
->property_samples_per_unit() = spu
;
1161 waveview
->property_amplitude_above_axis() = 2.0;
1162 waveview
->property_wave_color() = color
;
1163 waveview
->property_fill_color() = color
;
1166 waveview
->property_region_start() = region
->start();
1168 waveview
->property_region_start() = region
->start()+region
->length()-xfade
->length();
1170 waveview
->lower_to_bottom();
1171 fade
[which
].waves
.push_back (waveview
);
1175 toplevel
->lower_to_bottom();
1179 CrossfadeEditor::peaks_ready (boost::shared_ptr
<AudioRegion
> r
, WhichFade which
)
1181 /* this should never be called, because the peak files for an xfade
1182 will be ready by the time we want them. but our API forces us
1183 to provide this, so ..
1185 peaks_ready_connection
.disconnect ();
1186 make_waves (r
, which
);
1190 CrossfadeEditor::audition (Audition which
)
1192 AudioPlaylist
& pl (session
.the_auditioner()->prepare_playlist());
1195 nframes_t left_start_offset
;
1196 nframes_t right_length
;
1197 nframes_t left_length
;
1199 if (which
!= Right
&& preroll_button
.get_active()) {
1200 preroll
= session
.frame_rate() * 2; //2 second hardcoded preroll for now
1205 if (which
!= Left
&& postroll_button
.get_active()) {
1206 postroll
= session
.frame_rate() * 2; //2 second hardcoded postroll for now
1211 // Is there enough data for the whole preroll?
1212 left_length
= xfade
->length();
1213 if ((left_start_offset
= xfade
->out()->length() - xfade
->length()) > preroll
) {
1214 left_start_offset
-= preroll
;
1216 preroll
= left_start_offset
;
1217 left_start_offset
= 0;
1219 left_length
+= preroll
;
1221 // Is there enough data for the whole postroll?
1222 right_length
= xfade
->length();
1223 if ((xfade
->in()->length() - right_length
) > postroll
) {
1224 right_length
+= postroll
;
1226 right_length
= xfade
->in()->length();
1229 boost::shared_ptr
<AudioRegion
> left (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->out(), left_start_offset
, left_length
, "xfade out",
1230 0, Region::DefaultFlags
, false)));
1231 boost::shared_ptr
<AudioRegion
> right (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->in(), 0, right_length
, "xfade in",
1232 0, Region::DefaultFlags
, false)));
1234 //apply a 20ms declicking fade at the start and end of auditioning
1235 left
->set_fade_in_active(true);
1236 left
->set_fade_in_length(session
.frame_rate() / 50);
1237 right
->set_fade_out_active(true);
1238 right
->set_fade_out_length(session
.frame_rate() / 50);
1240 pl
.add_region (left
, 0);
1241 pl
.add_region (right
, 1 + preroll
);
1243 if (which
== Left
) {
1244 right
->set_scale_amplitude (0.0);
1245 } else if (which
== Right
) {
1246 left
->set_scale_amplitude (0.0);
1249 /* there is only one ... */
1250 pl
.foreach_crossfade (this, &CrossfadeEditor::setup
);
1252 session
.audition_playlist ();
1256 CrossfadeEditor::audition_both ()
1262 CrossfadeEditor::audition_left_dry ()
1264 boost::shared_ptr
<AudioRegion
> left (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->out(), xfade
->out()->length() - xfade
->length(), xfade
->length(), "xfade left",
1265 0, Region::DefaultFlags
, false)));
1267 session
.audition_region (left
);
1271 CrossfadeEditor::audition_left ()
1277 CrossfadeEditor::audition_right_dry ()
1279 boost::shared_ptr
<AudioRegion
> right (boost::dynamic_pointer_cast
<AudioRegion
> (RegionFactory::create (xfade
->in(), 0, xfade
->length(), "xfade in",
1280 0, Region::DefaultFlags
, false)));
1281 session
.audition_region (right
);
1285 CrossfadeEditor::audition_right ()
1291 CrossfadeEditor::cancel_audition ()
1293 session
.cancel_audition ();
1297 CrossfadeEditor::audition_toggled ()
1301 if ((x
= audition_both_button
.get_active ()) != session
.is_auditioning()) {
1312 CrossfadeEditor::audition_right_toggled ()
1316 if ((x
= audition_right_button
.get_active ()) != session
.is_auditioning()) {
1327 CrossfadeEditor::audition_right_dry_toggled ()
1331 if ((x
= audition_right_dry_button
.get_active ()) != session
.is_auditioning()) {
1334 audition_right_dry ();
1342 CrossfadeEditor::audition_left_toggled ()
1346 if ((x
= audition_left_button
.get_active ()) != session
.is_auditioning()) {
1357 CrossfadeEditor::audition_left_dry_toggled ()
1361 if ((x
= audition_left_dry_button
.get_active ()) != session
.is_auditioning()) {
1364 audition_left_dry ();
1372 CrossfadeEditor::on_key_press_event (GdkEventKey
*ev
)
1378 CrossfadeEditor::on_key_release_event (GdkEventKey
* ev
)
1380 switch (ev
->keyval
) {
1382 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1383 audition_right_dry_button
.set_active (!audition_right_dry_button
.get_active());
1385 audition_right_button
.set_active (!audition_right_button
.get_active());
1390 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1391 audition_left_dry_button
.set_active (!audition_left_dry_button
.get_active());
1393 audition_left_button
.set_active (!audition_left_button
.get_active());
1398 if (session
.is_auditioning()) {
1401 audition_both_button
.set_active (!audition_both_button
.get_active());