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"
40 #include "ardour/crossfade_binder.h"
42 #include <gtkmm2ext/gtk_ui.h>
44 #include "ardour_ui.h"
45 #include "crossfade_edit.h"
46 #include "rgb_macros.h"
49 #include "gui_thread.h"
50 #include "canvas_impl.h"
51 #include "simplerect.h"
56 using namespace ARDOUR;
59 using namespace Editing;
61 using Gtkmm2ext::Keyboard;
65 const int32_t CrossfadeEditor::Point::size = 7;
66 const double CrossfadeEditor::canvas_border = 10;
67 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
68 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
70 CrossfadeEditor::Half::Half ()
72 , normative_curve (Evoral::Parameter(GainAutomation))
73 , gain_curve (Evoral::Parameter(GainAutomation))
77 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
78 : ArdourDialog (_("Edit Crossfade")),
80 clear_button (_("Clear")),
81 revert_button (_("Reset")),
82 audition_both_button (_("Fade")),
83 audition_left_dry_button (_("Out (dry)")),
84 audition_left_button (_("Out")),
85 audition_right_dry_button (_("In (dry)")),
86 audition_right_button (_("In")),
88 preroll_button (_("With Pre-roll")),
89 postroll_button (_("With Post-roll")),
95 fade_out_table (3, 3),
97 select_in_button (_("Fade In")),
98 select_out_button (_("Fade Out")),
100 _peaks_ready_connection (0)
105 set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
106 set_name ("CrossfadeEditWindow");
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), boost::bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
300 _session->AuditionActive.connect (_session_connections, invalidator (*this), boost::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 or vertically */
424 if (point == fade[current].points.front() || point == fade[current].points.back()) {
428 new_x = (event->motion.x - canvas_border)/effective_width();
429 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
432 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
444 CrossfadeEditor::canvas_event (GdkEvent* event)
446 switch (event->type) {
447 case GDK_BUTTON_PRESS:
448 add_control_point ((event->button.x - canvas_border)/effective_width(),
449 1.0 - ((event->button.y - canvas_border)/effective_height()));
458 CrossfadeEditor::Point::~Point()
463 CrossfadeEditor::Point*
464 CrossfadeEditor::make_point ()
466 Point* p = new Point;
468 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
469 p->box->property_fill() = true;
470 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
471 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
472 p->box->property_outline_pixels() = 1;
474 p->curve = fade[current].line;
476 p->box->signal_event().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
482 CrossfadeEditor::add_control_point (double x, double y)
486 /* enforce end point x location */
488 if (fade[current].points.empty()) {
490 } else if (fade[current].points.size() == 1) {
494 Point* p = make_point ();
496 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
498 fade[current].points.push_back (p);
499 fade[current].points.sort (cmp);
505 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
507 if ( xfract < 0.0 ) {
509 } else if ( xfract > 1.0 ) {
513 if ( yfract < 0.0 ) {
515 } else if ( yfract > 1.0 ) {
519 const double half_size = rint(size/2.0);
520 double x1 = nx - half_size;
521 double x2 = nx + half_size;
523 box->property_x1() = x1;
524 box->property_x2() = x2;
526 box->property_y1() = ny - half_size;
527 box->property_y2() = ny + half_size;
534 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
537 toplevel->property_x1() = 0.0;
538 toplevel->property_y1() = 0.0;
539 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
540 toplevel->property_y2() = (double) 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)->property_y() = yoff;
626 (*i)->property_height() = ht;
627 (*i)->property_samples_per_unit() = 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)->property_y() = yoff;
638 (*i)->property_height() = ht;
639 (*i)->property_samples_per_unit() = 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 (Gnome::Art::Point (0,0));
687 while (spts.size() < npoints + 3) {
688 spts.push_back (Gnome::Art::Point (0,0));
691 /* the shade coordinates *MUST* be in anti-clockwise order.
698 spts[0].set_x (canvas_border);
699 spts[0].set_y (effective_height() + canvas_border);
703 spts[1].set_x (effective_width() + canvas_border);
704 spts[1].set_y (effective_height() + canvas_border);
708 spts[2].set_x (effective_width() + canvas_border);
709 spts[2].set_y (canvas_border);
716 spts[0].set_x (canvas_border);
717 spts[0].set_y (canvas_border);
721 spts[1].set_x (canvas_border);
722 spts[1].set_y (effective_height() + canvas_border);
726 spts[2].set_x (effective_width() + canvas_border);
727 spts[2].set_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].set_x (canvas_border + i);
738 pts[i].set_y (y_coordinate (y));
740 spts[last_spt - i].set_x (canvas_border + i);
741 spts[last_spt - i].set_y (pts[i].get_y());
744 fade[current].line->property_points() = pts;
745 fade[current].shading->property_points() = spts;
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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1073 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1076 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1077 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1078 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1081 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1082 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
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)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1098 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1101 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1102 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1103 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1106 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1107 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
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()->canvasvar_SelectedCrossfadeEditorWave.get();
1151 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
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 WaveView* waveview = new WaveView (*(canvas->root()));
1167 waveview->property_data_src() = region.get();
1168 waveview->property_cache_updater() = true;
1169 waveview->property_cache() = WaveView::create_cache();
1170 waveview->property_channel() = n;
1171 waveview->property_length_function() = (void*) region_length_from_c;
1172 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1173 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1174 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1175 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1176 waveview->property_x() = canvas_border;
1177 waveview->property_y() = yoff;
1178 waveview->property_height() = ht;
1179 waveview->property_samples_per_unit() = spu;
1180 waveview->property_amplitude_above_axis() = 2.0;
1181 waveview->property_wave_color() = color;
1182 waveview->property_fill_color() = color;
1185 waveview->property_region_start() = region->start();
1187 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1189 waveview->lower_to_bottom();
1190 fade[which].waves.push_back (waveview);
1194 toplevel->lower_to_bottom();
1198 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1200 boost::shared_ptr<AudioRegion> r (wr.lock());
1206 /* this should never be called, because the peak files for an xfade
1207 will be ready by the time we want them. but our API forces us
1208 to provide this, so ..
1210 delete _peaks_ready_connection;
1211 _peaks_ready_connection = 0;
1213 make_waves (r, which);
1217 CrossfadeEditor::audition (Audition which)
1219 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1221 framecnt_t postroll;
1222 framecnt_t left_start_offset;
1223 framecnt_t right_length;
1224 framecnt_t left_length;
1226 if (which != Right && preroll_button.get_active()) {
1227 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1232 if (which != Left && postroll_button.get_active()) {
1233 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1238 // Is there enough data for the whole preroll?
1239 left_length = xfade->length();
1240 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1241 left_start_offset -= preroll;
1243 preroll = left_start_offset;
1244 left_start_offset = 0;
1246 left_length += preroll;
1248 // Is there enough data for the whole postroll?
1249 right_length = xfade->length();
1250 if ((xfade->in()->length() - right_length) > postroll) {
1251 right_length += postroll;
1253 right_length = xfade->in()->length();
1256 PropertyList left_plist;
1257 PropertyList right_plist;
1260 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1261 left_plist.add (ARDOUR::Properties::length, left_length);
1262 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1263 left_plist.add (ARDOUR::Properties::layer, 0);
1264 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1266 right_plist.add (ARDOUR::Properties::start, 0);
1267 right_plist.add (ARDOUR::Properties::length, right_length);
1268 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1269 right_plist.add (ARDOUR::Properties::layer, 0);
1270 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1272 if (which == Left) {
1273 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1274 } else if (which == Right) {
1275 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1278 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1279 (RegionFactory::create (xfade->out(), left_plist, false)));
1280 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1281 (RegionFactory::create (xfade->in(), right_plist, false)));
1283 // apply a 20ms declicking fade at the start and end of auditioning
1284 // XXX this should really be a property
1286 left->set_fade_in_length (_session->frame_rate() / 50);
1287 right->set_fade_out_length (_session->frame_rate() / 50);
1289 pl.add_region (left, 0);
1290 pl.add_region (right, 1 + preroll);
1292 /* there is only one ... */
1293 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1295 _session->audition_playlist ();
1299 CrossfadeEditor::audition_both ()
1305 CrossfadeEditor::audition_left_dry ()
1309 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1310 plist.add (ARDOUR::Properties::length, xfade->length());
1311 plist.add (ARDOUR::Properties::name, string("xfade left"));
1312 plist.add (ARDOUR::Properties::layer, 0);
1314 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1315 (RegionFactory::create (xfade->out(), plist, false)));
1317 _session->audition_region (left);
1321 CrossfadeEditor::audition_left ()
1327 CrossfadeEditor::audition_right_dry ()
1331 plist.add (ARDOUR::Properties::start, 0);
1332 plist.add (ARDOUR::Properties::length, xfade->length());
1333 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1334 plist.add (ARDOUR::Properties::layer, 0);
1336 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1337 (RegionFactory::create (xfade->in(), plist, false)));
1339 _session->audition_region (right);
1343 CrossfadeEditor::audition_right ()
1349 CrossfadeEditor::cancel_audition ()
1351 _session->cancel_audition ();
1355 CrossfadeEditor::audition_toggled ()
1359 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1370 CrossfadeEditor::audition_right_toggled ()
1374 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1385 CrossfadeEditor::audition_right_dry_toggled ()
1389 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1392 audition_right_dry ();
1400 CrossfadeEditor::audition_left_toggled ()
1404 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1415 CrossfadeEditor::audition_left_dry_toggled ()
1419 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1422 audition_left_dry ();
1430 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1436 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1438 switch (ev->keyval) {
1440 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1441 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1443 audition_right_button.set_active (!audition_right_button.get_active());
1448 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1449 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1451 audition_left_button.set_active (!audition_left_button.get_active());
1456 if (_session->is_auditioning()) {
1459 audition_both_button.set_active (!audition_both_button.get_active());