2 Copyright (C) 2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <sigc++/bind.h>
24 #include <gtkmm/frame.h>
25 #include <gtkmm/image.h>
26 #include <gtkmm/scrolledwindow.h>
28 #include <libgnomecanvasmm/line.h>
30 #include "ardour/automation_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"
40 #include <gtkmm2ext/gtk_ui.h>
42 #include "ardour_ui.h"
43 #include "crossfade_edit.h"
44 #include "rgb_macros.h"
47 #include "gui_thread.h"
48 #include "canvas_impl.h"
49 #include "simplerect.h"
54 using namespace ARDOUR;
57 using namespace Editing;
59 using Gtkmm2ext::Keyboard;
63 const int32_t CrossfadeEditor::Point::size = 7;
64 const double CrossfadeEditor::canvas_border = 10;
65 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
66 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
68 CrossfadeEditor::Half::Half ()
70 , normative_curve (Evoral::Parameter(GainAutomation))
71 , gain_curve (Evoral::Parameter(GainAutomation))
75 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
76 : ArdourDialog (_("ardour: x-fade edit")),
78 clear_button (_("Clear")),
79 revert_button (_("Reset")),
80 audition_both_button (_("Fade")),
81 audition_left_dry_button (_("Out (dry)")),
82 audition_left_button (_("Out")),
83 audition_right_dry_button (_("In (dry)")),
84 audition_right_button (_("In")),
86 preroll_button (_("With Pre-roll")),
87 postroll_button (_("With Post-roll")),
93 fade_out_table (3, 3),
95 select_in_button (_("Fade In")),
96 select_out_button (_("Fade Out"))
100 set_wmclass (X_("ardour_automationedit"), "Ardour");
101 set_name ("CrossfadeEditWindow");
102 set_position (Gtk::WIN_POS_MOUSE);
104 add_accel_group (ActionManager::ui_manager->get_accel_group());
106 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
108 RadioButtonGroup sel_but_group = select_in_button.get_group();
109 select_out_button.set_group (sel_but_group);
110 select_out_button.set_mode (false);
111 select_in_button.set_mode (false);
113 get_action_area()->set_layout(BUTTONBOX_SPREAD);
114 get_action_area()->pack_start(clear_button);
115 get_action_area()->pack_start(revert_button);
116 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
117 ok_button = add_button ("OK", RESPONSE_ACCEPT);
119 if (fade_in_presets == 0) {
123 point_grabbed = false;
126 canvas = new ArdourCanvas::CanvasAA ();
127 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
128 canvas->set_size_request (425, 200);
130 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
131 toplevel->property_x1() = 0.0;
132 toplevel->property_y1() = 0.0;
133 toplevel->property_x2() = 10.0;
134 toplevel->property_y2() = 10.0;
135 toplevel->property_fill() = true;
136 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
137 toplevel->property_outline_pixels() = 0;
138 toplevel->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
140 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
141 fade[Out].line->property_width_pixels() = 1;
142 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
144 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
145 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
147 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
148 fade[In].line->property_width_pixels() = 1;
149 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
151 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
152 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
154 fade[In].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
155 fade[In].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
156 fade[Out].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
157 fade[Out].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
159 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
160 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
162 select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
163 select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
165 HBox* acbox = manage (new HBox);
167 audition_box.set_border_width (7);
168 audition_box.set_spacing (5);
169 audition_box.set_homogeneous (false);
170 audition_box.pack_start (audition_left_dry_button, false, false);
171 audition_box.pack_start (audition_left_button, false, false);
172 audition_box.pack_start (audition_both_button, false, false);
173 audition_box.pack_start (audition_right_button, false, false);
174 audition_box.pack_start (audition_right_dry_button, false, false);
176 Frame* audition_frame = manage (new Frame (_("Audition")));
178 audition_frame->set_name (X_("CrossfadeEditFrame"));
179 audition_frame->add (audition_box);
181 acbox->pack_start (*audition_frame, true, false);
183 Frame* canvas_frame = manage (new Frame);
184 canvas_frame->add (*canvas);
185 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
187 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
188 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
198 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
200 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
201 pbutton = manage (new Button);
202 pbutton->add (*pxmap);
203 pbutton->set_name ("CrossfadeEditButton");
204 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
205 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
206 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
207 fade_in_buttons.push_back (pbutton);
220 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
222 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
223 pbutton = manage (new Button);
224 pbutton->add (*pxmap);
225 pbutton->set_name ("CrossfadeEditButton");
226 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
227 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
228 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
229 fade_out_buttons.push_back (pbutton);
239 clear_button.set_name ("CrossfadeEditButton");
240 revert_button.set_name ("CrossfadeEditButton");
241 ok_button->set_name ("CrossfadeEditButton");
242 cancel_button->set_name ("CrossfadeEditButton");
243 preroll_button.set_name ("CrossfadeEditButton");
244 postroll_button.set_name ("CrossfadeEditButton");
245 audition_both_button.set_name ("CrossfadeEditAuditionButton");
246 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
247 audition_left_button.set_name ("CrossfadeEditAuditionButton");
248 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
249 audition_right_button.set_name ("CrossfadeEditAuditionButton");
251 clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
252 revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
253 audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
254 audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
255 audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
256 audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
257 audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
259 roll_box.pack_start (preroll_button, false, false);
260 roll_box.pack_start (postroll_button, false, false);
262 Gtk::HBox* rcenter_box = manage (new HBox);
263 rcenter_box->pack_start (roll_box, true, false);
265 VBox* vpacker2 = manage (new (VBox));
267 vpacker2->set_border_width (12);
268 vpacker2->set_spacing (7);
269 vpacker2->pack_start (*acbox, false, false);
270 vpacker2->pack_start (*rcenter_box, false, false);
272 curve_button_box.set_spacing (7);
273 curve_button_box.pack_start (fade_out_table, false, false, 12);
274 curve_button_box.pack_start (*vpacker2, false, false, 12);
275 curve_button_box.pack_start (fade_in_table, false, false, 12);
277 get_vbox()->pack_start (*canvas_frame, true, true);
278 get_vbox()->pack_start (curve_button_box, false, false);
280 /* button to allow hackers to check the actual curve values */
282 // Button* foobut = manage (new Button ("dump"));
283 // foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
284 // vpacker.pack_start (*foobut, false, false);
287 set (xfade->fade_in(), In);
290 set (xfade->fade_out(), Out);
292 curve_select_clicked (In);
294 xfade->StateChanged.connect (sigc::mem_fun(*this, &CrossfadeEditor::xfade_changed));
296 _session_connections.add_connection (_session->AuditionActive.connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_state_changed)));
300 CrossfadeEditor::~CrossfadeEditor()
302 /* most objects will be destroyed when the toplevel window is. */
304 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
308 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
314 CrossfadeEditor::dump ()
316 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
317 cerr << (*i)->when << ' ' << (*i)->value << endl;
322 CrossfadeEditor::audition_state_changed (bool yn)
324 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
327 audition_both_button.set_active (false);
328 audition_left_button.set_active (false);
329 audition_right_button.set_active (false);
330 audition_left_dry_button.set_active (false);
331 audition_right_dry_button.set_active (false);
336 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
339 ARDOUR::AutomationList::const_iterator the_end;
341 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
345 fade[which].points.clear ();
346 fade[which].gain_curve.clear ();
347 fade[which].normative_curve.clear ();
353 the_end = curve.end();
356 firstx = (*curve.begin())->when;
357 endx = (*the_end)->when;
359 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
361 double xfract = ((*i)->when - firstx) / (endx - firstx);
362 double yfract = ((*i)->value - miny) / (maxy - miny);
364 Point* p = make_point ();
366 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
369 fade[which].points.push_back (p);
372 /* no need to sort because curve is already time-ordered */
376 swap (which, current);
378 swap (which, current);
382 CrossfadeEditor::curve_event (GdkEvent* event)
384 /* treat it like a toplevel event */
386 return canvas_event (event);
390 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
393 if (point->curve != fade[current].line) {
397 switch (event->type) {
398 case GDK_BUTTON_PRESS:
399 point_grabbed = true;
401 case GDK_BUTTON_RELEASE:
402 point_grabbed = false;
404 if (Keyboard::is_delete_event (&event->button)) {
405 fade[current].points.remove (point);
412 case GDK_MOTION_NOTIFY:
416 /* can't drag first or last points horizontally */
418 if (point == fade[current].points.front() || point == fade[current].points.back()) {
421 new_x = (event->motion.x - canvas_border)/effective_width();
424 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
425 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
437 CrossfadeEditor::canvas_event (GdkEvent* event)
439 switch (event->type) {
440 case GDK_BUTTON_PRESS:
441 add_control_point ((event->button.x - canvas_border)/effective_width(),
442 1.0 - ((event->button.y - canvas_border)/effective_height()));
451 CrossfadeEditor::Point::~Point()
456 CrossfadeEditor::Point*
457 CrossfadeEditor::make_point ()
459 Point* p = new Point;
461 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
462 p->box->property_fill() = true;
463 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
464 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
465 p->box->property_outline_pixels() = 1;
467 p->curve = fade[current].line;
469 p->box->signal_event().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
475 CrossfadeEditor::add_control_point (double x, double y)
479 /* enforce end point x location */
481 if (fade[current].points.empty()) {
483 } else if (fade[current].points.size() == 1) {
487 Point* p = make_point ();
489 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
491 fade[current].points.push_back (p);
492 fade[current].points.sort (cmp);
498 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
500 const double half_size = rint(size/2.0);
501 double x1 = nx - half_size;
502 double x2 = nx + half_size;
504 box->property_x1() = x1;
505 box->property_x2() = x2;
507 box->property_y1() = ny - half_size;
508 box->property_y2() = ny + half_size;
515 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
518 toplevel->property_x1() = 0.0;
519 toplevel->property_y1() = 0.0;
520 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
521 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
524 canvas->set_scroll_region (0.0, 0.0,
525 canvas->get_allocation().get_width(),
526 canvas->get_allocation().get_height());
528 Point* end = make_point ();
531 if (fade[In].points.size() > 1) {
532 Point* old_end = fade[In].points.back();
533 fade[In].points.pop_back ();
534 end->move_to (x_coordinate (old_end->x),
535 y_coordinate (old_end->y),
536 old_end->x, old_end->y);
541 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
545 fade[In].points.push_back (end);
546 fade[In].points.sort (cmp);
548 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
549 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
555 if (fade[Out].points.size() > 1) {
556 Point* old_end = fade[Out].points.back();
557 fade[Out].points.pop_back ();
558 end->move_to (x_coordinate (old_end->x),
559 y_coordinate (old_end->y),
560 old_end->x, old_end->y);
565 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
569 fade[Out].points.push_back (end);
570 fade[Out].points.sort (cmp);
572 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
573 (*i)->move_to (x_coordinate ((*i)->x),
574 y_coordinate ((*i)->y),
578 WhichFade old_current = current;
583 current = old_current;
585 double spu = xfade->length() / (double) effective_width();
587 if (fade[In].waves.empty()) {
588 make_waves (xfade->in(), In);
591 if (fade[Out].waves.empty()) {
592 make_waves (xfade->out(), Out);
596 vector<ArdourCanvas::WaveView*>::iterator i;
599 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
601 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
606 (*i)->property_y() = yoff;
607 (*i)->property_height() = ht;
608 (*i)->property_samples_per_unit() = spu;
611 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
613 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
618 (*i)->property_y() = yoff;
619 (*i)->property_height() = ht;
620 (*i)->property_samples_per_unit() = spu;
627 CrossfadeEditor::xfade_changed (Change)
629 set (xfade->fade_in(), In);
630 set (xfade->fade_out(), Out);
634 CrossfadeEditor::redraw ()
636 if (canvas->get_allocation().get_width() < 2) {
640 nframes_t len = xfade->length ();
642 fade[current].normative_curve.clear ();
643 fade[current].gain_curve.clear ();
645 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
646 fade[current].normative_curve.add ((*i)->x, (*i)->y);
649 offset = xfade->in()->start();
651 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
652 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
656 size_t npoints = (size_t) effective_width();
659 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
661 ArdourCanvas::Points pts;
662 ArdourCanvas::Points spts;
664 while (pts.size() < npoints) {
665 pts.push_back (Gnome::Art::Point (0,0));
668 while (spts.size() < npoints + 3) {
669 spts.push_back (Gnome::Art::Point (0,0));
672 /* the shade coordinates *MUST* be in anti-clockwise order.
679 spts[0].set_x (canvas_border);
680 spts[0].set_y (effective_height() + canvas_border);
684 spts[1].set_x (effective_width() + canvas_border);
685 spts[1].set_y (effective_height() + canvas_border);
689 spts[2].set_x (effective_width() + canvas_border);
690 spts[2].set_y (canvas_border);
697 spts[0].set_x (canvas_border);
698 spts[0].set_y (canvas_border);
702 spts[1].set_x (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 (effective_height() + canvas_border);
712 size_t last_spt = (npoints + 3) - 1;
714 for (size_t i = 0; i < npoints; ++i) {
718 pts[i].set_x (canvas_border + i);
719 pts[i].set_y (y_coordinate (y));
721 spts[last_spt - i].set_x (canvas_border + i);
722 spts[last_spt - i].set_y (pts[i].get_y());
725 fade[current].line->property_points() = pts;
726 fade[current].shading->property_points() = spts;
728 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
729 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
734 CrossfadeEditor::apply_preset (Preset *preset)
737 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
742 select_in_button.clicked();
744 select_out_button.clicked();
747 curve_select_clicked (wf);
750 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
754 fade[current].points.clear ();
756 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
757 Point* p = make_point ();
758 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
760 fade[current].points.push_back (p);
767 CrossfadeEditor::apply ()
773 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
775 ARDOUR::AutomationList& in (xf->fade_in());
776 ARDOUR::AutomationList& out (xf->fade_out());
781 ARDOUR::AutomationList::const_iterator the_end = in.end();
784 double firstx = (*in.begin())->when;
785 double endx = (*the_end)->when;
786 double miny = in.get_min_y ();
787 double maxy = in.get_max_y ();
792 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
794 double when = firstx + ((*i)->x * (endx - firstx));
795 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
796 in.add (when, value);
804 firstx = (*out.begin())->when;
805 endx = (*the_end)->when;
806 miny = out.get_min_y ();
807 maxy = out.get_max_y ();
812 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
814 double when = firstx + ((*i)->x * (endx - firstx));
815 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
816 out.add (when, value);
824 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
827 xfade->set_active (true);
828 xfade->fade_in().curve().solve ();
829 xfade->fade_out().curve().solve ();
833 CrossfadeEditor::clear ()
835 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
839 fade[current].points.clear ();
845 CrossfadeEditor::reset ()
847 set (xfade->fade_in(), In);
848 set (xfade->fade_out(), Out);
850 curve_select_clicked (current);
854 CrossfadeEditor::build_presets ()
858 fade_in_presets = new Presets;
859 fade_out_presets = new Presets;
863 p = new Preset ("Linear (-6dB)", "crossfade-in-linear");
864 p->push_back (PresetPoint (0, 0));
865 p->push_back (PresetPoint (0.000000, 0.000000));
866 p->push_back (PresetPoint (0.166667, 0.166366));
867 p->push_back (PresetPoint (0.333333, 0.332853));
868 p->push_back (PresetPoint (0.500000, 0.499459));
869 p->push_back (PresetPoint (0.666667, 0.666186));
870 p->push_back (PresetPoint (0.833333, 0.833033));
871 p->push_back (PresetPoint (1.000000, 1.000000));
872 fade_in_presets->push_back (p);
874 p = new Preset ("S(1)-curve", "crossfade-in-S1");
875 p->push_back (PresetPoint (0, 0));
876 p->push_back (PresetPoint (0.1, 0.01));
877 p->push_back (PresetPoint (0.2, 0.03));
878 p->push_back (PresetPoint (0.8, 0.97));
879 p->push_back (PresetPoint (0.9, 0.99));
880 p->push_back (PresetPoint (1, 1));
881 fade_in_presets->push_back (p);
883 p = new Preset ("S(2)-curve", "crossfade-in-S2");
884 p->push_back (PresetPoint (0.0, 0.0));
885 p->push_back (PresetPoint (0.055, 0.222));
886 p->push_back (PresetPoint (0.163, 0.35));
887 p->push_back (PresetPoint (0.837, 0.678));
888 p->push_back (PresetPoint (0.945, 0.783));
889 p->push_back (PresetPoint (1.0, 1.0));
890 fade_in_presets->push_back (p);
892 p = new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
894 p->push_back (PresetPoint (0.000000, 0.000000));
895 p->push_back (PresetPoint (0.166667, 0.282192));
896 p->push_back (PresetPoint (0.333333, 0.518174));
897 p->push_back (PresetPoint (0.500000, 0.707946));
898 p->push_back (PresetPoint (0.666667, 0.851507));
899 p->push_back (PresetPoint (0.833333, 0.948859));
900 p->push_back (PresetPoint (1.000000, 1.000000));
902 fade_in_presets->push_back (p);
904 if (!Profile->get_sae()) {
906 p = new Preset ("Short cut", "crossfade-in-short-cut");
907 p->push_back (PresetPoint (0, 0));
908 p->push_back (PresetPoint (0.389401, 0.0333333));
909 p->push_back (PresetPoint (0.629032, 0.0861111));
910 p->push_back (PresetPoint (0.829493, 0.233333));
911 p->push_back (PresetPoint (0.9447, 0.483333));
912 p->push_back (PresetPoint (0.976959, 0.697222));
913 p->push_back (PresetPoint (1, 1));
914 fade_in_presets->push_back (p);
916 p = new Preset ("Slow cut", "crossfade-in-slow-cut");
917 p->push_back (PresetPoint (0, 0));
918 p->push_back (PresetPoint (0.304147, 0.0694444));
919 p->push_back (PresetPoint (0.529954, 0.152778));
920 p->push_back (PresetPoint (0.725806, 0.333333));
921 p->push_back (PresetPoint (0.847926, 0.558333));
922 p->push_back (PresetPoint (0.919355, 0.730556));
923 p->push_back (PresetPoint (1, 1));
924 fade_in_presets->push_back (p);
926 p = new Preset ("Fast cut", "crossfade-in-fast-cut");
927 p->push_back (PresetPoint (0, 0));
928 p->push_back (PresetPoint (0.0737327, 0.308333));
929 p->push_back (PresetPoint (0.246544, 0.658333));
930 p->push_back (PresetPoint (0.470046, 0.886111));
931 p->push_back (PresetPoint (0.652074, 0.972222));
932 p->push_back (PresetPoint (0.771889, 0.988889));
933 p->push_back (PresetPoint (1, 1));
934 fade_in_presets->push_back (p);
936 p = new Preset ("Long cut", "crossfade-in-long-cut");
937 p->push_back (PresetPoint (0, 0));
938 p->push_back (PresetPoint (0.0207373, 0.197222));
939 p->push_back (PresetPoint (0.0645161, 0.525));
940 p->push_back (PresetPoint (0.152074, 0.802778));
941 p->push_back (PresetPoint (0.276498, 0.919444));
942 p->push_back (PresetPoint (0.481567, 0.980556));
943 p->push_back (PresetPoint (0.767281, 1));
944 p->push_back (PresetPoint (1, 1));
945 fade_in_presets->push_back (p);
950 // p = new Preset ("regout.xpm");
951 p = new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
952 p->push_back (PresetPoint (0, 1));
953 p->push_back (PresetPoint (0.000000, 1.000000));
954 p->push_back (PresetPoint (0.166667, 0.833033));
955 p->push_back (PresetPoint (0.333333, 0.666186));
956 p->push_back (PresetPoint (0.500000, 0.499459));
957 p->push_back (PresetPoint (0.666667, 0.332853));
958 p->push_back (PresetPoint (0.833333, 0.166366));
959 p->push_back (PresetPoint (1.000000, 0.000000));
960 fade_out_presets->push_back (p);
962 p = new Preset ("S(1)-Curve", "crossfade-out-S1");
963 p->push_back (PresetPoint (0, 1));
964 p->push_back (PresetPoint (0.1, 0.99));
965 p->push_back (PresetPoint (0.2, 0.97));
966 p->push_back (PresetPoint (0.8, 0.03));
967 p->push_back (PresetPoint (0.9, 0.01));
968 p->push_back (PresetPoint (1, 0));
969 fade_out_presets->push_back (p);
971 p = new Preset ("S(2)-Curve", "crossfade-out-S2");
972 p->push_back (PresetPoint (0.0, 1.0));
973 p->push_back (PresetPoint (0.163, 0.678));
974 p->push_back (PresetPoint (0.055, 0.783));
975 p->push_back (PresetPoint (0.837, 0.35));
976 p->push_back (PresetPoint (0.945, 0.222));
977 p->push_back (PresetPoint (1.0, 0.0));
978 fade_out_presets->push_back (p);
980 // p = new Preset ("linout.xpm");
981 p = new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
982 p->push_back (PresetPoint (0.000000, 1.000000));
983 p->push_back (PresetPoint (0.166667, 0.948859));
984 p->push_back (PresetPoint (0.333333, 0.851507));
985 p->push_back (PresetPoint (0.500000, 0.707946));
986 p->push_back (PresetPoint (0.666667, 0.518174));
987 p->push_back (PresetPoint (0.833333, 0.282192));
988 p->push_back (PresetPoint (1.000000, 0.000000));
989 fade_out_presets->push_back (p);
991 if (!Profile->get_sae()) {
992 // p = new Preset ("hiout.xpm");
993 p = new Preset ("Short cut", "crossfade-out-short-cut");
994 p->push_back (PresetPoint (0, 1));
995 p->push_back (PresetPoint (0.305556, 1));
996 p->push_back (PresetPoint (0.548611, 0.991736));
997 p->push_back (PresetPoint (0.759259, 0.931129));
998 p->push_back (PresetPoint (0.918981, 0.68595));
999 p->push_back (PresetPoint (0.976852, 0.22865));
1000 p->push_back (PresetPoint (1, 0));
1001 fade_out_presets->push_back (p);
1003 p = new Preset ("Slow cut", "crossfade-out-slow-cut");
1004 p->push_back (PresetPoint (0, 1));
1005 p->push_back (PresetPoint (0.228111, 0.988889));
1006 p->push_back (PresetPoint (0.347926, 0.972222));
1007 p->push_back (PresetPoint (0.529954, 0.886111));
1008 p->push_back (PresetPoint (0.753456, 0.658333));
1009 p->push_back (PresetPoint (0.9262673, 0.308333));
1010 p->push_back (PresetPoint (1, 0));
1011 fade_out_presets->push_back (p);
1013 p = new Preset ("Fast cut", "crossfade-out-fast-cut");
1014 p->push_back (PresetPoint (0, 1));
1015 p->push_back (PresetPoint (0.080645, 0.730556));
1016 p->push_back (PresetPoint (0.277778, 0.289256));
1017 p->push_back (PresetPoint (0.470046, 0.152778));
1018 p->push_back (PresetPoint (0.695853, 0.0694444));
1019 p->push_back (PresetPoint (1, 0));
1020 fade_out_presets->push_back (p);
1022 // p = new Preset ("loout.xpm");
1023 p = new Preset ("Long cut", "crossfade-out-long-cut");
1024 p->push_back (PresetPoint (0, 1));
1025 p->push_back (PresetPoint (0.023041, 0.697222));
1026 p->push_back (PresetPoint (0.0553, 0.483333));
1027 p->push_back (PresetPoint (0.170507, 0.233333));
1028 p->push_back (PresetPoint (0.370968, 0.0861111));
1029 p->push_back (PresetPoint (0.610599, 0.0333333));
1030 p->push_back (PresetPoint (1, 0));
1031 fade_out_presets->push_back (p);
1037 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1043 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1044 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1045 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1048 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1049 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1050 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1053 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1054 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1055 fade[Out].shading->hide();
1056 fade[In].shading->show();
1058 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1062 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
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_CrossfadeEditorWave.get();
1070 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.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_SelectedCrossfadeEditorWave.get();
1075 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1078 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1079 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1080 fade[In].shading->hide();
1081 fade[Out].shading->show();
1083 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1087 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1095 CrossfadeEditor::x_coordinate (double& xfract) const
1097 xfract = min (1.0, xfract);
1098 xfract = max (0.0, xfract);
1100 return canvas_border + (xfract * effective_width());
1104 CrossfadeEditor::y_coordinate (double& yfract) const
1106 yfract = min (1.0, yfract);
1107 yfract = max (0.0, yfract);
1109 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1113 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1116 uint32_t nchans = region->n_channels();
1121 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1123 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1126 ht = canvas->get_allocation().get_height() / (double) nchans;
1127 spu = xfade->length() / (double) effective_width();
1129 for (uint32_t n = 0; n < nchans; ++n) {
1131 gdouble yoff = n * ht;
1133 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), peaks_ready_connection)) {
1134 WaveView* waveview = new WaveView (*(canvas->root()));
1136 waveview->property_data_src() = region.get();
1137 waveview->property_cache_updater() = true;
1138 waveview->property_cache() = WaveView::create_cache();
1139 waveview->property_channel() = n;
1140 waveview->property_length_function() = (void*) region_length_from_c;
1141 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1142 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1143 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1144 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1145 waveview->property_x() = canvas_border;
1146 waveview->property_y() = yoff;
1147 waveview->property_height() = ht;
1148 waveview->property_samples_per_unit() = spu;
1149 waveview->property_amplitude_above_axis() = 2.0;
1150 waveview->property_wave_color() = color;
1151 waveview->property_fill_color() = color;
1154 waveview->property_region_start() = region->start();
1156 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1158 waveview->lower_to_bottom();
1159 fade[which].waves.push_back (waveview);
1163 toplevel->lower_to_bottom();
1167 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1169 boost::shared_ptr<AudioRegion> r (wr.lock());
1175 /* this should never be called, because the peak files for an xfade
1176 will be ready by the time we want them. but our API forces us
1177 to provide this, so ..
1179 peaks_ready_connection.disconnect ();
1180 make_waves (r, which);
1184 CrossfadeEditor::audition (Audition which)
1186 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1189 nframes_t left_start_offset;
1190 nframes_t right_length;
1191 nframes_t left_length;
1193 if (which != Right && preroll_button.get_active()) {
1194 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1199 if (which != Left && postroll_button.get_active()) {
1200 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1205 // Is there enough data for the whole preroll?
1206 left_length = xfade->length();
1207 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1208 left_start_offset -= preroll;
1210 preroll = left_start_offset;
1211 left_start_offset = 0;
1213 left_length += preroll;
1215 // Is there enough data for the whole postroll?
1216 right_length = xfade->length();
1217 if ((xfade->in()->length() - right_length) > postroll) {
1218 right_length += postroll;
1220 right_length = xfade->in()->length();
1223 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out",
1224 0, Region::DefaultFlags, false)));
1225 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, right_length, "xfade in",
1226 0, Region::DefaultFlags, false)));
1228 //apply a 20ms declicking fade at the start and end of auditioning
1229 left->set_fade_in_active(true);
1230 left->set_fade_in_length(_session->frame_rate() / 50);
1231 right->set_fade_out_active(true);
1232 right->set_fade_out_length(_session->frame_rate() / 50);
1234 pl.add_region (left, 0);
1235 pl.add_region (right, 1 + preroll);
1237 if (which == Left) {
1238 right->set_scale_amplitude (0.0);
1239 } else if (which == Right) {
1240 left->set_scale_amplitude (0.0);
1243 /* there is only one ... */
1244 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1246 _session->audition_playlist ();
1250 CrossfadeEditor::audition_both ()
1256 CrossfadeEditor::audition_left_dry ()
1258 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left",
1259 0, Region::DefaultFlags, false)));
1261 _session->audition_region (left);
1265 CrossfadeEditor::audition_left ()
1271 CrossfadeEditor::audition_right_dry ()
1273 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in",
1274 0, Region::DefaultFlags, false)));
1275 _session->audition_region (right);
1279 CrossfadeEditor::audition_right ()
1285 CrossfadeEditor::cancel_audition ()
1287 _session->cancel_audition ();
1291 CrossfadeEditor::audition_toggled ()
1295 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1306 CrossfadeEditor::audition_right_toggled ()
1310 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1321 CrossfadeEditor::audition_right_dry_toggled ()
1325 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1328 audition_right_dry ();
1336 CrossfadeEditor::audition_left_toggled ()
1340 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1351 CrossfadeEditor::audition_left_dry_toggled ()
1355 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1358 audition_left_dry ();
1366 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1372 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1374 switch (ev->keyval) {
1376 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1377 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1379 audition_right_button.set_active (!audition_right_button.get_active());
1384 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1385 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1387 audition_left_button.set_active (!audition_left_button.get_active());
1392 if (_session->is_auditioning()) {
1395 audition_both_button.set_active (!audition_both_button.get_active());