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>
29 #include "pbd/memento_command.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"
39 #include "ardour/crossfade_binder.h"
41 #include <gtkmm2ext/gtk_ui.h>
43 #include "canvas/rectangle.h"
44 #include "canvas/wave_view.h"
45 #include "canvas/line.h"
46 #include "canvas/polygon.h"
48 #include "ardour_ui.h"
49 #include "crossfade_edit.h"
50 #include "rgb_macros.h"
53 #include "gui_thread.h"
57 using namespace ARDOUR;
60 using namespace Editing;
62 using Gtkmm2ext::Keyboard;
66 const int32_t CrossfadeEditor::Point::size = 7;
67 const double CrossfadeEditor::canvas_border = 10;
68 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
69 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
71 CrossfadeEditor::Half::Half ()
73 , normative_curve (Evoral::Parameter(GainAutomation))
74 , gain_curve (Evoral::Parameter(GainAutomation))
78 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
79 : ArdourDialog (_("Edit Crossfade")),
81 clear_button (_("Clear")),
82 revert_button (_("Reset")),
83 audition_both_button (_("Fade")),
84 audition_left_dry_button (_("Out (dry)")),
85 audition_left_button (_("Out")),
86 audition_right_dry_button (_("In (dry)")),
87 audition_right_button (_("In")),
89 preroll_button (_("With Pre-roll")),
90 postroll_button (_("With Post-roll")),
96 fade_out_table (3, 3),
98 select_in_button (_("Fade In")),
99 select_out_button (_("Fade Out")),
101 _peaks_ready_connection (0)
106 set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
107 set_name ("CrossfadeEditWindow");
108 set_position (Gtk::WIN_POS_MOUSE);
110 add_accel_group (ActionManager::ui_manager->get_accel_group());
112 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
114 RadioButtonGroup sel_but_group = select_in_button.get_group();
115 select_out_button.set_group (sel_but_group);
116 select_out_button.set_mode (false);
117 select_in_button.set_mode (false);
119 get_action_area()->set_layout(BUTTONBOX_SPREAD);
120 get_action_area()->pack_start(clear_button);
121 get_action_area()->pack_start(revert_button);
122 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
123 ok_button = add_button ("OK", RESPONSE_ACCEPT);
125 if (fade_in_presets == 0) {
129 point_grabbed = false;
132 canvas = new ArdourCanvas::GtkCanvas ();
133 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
134 canvas->set_size_request (425, 200);
136 toplevel = new ArdourCanvas::Rectangle (canvas->root());
137 toplevel->set (ArdourCanvas::Rect (0, 0, 10, 10));
138 toplevel->set_fill (true);
139 toplevel->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorBase());
140 toplevel->set_outline (false);
141 toplevel->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
143 fade[Out].line = new ArdourCanvas::PolyLine (canvas->root());
144 fade[Out].line->set_outline_width (1);
145 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
147 fade[Out].shading = new ArdourCanvas::Polygon (canvas->root());
148 fade[Out].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
150 fade[In].line = new ArdourCanvas::PolyLine (canvas->root());
151 fade[In].line->set_outline_width (1);
152 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
154 fade[In].shading = new ArdourCanvas::Polygon (canvas->root());
155 fade[In].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
157 fade[In].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
158 fade[In].line->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
159 fade[Out].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
160 fade[Out].line->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), boost::bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
299 _session->AuditionActive.connect (_session_connections, invalidator (*this), boost::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 or vertically */
423 if (point == fade[current].points.front() || point == fade[current].points.back()) {
427 new_x = (event->motion.x - canvas_border)/effective_width();
428 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
431 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
443 CrossfadeEditor::canvas_event (GdkEvent* event)
445 switch (event->type) {
446 case GDK_BUTTON_PRESS:
447 add_control_point ((event->button.x - canvas_border)/effective_width(),
448 1.0 - ((event->button.y - canvas_border)/effective_height()));
457 CrossfadeEditor::Point::~Point()
462 CrossfadeEditor::Point*
463 CrossfadeEditor::make_point ()
465 Point* p = new Point;
467 p->box = new ArdourCanvas::Rectangle (canvas->root());
468 p->box->set_fill (true);
469 p->box->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointFill());
470 p->box->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointOutline());
471 p->box->set_outline_width (1);
473 p->curve = fade[current].line;
475 p->box->Event.connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
481 CrossfadeEditor::add_control_point (double x, double y)
485 /* enforce end point x location */
487 if (fade[current].points.empty()) {
489 } else if (fade[current].points.size() == 1) {
493 Point* p = make_point ();
495 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
497 fade[current].points.push_back (p);
498 fade[current].points.sort (cmp);
504 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
506 if ( xfract < 0.0 ) {
508 } else if ( xfract > 1.0 ) {
512 if ( yfract < 0.0 ) {
514 } else if ( yfract > 1.0 ) {
518 const double half_size = rint(size/2.0);
519 double x1 = nx - half_size;
520 double x2 = nx + half_size;
522 box->set (ArdourCanvas::Rect (x1, ny - half_size, x2, ny + half_size));
529 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
536 canvas->get_allocation().get_width() + canvas_border,
537 canvas->get_allocation().get_height() + canvas_border
543 // canvas->set_scroll_region (0.0, 0.0,
544 // canvas->get_allocation().get_width(),
545 // canvas->get_allocation().get_height());
547 Point* end = make_point ();
550 if (fade[In].points.size() > 1) {
551 Point* old_end = fade[In].points.back();
552 fade[In].points.pop_back ();
553 end->move_to (x_coordinate (old_end->x),
554 y_coordinate (old_end->y),
555 old_end->x, old_end->y);
560 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
564 fade[In].points.push_back (end);
565 fade[In].points.sort (cmp);
567 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
568 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
574 if (fade[Out].points.size() > 1) {
575 Point* old_end = fade[Out].points.back();
576 fade[Out].points.pop_back ();
577 end->move_to (x_coordinate (old_end->x),
578 y_coordinate (old_end->y),
579 old_end->x, old_end->y);
584 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
588 fade[Out].points.push_back (end);
589 fade[Out].points.sort (cmp);
591 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
592 (*i)->move_to (x_coordinate ((*i)->x),
593 y_coordinate ((*i)->y),
597 WhichFade old_current = current;
602 current = old_current;
604 double spu = xfade->length() / (double) effective_width();
606 if (fade[In].waves.empty()) {
607 make_waves (xfade->in(), In);
610 if (fade[Out].waves.empty()) {
611 make_waves (xfade->out(), Out);
615 vector<ArdourCanvas::WaveView*>::iterator i;
618 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
620 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
625 (*i)->set_y_position (yoff);
626 (*i)->set_height (ht);
627 (*i)->set_samples_per_pixel (spu);
630 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
632 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
637 (*i)->set_y_position (yoff);
638 (*i)->set_height (ht);
639 (*i)->set_samples_per_pixel (spu);
646 CrossfadeEditor::xfade_changed (const PropertyChange&)
648 set (xfade->fade_in(), In);
649 set (xfade->fade_out(), Out);
653 CrossfadeEditor::redraw ()
655 if (canvas->get_allocation().get_width() < 2) {
659 framecnt_t len = xfade->length ();
661 fade[current].normative_curve.clear ();
662 fade[current].gain_curve.clear ();
664 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
665 fade[current].normative_curve.add ((*i)->x, (*i)->y);
668 offset = xfade->in()->start();
670 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
671 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
675 size_t npoints = (size_t) effective_width();
678 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
680 ArdourCanvas::Points pts;
681 ArdourCanvas::Points spts;
683 while (pts.size() < npoints) {
684 pts.push_back (ArdourCanvas::Duple (0,0));
687 while (spts.size() < npoints + 3) {
688 spts.push_back (ArdourCanvas::Duple (0,0));
691 /* the shade coordinates *MUST* be in anti-clockwise order.
698 spts[0].x = canvas_border;
699 spts[0].y = effective_height() + canvas_border;
703 spts[1].x = effective_width() + canvas_border;
704 spts[1].y = effective_height() + canvas_border;
708 spts[2].x = effective_width() + canvas_border;
709 spts[2].y = canvas_border;
716 spts[0].x = canvas_border;
717 spts[0].y = canvas_border;
721 spts[1].x = canvas_border;
722 spts[1].y = effective_height() + canvas_border;
726 spts[2].x = effective_width() + canvas_border;
727 spts[2].y = effective_height() + canvas_border;
731 size_t last_spt = (npoints + 3) - 1;
733 for (size_t i = 0; i < npoints; ++i) {
737 pts[i].x = canvas_border + i;
738 pts[i].y = y_coordinate (y);
740 spts[last_spt - i].x = canvas_border + i;
741 spts[last_spt - i].y = pts[i].y;
744 fade[current].line->set (pts);
745 fade[current].shading->set (pts);
747 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
748 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
753 CrossfadeEditor::apply_preset (Preset *preset)
756 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
761 select_in_button.clicked();
763 select_out_button.clicked();
766 curve_select_clicked (wf);
769 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
773 fade[current].points.clear ();
775 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
776 Point* p = make_point ();
777 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
779 fade[current].points.push_back (p);
786 CrossfadeEditor::apply ()
788 _session->begin_reversible_command (_("Edit crossfade"));
790 XMLNode& before = xfade->get_state ();
794 _session->add_command (
795 new MementoCommand<Crossfade> (
796 new ARDOUR::CrossfadeBinder (_session->playlists, xfade->id ()),
797 &before, &xfade->get_state ()
801 _session->commit_reversible_command ();
805 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
807 ARDOUR::AutomationList& in (xf->fade_in());
808 ARDOUR::AutomationList& out (xf->fade_out());
813 ARDOUR::AutomationList::const_iterator the_end = in.end();
816 double firstx = (*in.begin())->when;
817 double endx = (*the_end)->when;
822 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
824 double when = firstx + ((*i)->x * (endx - firstx));
825 double value = (*i)->y;
826 in.add (when, value);
834 firstx = (*out.begin())->when;
835 endx = (*the_end)->when;
840 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
842 double when = firstx + ((*i)->x * (endx - firstx));
843 double value = (*i)->y;
844 out.add (when, value);
852 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
855 xfade->set_active (true);
856 xfade->fade_in().curve().solve ();
857 xfade->fade_out().curve().solve ();
861 CrossfadeEditor::clear ()
863 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
867 fade[current].points.clear ();
873 CrossfadeEditor::reset ()
875 set (xfade->fade_in(), In);
876 set (xfade->fade_out(), Out);
878 curve_select_clicked (current);
882 CrossfadeEditor::build_presets ()
886 fade_in_presets = new Presets;
887 fade_out_presets = new Presets;
891 p = new Preset ("Linear (-6dB)", "fadein-linear");
892 p->push_back (PresetPoint (0, 0));
893 p->push_back (PresetPoint (0.000000, 0.000000));
894 p->push_back (PresetPoint (0.166667, 0.166366));
895 p->push_back (PresetPoint (0.333333, 0.332853));
896 p->push_back (PresetPoint (0.500000, 0.499459));
897 p->push_back (PresetPoint (0.666667, 0.666186));
898 p->push_back (PresetPoint (0.833333, 0.833033));
899 p->push_back (PresetPoint (1.000000, 1.000000));
900 fade_in_presets->push_back (p);
902 p = new Preset ("S(1)-curve", "fadein-S1");
903 p->push_back (PresetPoint (0, 0));
904 p->push_back (PresetPoint (0.1, 0.01));
905 p->push_back (PresetPoint (0.2, 0.03));
906 p->push_back (PresetPoint (0.8, 0.97));
907 p->push_back (PresetPoint (0.9, 0.99));
908 p->push_back (PresetPoint (1, 1));
909 fade_in_presets->push_back (p);
911 p = new Preset ("S(2)-curve", "fadein-S2");
912 p->push_back (PresetPoint (0.0, 0.0));
913 p->push_back (PresetPoint (0.055, 0.222));
914 p->push_back (PresetPoint (0.163, 0.35));
915 p->push_back (PresetPoint (0.837, 0.678));
916 p->push_back (PresetPoint (0.945, 0.783));
917 p->push_back (PresetPoint (1.0, 1.0));
918 fade_in_presets->push_back (p);
920 p = new Preset ("Constant power (-3dB)", "fadein-constant-power");
922 p->push_back (PresetPoint (0.000000, 0.000000));
923 p->push_back (PresetPoint (0.166667, 0.282192));
924 p->push_back (PresetPoint (0.333333, 0.518174));
925 p->push_back (PresetPoint (0.500000, 0.707946));
926 p->push_back (PresetPoint (0.666667, 0.851507));
927 p->push_back (PresetPoint (0.833333, 0.948859));
928 p->push_back (PresetPoint (1.000000, 1.000000));
930 fade_in_presets->push_back (p);
932 if (!Profile->get_sae()) {
934 p = new Preset ("Short cut", "fadein-short-cut");
935 p->push_back (PresetPoint (0, 0));
936 p->push_back (PresetPoint (0.389401, 0.0333333));
937 p->push_back (PresetPoint (0.629032, 0.0861111));
938 p->push_back (PresetPoint (0.829493, 0.233333));
939 p->push_back (PresetPoint (0.9447, 0.483333));
940 p->push_back (PresetPoint (0.976959, 0.697222));
941 p->push_back (PresetPoint (1, 1));
942 fade_in_presets->push_back (p);
944 p = new Preset ("Slow cut", "fadein-slow-cut");
945 p->push_back (PresetPoint (0, 0));
946 p->push_back (PresetPoint (0.304147, 0.0694444));
947 p->push_back (PresetPoint (0.529954, 0.152778));
948 p->push_back (PresetPoint (0.725806, 0.333333));
949 p->push_back (PresetPoint (0.847926, 0.558333));
950 p->push_back (PresetPoint (0.919355, 0.730556));
951 p->push_back (PresetPoint (1, 1));
952 fade_in_presets->push_back (p);
954 p = new Preset ("Fast cut", "fadein-fast-cut");
955 p->push_back (PresetPoint (0, 0));
956 p->push_back (PresetPoint (0.0737327, 0.308333));
957 p->push_back (PresetPoint (0.246544, 0.658333));
958 p->push_back (PresetPoint (0.470046, 0.886111));
959 p->push_back (PresetPoint (0.652074, 0.972222));
960 p->push_back (PresetPoint (0.771889, 0.988889));
961 p->push_back (PresetPoint (1, 1));
962 fade_in_presets->push_back (p);
964 p = new Preset ("Long cut", "fadein-long-cut");
965 p->push_back (PresetPoint (0, 0));
966 p->push_back (PresetPoint (0.0207373, 0.197222));
967 p->push_back (PresetPoint (0.0645161, 0.525));
968 p->push_back (PresetPoint (0.152074, 0.802778));
969 p->push_back (PresetPoint (0.276498, 0.919444));
970 p->push_back (PresetPoint (0.481567, 0.980556));
971 p->push_back (PresetPoint (0.767281, 1));
972 p->push_back (PresetPoint (1, 1));
973 fade_in_presets->push_back (p);
978 // p = new Preset ("regout.xpm");
979 p = new Preset ("Linear (-6dB cut)", "fadeout-linear");
980 p->push_back (PresetPoint (0, 1));
981 p->push_back (PresetPoint (0.000000, 1.000000));
982 p->push_back (PresetPoint (0.166667, 0.833033));
983 p->push_back (PresetPoint (0.333333, 0.666186));
984 p->push_back (PresetPoint (0.500000, 0.499459));
985 p->push_back (PresetPoint (0.666667, 0.332853));
986 p->push_back (PresetPoint (0.833333, 0.166366));
987 p->push_back (PresetPoint (1.000000, 0.000000));
988 fade_out_presets->push_back (p);
990 p = new Preset ("S(1)-Curve", "fadeout-S1");
991 p->push_back (PresetPoint (0, 1));
992 p->push_back (PresetPoint (0.1, 0.99));
993 p->push_back (PresetPoint (0.2, 0.97));
994 p->push_back (PresetPoint (0.8, 0.03));
995 p->push_back (PresetPoint (0.9, 0.01));
996 p->push_back (PresetPoint (1, 0));
997 fade_out_presets->push_back (p);
999 p = new Preset ("S(2)-Curve", "fadeout-S2");
1000 p->push_back (PresetPoint (0.0, 1.0));
1001 p->push_back (PresetPoint (0.163, 0.678));
1002 p->push_back (PresetPoint (0.055, 0.783));
1003 p->push_back (PresetPoint (0.837, 0.35));
1004 p->push_back (PresetPoint (0.945, 0.222));
1005 p->push_back (PresetPoint (1.0, 0.0));
1006 fade_out_presets->push_back (p);
1008 // p = new Preset ("linout.xpm");
1009 p = new Preset ("Constant power (-3dB cut)", "fadeout-constant-power");
1010 p->push_back (PresetPoint (0.000000, 1.000000));
1011 p->push_back (PresetPoint (0.166667, 0.948859));
1012 p->push_back (PresetPoint (0.333333, 0.851507));
1013 p->push_back (PresetPoint (0.500000, 0.707946));
1014 p->push_back (PresetPoint (0.666667, 0.518174));
1015 p->push_back (PresetPoint (0.833333, 0.282192));
1016 p->push_back (PresetPoint (1.000000, 0.000000));
1017 fade_out_presets->push_back (p);
1019 if (!Profile->get_sae()) {
1020 // p = new Preset ("hiout.xpm");
1021 p = new Preset ("Short cut", "fadeout-short-cut");
1022 p->push_back (PresetPoint (0, 1));
1023 p->push_back (PresetPoint (0.305556, 1));
1024 p->push_back (PresetPoint (0.548611, 0.991736));
1025 p->push_back (PresetPoint (0.759259, 0.931129));
1026 p->push_back (PresetPoint (0.918981, 0.68595));
1027 p->push_back (PresetPoint (0.976852, 0.22865));
1028 p->push_back (PresetPoint (1, 0));
1029 fade_out_presets->push_back (p);
1031 p = new Preset ("Slow cut", "fadeout-slow-cut");
1032 p->push_back (PresetPoint (0, 1));
1033 p->push_back (PresetPoint (0.228111, 0.988889));
1034 p->push_back (PresetPoint (0.347926, 0.972222));
1035 p->push_back (PresetPoint (0.529954, 0.886111));
1036 p->push_back (PresetPoint (0.753456, 0.658333));
1037 p->push_back (PresetPoint (0.9262673, 0.308333));
1038 p->push_back (PresetPoint (1, 0));
1039 fade_out_presets->push_back (p);
1041 p = new Preset ("Fast cut", "fadeout-fast-cut");
1042 p->push_back (PresetPoint (0, 1));
1043 p->push_back (PresetPoint (0.080645, 0.730556));
1044 p->push_back (PresetPoint (0.277778, 0.289256));
1045 p->push_back (PresetPoint (0.470046, 0.152778));
1046 p->push_back (PresetPoint (0.695853, 0.0694444));
1047 p->push_back (PresetPoint (1, 0));
1048 fade_out_presets->push_back (p);
1050 // p = new Preset ("loout.xpm");
1051 p = new Preset ("Long cut", "fadeout-long-cut");
1052 p->push_back (PresetPoint (0, 1));
1053 p->push_back (PresetPoint (0.023041, 0.697222));
1054 p->push_back (PresetPoint (0.0553, 0.483333));
1055 p->push_back (PresetPoint (0.170507, 0.233333));
1056 p->push_back (PresetPoint (0.370968, 0.0861111));
1057 p->push_back (PresetPoint (0.610599, 0.0333333));
1058 p->push_back (PresetPoint (1, 0));
1059 fade_out_presets->push_back (p);
1065 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1071 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1072 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1073 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1076 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1077 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1078 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1081 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1082 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1083 fade[Out].shading->hide();
1084 fade[In].shading->show();
1086 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1090 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1096 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1097 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1098 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1101 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1102 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1103 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1106 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1107 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1108 fade[In].shading->hide();
1109 fade[Out].shading->show();
1111 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1115 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1123 CrossfadeEditor::x_coordinate (double& xfract) const
1125 xfract = min (1.0, xfract);
1126 xfract = max (0.0, xfract);
1128 return canvas_border + (xfract * effective_width());
1132 CrossfadeEditor::y_coordinate (double& yfract) const
1134 yfract = min (1.0, yfract);
1135 yfract = max (0.0, yfract);
1137 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1141 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1144 uint32_t nchans = region->n_channels();
1149 color = ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave();
1151 color = ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave();
1154 ht = canvas->get_allocation().get_height() / (double) nchans;
1155 spu = xfade->length() / (double) effective_width();
1157 delete _peaks_ready_connection;
1158 _peaks_ready_connection = 0;
1160 for (uint32_t n = 0; n < nchans; ++n) {
1162 gdouble yoff = n * ht;
1164 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1165 ArdourCanvas::WaveView* waveview = new ArdourCanvas::WaveView (canvas->root(), region);
1167 waveview->set_channel (n);
1168 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1169 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1170 waveview->set_x_position (canvas_border);
1171 waveview->set_y_position (yoff);
1172 waveview->set_height (ht);
1173 waveview->set_samples_per_pixel (spu);
1174 waveview->property_amplitude_above_axis() = 2.0;
1175 waveview->set_outline_color (color);
1176 waveview->set_fill_color (color);
1179 waveview->set_region_start (region->start());
1181 waveview->set_region_start (region->start() + region->length() - xfade->length());
1184 waveview->lower_to_bottom();
1185 fade[which].waves.push_back (waveview);
1189 toplevel->lower_to_bottom();
1193 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1195 boost::shared_ptr<AudioRegion> r (wr.lock());
1201 /* this should never be called, because the peak files for an xfade
1202 will be ready by the time we want them. but our API forces us
1203 to provide this, so ..
1205 delete _peaks_ready_connection;
1206 _peaks_ready_connection = 0;
1208 make_waves (r, which);
1212 CrossfadeEditor::audition (Audition which)
1214 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1216 framecnt_t postroll;
1217 framecnt_t left_start_offset;
1218 framecnt_t right_length;
1219 framecnt_t left_length;
1221 if (which != Right && preroll_button.get_active()) {
1222 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1227 if (which != Left && postroll_button.get_active()) {
1228 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1233 // Is there enough data for the whole preroll?
1234 left_length = xfade->length();
1235 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1236 left_start_offset -= preroll;
1238 preroll = left_start_offset;
1239 left_start_offset = 0;
1241 left_length += preroll;
1243 // Is there enough data for the whole postroll?
1244 right_length = xfade->length();
1245 if ((xfade->in()->length() - right_length) > postroll) {
1246 right_length += postroll;
1248 right_length = xfade->in()->length();
1251 PropertyList left_plist;
1252 PropertyList right_plist;
1255 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1256 left_plist.add (ARDOUR::Properties::length, left_length);
1257 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1258 left_plist.add (ARDOUR::Properties::layer, 0);
1259 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1261 right_plist.add (ARDOUR::Properties::start, 0);
1262 right_plist.add (ARDOUR::Properties::length, right_length);
1263 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1264 right_plist.add (ARDOUR::Properties::layer, 0);
1265 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1267 if (which == Left) {
1268 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1269 } else if (which == Right) {
1270 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1273 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1274 (RegionFactory::create (xfade->out(), left_plist, false)));
1275 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1276 (RegionFactory::create (xfade->in(), right_plist, false)));
1278 // apply a 20ms declicking fade at the start and end of auditioning
1279 // XXX this should really be a property
1281 left->set_fade_in_length (_session->frame_rate() / 50);
1282 right->set_fade_out_length (_session->frame_rate() / 50);
1284 pl.add_region (left, 0);
1285 pl.add_region (right, 1 + preroll);
1287 /* there is only one ... */
1288 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1290 _session->audition_playlist ();
1294 CrossfadeEditor::audition_both ()
1300 CrossfadeEditor::audition_left_dry ()
1304 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1305 plist.add (ARDOUR::Properties::length, xfade->length());
1306 plist.add (ARDOUR::Properties::name, string("xfade left"));
1307 plist.add (ARDOUR::Properties::layer, 0);
1309 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1310 (RegionFactory::create (xfade->out(), plist, false)));
1312 _session->audition_region (left);
1316 CrossfadeEditor::audition_left ()
1322 CrossfadeEditor::audition_right_dry ()
1326 plist.add (ARDOUR::Properties::start, 0);
1327 plist.add (ARDOUR::Properties::length, xfade->length());
1328 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1329 plist.add (ARDOUR::Properties::layer, 0);
1331 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1332 (RegionFactory::create (xfade->in(), plist, false)));
1334 _session->audition_region (right);
1338 CrossfadeEditor::audition_right ()
1344 CrossfadeEditor::cancel_audition ()
1346 _session->cancel_audition ();
1350 CrossfadeEditor::audition_toggled ()
1354 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1365 CrossfadeEditor::audition_right_toggled ()
1369 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1380 CrossfadeEditor::audition_right_dry_toggled ()
1384 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1387 audition_right_dry ();
1395 CrossfadeEditor::audition_left_toggled ()
1399 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1410 CrossfadeEditor::audition_left_dry_toggled ()
1414 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1417 audition_left_dry ();
1425 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1431 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1433 switch (ev->keyval) {
1435 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1436 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1438 audition_right_button.set_active (!audition_right_button.get_active());
1443 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1444 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1446 audition_left_button.set_active (!audition_left_button.get_active());
1451 if (_session->is_auditioning()) {
1454 audition_both_button.set_active (!audition_both_button.get_active());