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 "pbd/memento_command.h"
31 #include "ardour/automation_list.h"
32 #include "evoral/Curve.hpp"
33 #include "ardour/crossfade.h"
34 #include "ardour/session.h"
35 #include "ardour/auditioner.h"
36 #include "ardour/audioplaylist.h"
37 #include "ardour/audiosource.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;
58 using namespace Editing;
60 using Gtkmm2ext::Keyboard;
64 const int32_t CrossfadeEditor::Point::size = 7;
65 const double CrossfadeEditor::canvas_border = 10;
66 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
67 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
69 CrossfadeEditor::Half::Half ()
71 , normative_curve (Evoral::Parameter(GainAutomation))
72 , gain_curve (Evoral::Parameter(GainAutomation))
76 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
77 : ArdourDialog (_("Edit Crossfade")),
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 _peaks_ready_connection (0)
104 set_wmclass (X_("ardour_automationedit"), "Ardour");
105 set_name ("CrossfadeEditWindow");
106 set_position (Gtk::WIN_POS_MOUSE);
108 add_accel_group (ActionManager::ui_manager->get_accel_group());
110 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
112 RadioButtonGroup sel_but_group = select_in_button.get_group();
113 select_out_button.set_group (sel_but_group);
114 select_out_button.set_mode (false);
115 select_in_button.set_mode (false);
117 get_action_area()->set_layout(BUTTONBOX_SPREAD);
118 get_action_area()->pack_start(clear_button);
119 get_action_area()->pack_start(revert_button);
120 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
121 ok_button = add_button ("OK", RESPONSE_ACCEPT);
123 if (fade_in_presets == 0) {
127 point_grabbed = false;
130 canvas = new ArdourCanvas::CanvasAA ();
131 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
132 canvas->set_size_request (425, 200);
134 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
135 toplevel->property_x1() = 0.0;
136 toplevel->property_y1() = 0.0;
137 toplevel->property_x2() = 10.0;
138 toplevel->property_y2() = 10.0;
139 toplevel->property_fill() = true;
140 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
141 toplevel->property_outline_pixels() = 0;
142 toplevel->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
144 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
145 fade[Out].line->property_width_pixels() = 1;
146 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
148 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
149 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
151 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
152 fade[In].line->property_width_pixels() = 1;
153 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
155 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
156 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
158 fade[In].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
159 fade[In].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
160 fade[Out].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
161 fade[Out].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
163 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
164 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
166 select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
167 select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
169 HBox* acbox = manage (new HBox);
171 audition_box.set_border_width (7);
172 audition_box.set_spacing (5);
173 audition_box.set_homogeneous (false);
174 audition_box.pack_start (audition_left_dry_button, false, false);
175 audition_box.pack_start (audition_left_button, false, false);
176 audition_box.pack_start (audition_both_button, false, false);
177 audition_box.pack_start (audition_right_button, false, false);
178 audition_box.pack_start (audition_right_dry_button, false, false);
180 Frame* audition_frame = manage (new Frame (_("Audition")));
182 audition_frame->set_name (X_("CrossfadeEditFrame"));
183 audition_frame->add (audition_box);
185 acbox->pack_start (*audition_frame, true, false);
187 Frame* canvas_frame = manage (new Frame);
188 canvas_frame->add (*canvas);
189 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
191 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
192 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
202 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
204 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
205 pbutton = manage (new Button);
206 pbutton->add (*pxmap);
207 pbutton->set_name ("CrossfadeEditButton");
208 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
209 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
210 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
211 fade_in_buttons.push_back (pbutton);
224 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
226 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
227 pbutton = manage (new Button);
228 pbutton->add (*pxmap);
229 pbutton->set_name ("CrossfadeEditButton");
230 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
231 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
232 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
233 fade_out_buttons.push_back (pbutton);
243 clear_button.set_name ("CrossfadeEditButton");
244 revert_button.set_name ("CrossfadeEditButton");
245 ok_button->set_name ("CrossfadeEditButton");
246 cancel_button->set_name ("CrossfadeEditButton");
247 preroll_button.set_name ("CrossfadeEditButton");
248 postroll_button.set_name ("CrossfadeEditButton");
249 audition_both_button.set_name ("CrossfadeEditAuditionButton");
250 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
251 audition_left_button.set_name ("CrossfadeEditAuditionButton");
252 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
253 audition_right_button.set_name ("CrossfadeEditAuditionButton");
255 clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
256 revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
257 audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
258 audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
259 audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
260 audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
261 audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
263 roll_box.pack_start (preroll_button, false, false);
264 roll_box.pack_start (postroll_button, false, false);
266 Gtk::HBox* rcenter_box = manage (new HBox);
267 rcenter_box->pack_start (roll_box, true, false);
269 VBox* vpacker2 = manage (new (VBox));
271 vpacker2->set_border_width (12);
272 vpacker2->set_spacing (7);
273 vpacker2->pack_start (*acbox, false, false);
274 vpacker2->pack_start (*rcenter_box, false, false);
276 curve_button_box.set_spacing (7);
277 curve_button_box.pack_start (fade_out_table, false, false, 12);
278 curve_button_box.pack_start (*vpacker2, false, false, 12);
279 curve_button_box.pack_start (fade_in_table, false, false, 12);
281 get_vbox()->pack_start (*canvas_frame, true, true);
282 get_vbox()->pack_start (curve_button_box, false, false);
284 /* button to allow hackers to check the actual curve values */
286 // Button* foobut = manage (new Button ("dump"));
287 // foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
288 // vpacker.pack_start (*foobut, false, false);
291 set (xfade->fade_in(), In);
294 set (xfade->fade_out(), Out);
296 curve_select_clicked (In);
298 xfade->PropertyChanged.connect (state_connection, invalidator (*this), ui_bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
300 _session->AuditionActive.connect (_session_connections, invalidator (*this), ui_bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
304 CrossfadeEditor::~CrossfadeEditor()
306 /* most objects will be destroyed when the toplevel window is. */
308 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
312 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
316 delete _peaks_ready_connection;
320 CrossfadeEditor::dump ()
322 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
323 cerr << (*i)->when << ' ' << (*i)->value << endl;
328 CrossfadeEditor::audition_state_changed (bool yn)
330 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
333 audition_both_button.set_active (false);
334 audition_left_button.set_active (false);
335 audition_right_button.set_active (false);
336 audition_left_dry_button.set_active (false);
337 audition_right_dry_button.set_active (false);
342 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
345 ARDOUR::AutomationList::const_iterator the_end;
347 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
351 fade[which].points.clear ();
352 fade[which].gain_curve.clear ();
353 fade[which].normative_curve.clear ();
359 the_end = curve.end();
362 firstx = (*curve.begin())->when;
363 endx = (*the_end)->when;
365 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
367 double xfract = ((*i)->when - firstx) / (endx - firstx);
368 double yfract = ((*i)->value - miny) / (maxy - miny);
370 Point* p = make_point ();
372 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
375 fade[which].points.push_back (p);
378 /* no need to sort because curve is already time-ordered */
382 swap (which, current);
384 swap (which, current);
388 CrossfadeEditor::curve_event (GdkEvent* event)
390 /* treat it like a toplevel event */
392 return canvas_event (event);
396 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
399 if (point->curve != fade[current].line) {
403 switch (event->type) {
404 case GDK_BUTTON_PRESS:
405 point_grabbed = true;
407 case GDK_BUTTON_RELEASE:
408 point_grabbed = false;
410 if (Keyboard::is_delete_event (&event->button)) {
411 fade[current].points.remove (point);
418 case GDK_MOTION_NOTIFY:
422 /* can't drag first or last points horizontally */
424 if (point == fade[current].points.front() || point == fade[current].points.back()) {
427 new_x = (event->motion.x - canvas_border)/effective_width();
430 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::SimpleRect (*(canvas->root()));
468 p->box->property_fill() = true;
469 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
470 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
471 p->box->property_outline_pixels() = 1;
473 p->curve = fade[current].line;
475 p->box->signal_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->property_x1() = x1;
523 box->property_x2() = x2;
525 box->property_y1() = ny - half_size;
526 box->property_y2() = ny + half_size;
533 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
536 toplevel->property_x1() = 0.0;
537 toplevel->property_y1() = 0.0;
538 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
539 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
542 canvas->set_scroll_region (0.0, 0.0,
543 canvas->get_allocation().get_width(),
544 canvas->get_allocation().get_height());
546 Point* end = make_point ();
549 if (fade[In].points.size() > 1) {
550 Point* old_end = fade[In].points.back();
551 fade[In].points.pop_back ();
552 end->move_to (x_coordinate (old_end->x),
553 y_coordinate (old_end->y),
554 old_end->x, old_end->y);
559 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
563 fade[In].points.push_back (end);
564 fade[In].points.sort (cmp);
566 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
567 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
573 if (fade[Out].points.size() > 1) {
574 Point* old_end = fade[Out].points.back();
575 fade[Out].points.pop_back ();
576 end->move_to (x_coordinate (old_end->x),
577 y_coordinate (old_end->y),
578 old_end->x, old_end->y);
583 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
587 fade[Out].points.push_back (end);
588 fade[Out].points.sort (cmp);
590 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
591 (*i)->move_to (x_coordinate ((*i)->x),
592 y_coordinate ((*i)->y),
596 WhichFade old_current = current;
601 current = old_current;
603 double spu = xfade->length() / (double) effective_width();
605 if (fade[In].waves.empty()) {
606 make_waves (xfade->in(), In);
609 if (fade[Out].waves.empty()) {
610 make_waves (xfade->out(), Out);
614 vector<ArdourCanvas::WaveView*>::iterator i;
617 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
619 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
624 (*i)->property_y() = yoff;
625 (*i)->property_height() = ht;
626 (*i)->property_samples_per_unit() = spu;
629 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
631 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
636 (*i)->property_y() = yoff;
637 (*i)->property_height() = ht;
638 (*i)->property_samples_per_unit() = spu;
645 CrossfadeEditor::xfade_changed (const PropertyChange&)
647 set (xfade->fade_in(), In);
648 set (xfade->fade_out(), Out);
652 CrossfadeEditor::redraw ()
654 if (canvas->get_allocation().get_width() < 2) {
658 nframes_t len = xfade->length ();
660 fade[current].normative_curve.clear ();
661 fade[current].gain_curve.clear ();
663 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
664 fade[current].normative_curve.add ((*i)->x, (*i)->y);
667 offset = xfade->in()->start();
669 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
670 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
674 size_t npoints = (size_t) effective_width();
677 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
679 ArdourCanvas::Points pts;
680 ArdourCanvas::Points spts;
682 while (pts.size() < npoints) {
683 pts.push_back (Gnome::Art::Point (0,0));
686 while (spts.size() < npoints + 3) {
687 spts.push_back (Gnome::Art::Point (0,0));
690 /* the shade coordinates *MUST* be in anti-clockwise order.
697 spts[0].set_x (canvas_border);
698 spts[0].set_y (effective_height() + canvas_border);
702 spts[1].set_x (effective_width() + canvas_border);
703 spts[1].set_y (effective_height() + canvas_border);
707 spts[2].set_x (effective_width() + canvas_border);
708 spts[2].set_y (canvas_border);
715 spts[0].set_x (canvas_border);
716 spts[0].set_y (canvas_border);
720 spts[1].set_x (canvas_border);
721 spts[1].set_y (effective_height() + canvas_border);
725 spts[2].set_x (effective_width() + canvas_border);
726 spts[2].set_y (effective_height() + canvas_border);
730 size_t last_spt = (npoints + 3) - 1;
732 for (size_t i = 0; i < npoints; ++i) {
736 pts[i].set_x (canvas_border + i);
737 pts[i].set_y (y_coordinate (y));
739 spts[last_spt - i].set_x (canvas_border + i);
740 spts[last_spt - i].set_y (pts[i].get_y());
743 fade[current].line->property_points() = pts;
744 fade[current].shading->property_points() = spts;
746 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
747 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
752 CrossfadeEditor::apply_preset (Preset *preset)
755 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
760 select_in_button.clicked();
762 select_out_button.clicked();
765 curve_select_clicked (wf);
768 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
772 fade[current].points.clear ();
774 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
775 Point* p = make_point ();
776 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
778 fade[current].points.push_back (p);
785 CrossfadeEditor::apply ()
787 _session->begin_reversible_command (_("Edit crossfade"));
789 XMLNode& before = xfade->get_state ();
793 _session->add_command (new MementoCommand<Crossfade> (*xfade.get(), &before, &xfade->get_state()));
794 _session->commit_reversible_command ();
798 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
800 ARDOUR::AutomationList& in (xf->fade_in());
801 ARDOUR::AutomationList& out (xf->fade_out());
806 ARDOUR::AutomationList::const_iterator the_end = in.end();
809 double firstx = (*in.begin())->when;
810 double endx = (*the_end)->when;
811 double miny = in.get_min_y ();
812 double maxy = in.get_max_y ();
817 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
819 double when = firstx + ((*i)->x * (endx - firstx));
820 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
821 in.add (when, value);
829 firstx = (*out.begin())->when;
830 endx = (*the_end)->when;
831 miny = out.get_min_y ();
832 maxy = out.get_max_y ();
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; // miny + ((*i)->y * (maxy - miny));
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)", "crossfade-in-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", "crossfade-in-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", "crossfade-in-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)", "crossfade-in-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", "crossfade-in-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", "crossfade-in-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", "crossfade-in-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", "crossfade-in-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)", "crossfade-out-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", "crossfade-out-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", "crossfade-out-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)", "crossfade-out-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", "crossfade-out-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", "crossfade-out-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", "crossfade-out-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", "crossfade-out-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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1070 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1073 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1074 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1075 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1078 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1079 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1095 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1098 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1099 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1100 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1103 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1104 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
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()->canvasvar_SelectedCrossfadeEditorWave.get();
1148 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
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 WaveView* waveview = new WaveView (*(canvas->root()));
1164 waveview->property_data_src() = region.get();
1165 waveview->property_cache_updater() = true;
1166 waveview->property_cache() = WaveView::create_cache();
1167 waveview->property_channel() = n;
1168 waveview->property_length_function() = (void*) region_length_from_c;
1169 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1170 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1171 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1172 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1173 waveview->property_x() = canvas_border;
1174 waveview->property_y() = yoff;
1175 waveview->property_height() = ht;
1176 waveview->property_samples_per_unit() = spu;
1177 waveview->property_amplitude_above_axis() = 2.0;
1178 waveview->property_wave_color() = color;
1179 waveview->property_fill_color() = color;
1182 waveview->property_region_start() = region->start();
1184 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1186 waveview->lower_to_bottom();
1187 fade[which].waves.push_back (waveview);
1191 toplevel->lower_to_bottom();
1195 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1197 boost::shared_ptr<AudioRegion> r (wr.lock());
1203 /* this should never be called, because the peak files for an xfade
1204 will be ready by the time we want them. but our API forces us
1205 to provide this, so ..
1207 delete _peaks_ready_connection;
1208 _peaks_ready_connection = 0;
1210 make_waves (r, which);
1214 CrossfadeEditor::audition (Audition which)
1216 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1219 nframes_t left_start_offset;
1220 nframes_t right_length;
1221 nframes_t left_length;
1223 if (which != Right && preroll_button.get_active()) {
1224 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1229 if (which != Left && postroll_button.get_active()) {
1230 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1235 // Is there enough data for the whole preroll?
1236 left_length = xfade->length();
1237 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1238 left_start_offset -= preroll;
1240 preroll = left_start_offset;
1241 left_start_offset = 0;
1243 left_length += preroll;
1245 // Is there enough data for the whole postroll?
1246 right_length = xfade->length();
1247 if ((xfade->in()->length() - right_length) > postroll) {
1248 right_length += postroll;
1250 right_length = xfade->in()->length();
1253 PropertyList left_plist;
1254 PropertyList right_plist;
1257 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1258 left_plist.add (ARDOUR::Properties::length, left_length);
1259 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1260 left_plist.add (ARDOUR::Properties::layer, 0);
1261 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1263 right_plist.add (ARDOUR::Properties::start, 0);
1264 right_plist.add (ARDOUR::Properties::length, right_length);
1265 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1266 right_plist.add (ARDOUR::Properties::layer, 0);
1267 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1269 if (which == Left) {
1270 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1271 } else if (which == Right) {
1272 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1275 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1276 (RegionFactory::create (xfade->out(), left_plist, false)));
1277 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1278 (RegionFactory::create (xfade->in(), right_plist, false)));
1280 // apply a 20ms declicking fade at the start and end of auditioning
1281 // XXX this should really be a property
1283 left->set_fade_in_length (_session->frame_rate() / 50);
1284 right->set_fade_out_length (_session->frame_rate() / 50);
1286 pl.add_region (left, 0);
1287 pl.add_region (right, 1 + preroll);
1289 /* there is only one ... */
1290 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1292 _session->audition_playlist ();
1296 CrossfadeEditor::audition_both ()
1302 CrossfadeEditor::audition_left_dry ()
1306 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1307 plist.add (ARDOUR::Properties::length, xfade->length());
1308 plist.add (ARDOUR::Properties::name, string("xfade left"));
1309 plist.add (ARDOUR::Properties::layer, 0);
1311 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1312 (RegionFactory::create (xfade->out(), plist, false)));
1314 _session->audition_region (left);
1318 CrossfadeEditor::audition_left ()
1324 CrossfadeEditor::audition_right_dry ()
1328 plist.add (ARDOUR::Properties::start, 0);
1329 plist.add (ARDOUR::Properties::length, xfade->length());
1330 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1331 plist.add (ARDOUR::Properties::layer, 0);
1333 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1334 (RegionFactory::create (xfade->in(), plist, false)));
1336 _session->audition_region (right);
1340 CrossfadeEditor::audition_right ()
1346 CrossfadeEditor::cancel_audition ()
1348 _session->cancel_audition ();
1352 CrossfadeEditor::audition_toggled ()
1356 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1367 CrossfadeEditor::audition_right_toggled ()
1371 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1382 CrossfadeEditor::audition_right_dry_toggled ()
1386 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1389 audition_right_dry ();
1397 CrossfadeEditor::audition_left_toggled ()
1401 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1412 CrossfadeEditor::audition_left_dry_toggled ()
1416 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1419 audition_left_dry ();
1427 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1433 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1435 switch (ev->keyval) {
1437 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1438 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1440 audition_right_button.set_active (!audition_right_button.get_active());
1445 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1446 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1448 audition_left_button.set_active (!audition_left_button.get_active());
1453 if (_session->is_auditioning()) {
1456 audition_both_button.set_active (!audition_both_button.get_active());