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_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
146 fade[Out].shading = new ArdourCanvas::Polygon (canvas->root());
147 fade[Out].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
149 fade[In].line = new ArdourCanvas::PolyLine (canvas->root());
150 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
152 fade[In].shading = new ArdourCanvas::Polygon (canvas->root());
153 fade[In].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
155 fade[In].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
156 fade[In].line->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
157 fade[Out].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
158 fade[Out].line->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
160 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
161 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
163 select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
164 select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
166 HBox* acbox = manage (new HBox);
168 audition_box.set_border_width (7);
169 audition_box.set_spacing (5);
170 audition_box.set_homogeneous (false);
171 audition_box.pack_start (audition_left_dry_button, false, false);
172 audition_box.pack_start (audition_left_button, false, false);
173 audition_box.pack_start (audition_both_button, false, false);
174 audition_box.pack_start (audition_right_button, false, false);
175 audition_box.pack_start (audition_right_dry_button, false, false);
177 Frame* audition_frame = manage (new Frame (_("Audition")));
179 audition_frame->set_name (X_("CrossfadeEditFrame"));
180 audition_frame->add (audition_box);
182 acbox->pack_start (*audition_frame, true, false);
184 Frame* canvas_frame = manage (new Frame);
185 canvas_frame->add (*canvas);
186 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
188 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
189 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
199 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
201 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
202 pbutton = manage (new Button);
203 pbutton->add (*pxmap);
204 pbutton->set_name ("CrossfadeEditButton");
205 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
206 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
207 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
208 fade_in_buttons.push_back (pbutton);
221 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
223 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
224 pbutton = manage (new Button);
225 pbutton->add (*pxmap);
226 pbutton->set_name ("CrossfadeEditButton");
227 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
228 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
229 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
230 fade_out_buttons.push_back (pbutton);
240 clear_button.set_name ("CrossfadeEditButton");
241 revert_button.set_name ("CrossfadeEditButton");
242 ok_button->set_name ("CrossfadeEditButton");
243 cancel_button->set_name ("CrossfadeEditButton");
244 preroll_button.set_name ("CrossfadeEditButton");
245 postroll_button.set_name ("CrossfadeEditButton");
246 audition_both_button.set_name ("CrossfadeEditAuditionButton");
247 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
248 audition_left_button.set_name ("CrossfadeEditAuditionButton");
249 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
250 audition_right_button.set_name ("CrossfadeEditAuditionButton");
252 clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
253 revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
254 audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
255 audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
256 audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
257 audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
258 audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
260 roll_box.pack_start (preroll_button, false, false);
261 roll_box.pack_start (postroll_button, false, false);
263 Gtk::HBox* rcenter_box = manage (new HBox);
264 rcenter_box->pack_start (roll_box, true, false);
266 VBox* vpacker2 = manage (new (VBox));
268 vpacker2->set_border_width (12);
269 vpacker2->set_spacing (7);
270 vpacker2->pack_start (*acbox, false, false);
271 vpacker2->pack_start (*rcenter_box, false, false);
273 curve_button_box.set_spacing (7);
274 curve_button_box.pack_start (fade_out_table, false, false, 12);
275 curve_button_box.pack_start (*vpacker2, false, false, 12);
276 curve_button_box.pack_start (fade_in_table, false, false, 12);
278 get_vbox()->pack_start (*canvas_frame, true, true);
279 get_vbox()->pack_start (curve_button_box, false, false);
281 /* button to allow hackers to check the actual curve values */
283 // Button* foobut = manage (new Button ("dump"));
284 // foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
285 // vpacker.pack_start (*foobut, false, false);
288 set (xfade->fade_in(), In);
291 set (xfade->fade_out(), Out);
293 curve_select_clicked (In);
295 xfade->PropertyChanged.connect (state_connection, invalidator (*this), boost::bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
297 _session->AuditionActive.connect (_session_connections, invalidator (*this), boost::bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
301 CrossfadeEditor::~CrossfadeEditor()
303 /* most objects will be destroyed when the toplevel window is. */
305 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
309 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
313 delete _peaks_ready_connection;
317 CrossfadeEditor::dump ()
319 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
320 cerr << (*i)->when << ' ' << (*i)->value << endl;
325 CrossfadeEditor::audition_state_changed (bool yn)
327 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
330 audition_both_button.set_active (false);
331 audition_left_button.set_active (false);
332 audition_right_button.set_active (false);
333 audition_left_dry_button.set_active (false);
334 audition_right_dry_button.set_active (false);
339 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
342 ARDOUR::AutomationList::const_iterator the_end;
344 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
348 fade[which].points.clear ();
349 fade[which].gain_curve.clear ();
350 fade[which].normative_curve.clear ();
356 the_end = curve.end();
359 firstx = (*curve.begin())->when;
360 endx = (*the_end)->when;
362 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
364 double xfract = ((*i)->when - firstx) / (endx - firstx);
365 double yfract = ((*i)->value - miny) / (maxy - miny);
367 Point* p = make_point ();
369 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
372 fade[which].points.push_back (p);
375 /* no need to sort because curve is already time-ordered */
379 swap (which, current);
381 swap (which, current);
385 CrossfadeEditor::curve_event (GdkEvent* event)
387 /* treat it like a toplevel event */
389 return canvas_event (event);
393 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
396 if (point->curve != fade[current].line) {
400 switch (event->type) {
401 case GDK_BUTTON_PRESS:
402 point_grabbed = true;
404 case GDK_BUTTON_RELEASE:
405 point_grabbed = false;
407 if (Keyboard::is_delete_event (&event->button)) {
408 fade[current].points.remove (point);
415 case GDK_MOTION_NOTIFY:
419 /* can't drag first or last points horizontally or vertically */
421 if (point == fade[current].points.front() || point == fade[current].points.back()) {
425 new_x = (event->motion.x - canvas_border)/effective_width();
426 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
429 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
441 CrossfadeEditor::canvas_event (GdkEvent* event)
443 switch (event->type) {
444 case GDK_BUTTON_PRESS:
445 add_control_point ((event->button.x - canvas_border)/effective_width(),
446 1.0 - ((event->button.y - canvas_border)/effective_height()));
455 CrossfadeEditor::Point::~Point()
460 CrossfadeEditor::Point*
461 CrossfadeEditor::make_point ()
463 Point* p = new Point;
465 p->box = new ArdourCanvas::Rectangle (canvas->root());
466 p->box->set_fill (true);
467 p->box->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointFill());
468 p->box->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointOutline());
470 p->curve = fade[current].line;
472 p->box->Event.connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
478 CrossfadeEditor::add_control_point (double x, double y)
482 /* enforce end point x location */
484 if (fade[current].points.empty()) {
486 } else if (fade[current].points.size() == 1) {
490 Point* p = make_point ();
492 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
494 fade[current].points.push_back (p);
495 fade[current].points.sort (cmp);
501 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
503 if ( xfract < 0.0 ) {
505 } else if ( xfract > 1.0 ) {
509 if ( yfract < 0.0 ) {
511 } else if ( yfract > 1.0 ) {
515 const double half_size = rint(size/2.0);
516 double x1 = nx - half_size;
517 double x2 = nx + half_size;
519 box->set (ArdourCanvas::Rect (x1, ny - half_size, x2, ny + half_size));
526 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
533 canvas->get_allocation().get_width() + canvas_border,
534 canvas->get_allocation().get_height() + canvas_border
540 // canvas->set_scroll_region (0.0, 0.0,
541 // canvas->get_allocation().get_width(),
542 // canvas->get_allocation().get_height());
544 Point* end = make_point ();
547 if (fade[In].points.size() > 1) {
548 Point* old_end = fade[In].points.back();
549 fade[In].points.pop_back ();
550 end->move_to (x_coordinate (old_end->x),
551 y_coordinate (old_end->y),
552 old_end->x, old_end->y);
557 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
561 fade[In].points.push_back (end);
562 fade[In].points.sort (cmp);
564 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
565 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
571 if (fade[Out].points.size() > 1) {
572 Point* old_end = fade[Out].points.back();
573 fade[Out].points.pop_back ();
574 end->move_to (x_coordinate (old_end->x),
575 y_coordinate (old_end->y),
576 old_end->x, old_end->y);
581 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
585 fade[Out].points.push_back (end);
586 fade[Out].points.sort (cmp);
588 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
589 (*i)->move_to (x_coordinate ((*i)->x),
590 y_coordinate ((*i)->y),
594 WhichFade old_current = current;
599 current = old_current;
601 double spu = xfade->length() / (double) effective_width();
603 if (fade[In].waves.empty()) {
604 make_waves (xfade->in(), In);
607 if (fade[Out].waves.empty()) {
608 make_waves (xfade->out(), Out);
612 vector<ArdourCanvas::WaveView*>::iterator i;
615 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
617 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
622 (*i)->set_y_position (yoff);
623 (*i)->set_height (ht);
624 (*i)->set_samples_per_pixel (spu);
627 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
629 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
634 (*i)->set_y_position (yoff);
635 (*i)->set_height (ht);
636 (*i)->set_samples_per_pixel (spu);
643 CrossfadeEditor::xfade_changed (const PropertyChange&)
645 set (xfade->fade_in(), In);
646 set (xfade->fade_out(), Out);
650 CrossfadeEditor::redraw ()
652 if (canvas->get_allocation().get_width() < 2) {
656 framecnt_t len = xfade->length ();
658 fade[current].normative_curve.clear ();
659 fade[current].gain_curve.clear ();
661 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
662 fade[current].normative_curve.add ((*i)->x, (*i)->y);
665 offset = xfade->in()->start();
667 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
668 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
672 size_t npoints = (size_t) effective_width();
675 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
677 ArdourCanvas::Points pts;
678 ArdourCanvas::Points spts;
680 while (pts.size() < npoints) {
681 pts.push_back (ArdourCanvas::Duple (0,0));
684 while (spts.size() < npoints + 3) {
685 spts.push_back (ArdourCanvas::Duple (0,0));
688 /* the shade coordinates *MUST* be in anti-clockwise order.
695 spts[0].x = canvas_border;
696 spts[0].y = effective_height() + canvas_border;
700 spts[1].x = effective_width() + canvas_border;
701 spts[1].y = effective_height() + canvas_border;
705 spts[2].x = effective_width() + canvas_border;
706 spts[2].y = canvas_border;
713 spts[0].x = canvas_border;
714 spts[0].y = canvas_border;
718 spts[1].x = canvas_border;
719 spts[1].y = effective_height() + canvas_border;
723 spts[2].x = effective_width() + canvas_border;
724 spts[2].y = effective_height() + canvas_border;
728 size_t last_spt = (npoints + 3) - 1;
730 for (size_t i = 0; i < npoints; ++i) {
734 pts[i].x = canvas_border + i;
735 pts[i].y = y_coordinate (y);
737 spts[last_spt - i].x = canvas_border + i;
738 spts[last_spt - i].y = pts[i].y;
741 fade[current].line->set (pts);
742 fade[current].shading->set (pts);
744 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
745 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
750 CrossfadeEditor::apply_preset (Preset *preset)
753 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
758 select_in_button.clicked();
760 select_out_button.clicked();
763 curve_select_clicked (wf);
766 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
770 fade[current].points.clear ();
772 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
773 Point* p = make_point ();
774 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
776 fade[current].points.push_back (p);
783 CrossfadeEditor::apply ()
785 _session->begin_reversible_command (_("Edit crossfade"));
787 XMLNode& before = xfade->get_state ();
791 _session->add_command (
792 new MementoCommand<Crossfade> (
793 new ARDOUR::CrossfadeBinder (_session->playlists, xfade->id ()),
794 &before, &xfade->get_state ()
798 _session->commit_reversible_command ();
802 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
804 ARDOUR::AutomationList& in (xf->fade_in());
805 ARDOUR::AutomationList& out (xf->fade_out());
810 ARDOUR::AutomationList::const_iterator the_end = in.end();
813 double firstx = (*in.begin())->when;
814 double endx = (*the_end)->when;
819 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
821 double when = firstx + ((*i)->x * (endx - firstx));
822 double value = (*i)->y;
823 in.add (when, value);
831 firstx = (*out.begin())->when;
832 endx = (*the_end)->when;
837 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
839 double when = firstx + ((*i)->x * (endx - firstx));
840 double value = (*i)->y;
841 out.add (when, value);
849 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
852 xfade->set_active (true);
853 xfade->fade_in().curve().solve ();
854 xfade->fade_out().curve().solve ();
858 CrossfadeEditor::clear ()
860 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
864 fade[current].points.clear ();
870 CrossfadeEditor::reset ()
872 set (xfade->fade_in(), In);
873 set (xfade->fade_out(), Out);
875 curve_select_clicked (current);
879 CrossfadeEditor::build_presets ()
883 fade_in_presets = new Presets;
884 fade_out_presets = new Presets;
888 p = new Preset ("Linear (-6dB)", "fadein-linear");
889 p->push_back (PresetPoint (0, 0));
890 p->push_back (PresetPoint (0.000000, 0.000000));
891 p->push_back (PresetPoint (0.166667, 0.166366));
892 p->push_back (PresetPoint (0.333333, 0.332853));
893 p->push_back (PresetPoint (0.500000, 0.499459));
894 p->push_back (PresetPoint (0.666667, 0.666186));
895 p->push_back (PresetPoint (0.833333, 0.833033));
896 p->push_back (PresetPoint (1.000000, 1.000000));
897 fade_in_presets->push_back (p);
899 p = new Preset ("S(1)-curve", "fadein-S1");
900 p->push_back (PresetPoint (0, 0));
901 p->push_back (PresetPoint (0.1, 0.01));
902 p->push_back (PresetPoint (0.2, 0.03));
903 p->push_back (PresetPoint (0.8, 0.97));
904 p->push_back (PresetPoint (0.9, 0.99));
905 p->push_back (PresetPoint (1, 1));
906 fade_in_presets->push_back (p);
908 p = new Preset ("S(2)-curve", "fadein-S2");
909 p->push_back (PresetPoint (0.0, 0.0));
910 p->push_back (PresetPoint (0.055, 0.222));
911 p->push_back (PresetPoint (0.163, 0.35));
912 p->push_back (PresetPoint (0.837, 0.678));
913 p->push_back (PresetPoint (0.945, 0.783));
914 p->push_back (PresetPoint (1.0, 1.0));
915 fade_in_presets->push_back (p);
917 p = new Preset ("Constant power (-3dB)", "fadein-constant-power");
919 p->push_back (PresetPoint (0.000000, 0.000000));
920 p->push_back (PresetPoint (0.166667, 0.282192));
921 p->push_back (PresetPoint (0.333333, 0.518174));
922 p->push_back (PresetPoint (0.500000, 0.707946));
923 p->push_back (PresetPoint (0.666667, 0.851507));
924 p->push_back (PresetPoint (0.833333, 0.948859));
925 p->push_back (PresetPoint (1.000000, 1.000000));
927 fade_in_presets->push_back (p);
929 if (!Profile->get_sae()) {
931 p = new Preset ("Short cut", "fadein-short-cut");
932 p->push_back (PresetPoint (0, 0));
933 p->push_back (PresetPoint (0.389401, 0.0333333));
934 p->push_back (PresetPoint (0.629032, 0.0861111));
935 p->push_back (PresetPoint (0.829493, 0.233333));
936 p->push_back (PresetPoint (0.9447, 0.483333));
937 p->push_back (PresetPoint (0.976959, 0.697222));
938 p->push_back (PresetPoint (1, 1));
939 fade_in_presets->push_back (p);
941 p = new Preset ("Slow cut", "fadein-slow-cut");
942 p->push_back (PresetPoint (0, 0));
943 p->push_back (PresetPoint (0.304147, 0.0694444));
944 p->push_back (PresetPoint (0.529954, 0.152778));
945 p->push_back (PresetPoint (0.725806, 0.333333));
946 p->push_back (PresetPoint (0.847926, 0.558333));
947 p->push_back (PresetPoint (0.919355, 0.730556));
948 p->push_back (PresetPoint (1, 1));
949 fade_in_presets->push_back (p);
951 p = new Preset ("Fast cut", "fadein-fast-cut");
952 p->push_back (PresetPoint (0, 0));
953 p->push_back (PresetPoint (0.0737327, 0.308333));
954 p->push_back (PresetPoint (0.246544, 0.658333));
955 p->push_back (PresetPoint (0.470046, 0.886111));
956 p->push_back (PresetPoint (0.652074, 0.972222));
957 p->push_back (PresetPoint (0.771889, 0.988889));
958 p->push_back (PresetPoint (1, 1));
959 fade_in_presets->push_back (p);
961 p = new Preset ("Long cut", "fadein-long-cut");
962 p->push_back (PresetPoint (0, 0));
963 p->push_back (PresetPoint (0.0207373, 0.197222));
964 p->push_back (PresetPoint (0.0645161, 0.525));
965 p->push_back (PresetPoint (0.152074, 0.802778));
966 p->push_back (PresetPoint (0.276498, 0.919444));
967 p->push_back (PresetPoint (0.481567, 0.980556));
968 p->push_back (PresetPoint (0.767281, 1));
969 p->push_back (PresetPoint (1, 1));
970 fade_in_presets->push_back (p);
975 // p = new Preset ("regout.xpm");
976 p = new Preset ("Linear (-6dB cut)", "fadeout-linear");
977 p->push_back (PresetPoint (0, 1));
978 p->push_back (PresetPoint (0.000000, 1.000000));
979 p->push_back (PresetPoint (0.166667, 0.833033));
980 p->push_back (PresetPoint (0.333333, 0.666186));
981 p->push_back (PresetPoint (0.500000, 0.499459));
982 p->push_back (PresetPoint (0.666667, 0.332853));
983 p->push_back (PresetPoint (0.833333, 0.166366));
984 p->push_back (PresetPoint (1.000000, 0.000000));
985 fade_out_presets->push_back (p);
987 p = new Preset ("S(1)-Curve", "fadeout-S1");
988 p->push_back (PresetPoint (0, 1));
989 p->push_back (PresetPoint (0.1, 0.99));
990 p->push_back (PresetPoint (0.2, 0.97));
991 p->push_back (PresetPoint (0.8, 0.03));
992 p->push_back (PresetPoint (0.9, 0.01));
993 p->push_back (PresetPoint (1, 0));
994 fade_out_presets->push_back (p);
996 p = new Preset ("S(2)-Curve", "fadeout-S2");
997 p->push_back (PresetPoint (0.0, 1.0));
998 p->push_back (PresetPoint (0.163, 0.678));
999 p->push_back (PresetPoint (0.055, 0.783));
1000 p->push_back (PresetPoint (0.837, 0.35));
1001 p->push_back (PresetPoint (0.945, 0.222));
1002 p->push_back (PresetPoint (1.0, 0.0));
1003 fade_out_presets->push_back (p);
1005 // p = new Preset ("linout.xpm");
1006 p = new Preset ("Constant power (-3dB cut)", "fadeout-constant-power");
1007 p->push_back (PresetPoint (0.000000, 1.000000));
1008 p->push_back (PresetPoint (0.166667, 0.948859));
1009 p->push_back (PresetPoint (0.333333, 0.851507));
1010 p->push_back (PresetPoint (0.500000, 0.707946));
1011 p->push_back (PresetPoint (0.666667, 0.518174));
1012 p->push_back (PresetPoint (0.833333, 0.282192));
1013 p->push_back (PresetPoint (1.000000, 0.000000));
1014 fade_out_presets->push_back (p);
1016 if (!Profile->get_sae()) {
1017 // p = new Preset ("hiout.xpm");
1018 p = new Preset ("Short cut", "fadeout-short-cut");
1019 p->push_back (PresetPoint (0, 1));
1020 p->push_back (PresetPoint (0.305556, 1));
1021 p->push_back (PresetPoint (0.548611, 0.991736));
1022 p->push_back (PresetPoint (0.759259, 0.931129));
1023 p->push_back (PresetPoint (0.918981, 0.68595));
1024 p->push_back (PresetPoint (0.976852, 0.22865));
1025 p->push_back (PresetPoint (1, 0));
1026 fade_out_presets->push_back (p);
1028 p = new Preset ("Slow cut", "fadeout-slow-cut");
1029 p->push_back (PresetPoint (0, 1));
1030 p->push_back (PresetPoint (0.228111, 0.988889));
1031 p->push_back (PresetPoint (0.347926, 0.972222));
1032 p->push_back (PresetPoint (0.529954, 0.886111));
1033 p->push_back (PresetPoint (0.753456, 0.658333));
1034 p->push_back (PresetPoint (0.9262673, 0.308333));
1035 p->push_back (PresetPoint (1, 0));
1036 fade_out_presets->push_back (p);
1038 p = new Preset ("Fast cut", "fadeout-fast-cut");
1039 p->push_back (PresetPoint (0, 1));
1040 p->push_back (PresetPoint (0.080645, 0.730556));
1041 p->push_back (PresetPoint (0.277778, 0.289256));
1042 p->push_back (PresetPoint (0.470046, 0.152778));
1043 p->push_back (PresetPoint (0.695853, 0.0694444));
1044 p->push_back (PresetPoint (1, 0));
1045 fade_out_presets->push_back (p);
1047 // p = new Preset ("loout.xpm");
1048 p = new Preset ("Long cut", "fadeout-long-cut");
1049 p->push_back (PresetPoint (0, 1));
1050 p->push_back (PresetPoint (0.023041, 0.697222));
1051 p->push_back (PresetPoint (0.0553, 0.483333));
1052 p->push_back (PresetPoint (0.170507, 0.233333));
1053 p->push_back (PresetPoint (0.370968, 0.0861111));
1054 p->push_back (PresetPoint (0.610599, 0.0333333));
1055 p->push_back (PresetPoint (1, 0));
1056 fade_out_presets->push_back (p);
1062 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1068 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1069 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1070 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1073 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1074 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1075 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1078 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1079 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1080 fade[Out].shading->hide();
1081 fade[In].shading->show();
1083 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1087 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1093 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1094 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1095 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1098 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1099 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1100 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1103 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1104 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1105 fade[In].shading->hide();
1106 fade[Out].shading->show();
1108 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1112 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1120 CrossfadeEditor::x_coordinate (double& xfract) const
1122 xfract = min (1.0, xfract);
1123 xfract = max (0.0, xfract);
1125 return canvas_border + (xfract * effective_width());
1129 CrossfadeEditor::y_coordinate (double& yfract) const
1131 yfract = min (1.0, yfract);
1132 yfract = max (0.0, yfract);
1134 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1138 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1141 uint32_t nchans = region->n_channels();
1146 color = ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave();
1148 color = ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave();
1151 ht = canvas->get_allocation().get_height() / (double) nchans;
1152 spu = xfade->length() / (double) effective_width();
1154 delete _peaks_ready_connection;
1155 _peaks_ready_connection = 0;
1157 for (uint32_t n = 0; n < nchans; ++n) {
1159 gdouble yoff = n * ht;
1161 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1162 ArdourCanvas::WaveView* waveview = new ArdourCanvas::WaveView (canvas->root(), region);
1164 waveview->set_channel (n);
1165 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1166 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1167 waveview->set_x_position (canvas_border);
1168 waveview->set_y_position (yoff);
1169 waveview->set_height (ht);
1170 waveview->set_samples_per_pixel (spu);
1171 waveview->property_amplitude_above_axis() = 2.0;
1172 waveview->set_outline_color (color);
1173 waveview->set_fill_color (color);
1176 waveview->set_region_start (region->start() + region->length() - xfade->length());
1179 waveview->lower_to_bottom();
1180 fade[which].waves.push_back (waveview);
1184 toplevel->lower_to_bottom();
1188 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1190 boost::shared_ptr<AudioRegion> r (wr.lock());
1196 /* this should never be called, because the peak files for an xfade
1197 will be ready by the time we want them. but our API forces us
1198 to provide this, so ..
1200 delete _peaks_ready_connection;
1201 _peaks_ready_connection = 0;
1203 make_waves (r, which);
1207 CrossfadeEditor::audition (Audition which)
1209 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1211 framecnt_t postroll;
1212 framecnt_t left_start_offset;
1213 framecnt_t right_length;
1214 framecnt_t left_length;
1216 if (which != Right && preroll_button.get_active()) {
1217 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1222 if (which != Left && postroll_button.get_active()) {
1223 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1228 // Is there enough data for the whole preroll?
1229 left_length = xfade->length();
1230 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1231 left_start_offset -= preroll;
1233 preroll = left_start_offset;
1234 left_start_offset = 0;
1236 left_length += preroll;
1238 // Is there enough data for the whole postroll?
1239 right_length = xfade->length();
1240 if ((xfade->in()->length() - right_length) > postroll) {
1241 right_length += postroll;
1243 right_length = xfade->in()->length();
1246 PropertyList left_plist;
1247 PropertyList right_plist;
1250 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1251 left_plist.add (ARDOUR::Properties::length, left_length);
1252 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1253 left_plist.add (ARDOUR::Properties::layer, 0);
1254 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1256 right_plist.add (ARDOUR::Properties::start, 0);
1257 right_plist.add (ARDOUR::Properties::length, right_length);
1258 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1259 right_plist.add (ARDOUR::Properties::layer, 0);
1260 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1262 if (which == Left) {
1263 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1264 } else if (which == Right) {
1265 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1268 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1269 (RegionFactory::create (xfade->out(), left_plist, false)));
1270 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1271 (RegionFactory::create (xfade->in(), right_plist, false)));
1273 // apply a 20ms declicking fade at the start and end of auditioning
1274 // XXX this should really be a property
1276 left->set_fade_in_length (_session->frame_rate() / 50);
1277 right->set_fade_out_length (_session->frame_rate() / 50);
1279 pl.add_region (left, 0);
1280 pl.add_region (right, 1 + preroll);
1282 /* there is only one ... */
1283 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1285 _session->audition_playlist ();
1289 CrossfadeEditor::audition_both ()
1295 CrossfadeEditor::audition_left_dry ()
1299 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1300 plist.add (ARDOUR::Properties::length, xfade->length());
1301 plist.add (ARDOUR::Properties::name, string("xfade left"));
1302 plist.add (ARDOUR::Properties::layer, 0);
1304 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1305 (RegionFactory::create (xfade->out(), plist, false)));
1307 _session->audition_region (left);
1311 CrossfadeEditor::audition_left ()
1317 CrossfadeEditor::audition_right_dry ()
1321 plist.add (ARDOUR::Properties::start, 0);
1322 plist.add (ARDOUR::Properties::length, xfade->length());
1323 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1324 plist.add (ARDOUR::Properties::layer, 0);
1326 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1327 (RegionFactory::create (xfade->in(), plist, false)));
1329 _session->audition_region (right);
1333 CrossfadeEditor::audition_right ()
1339 CrossfadeEditor::cancel_audition ()
1341 _session->cancel_audition ();
1345 CrossfadeEditor::audition_toggled ()
1349 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1360 CrossfadeEditor::audition_right_toggled ()
1364 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1375 CrossfadeEditor::audition_right_dry_toggled ()
1379 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1382 audition_right_dry ();
1390 CrossfadeEditor::audition_left_toggled ()
1394 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1405 CrossfadeEditor::audition_left_dry_toggled ()
1409 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1412 audition_left_dry ();
1420 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1426 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1428 switch (ev->keyval) {
1430 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1431 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1433 audition_right_button.set_active (!audition_right_button.get_active());
1438 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1439 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1441 audition_left_button.set_active (!audition_left_button.get_active());
1446 if (_session->is_auditioning()) {
1449 audition_both_button.set_active (!audition_both_button.get_active());