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/playlist_templates.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;
59 using namespace Editing;
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")),
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 set_wmclass (X_("ardour_automationedit"), "Ardour");
100 set_name ("CrossfadeEditWindow");
101 set_position (Gtk::WIN_POS_MOUSE);
103 add_accel_group (ActionManager::ui_manager->get_accel_group());
105 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
107 RadioButtonGroup sel_but_group = select_in_button.get_group();
108 select_out_button.set_group (sel_but_group);
109 select_out_button.set_mode (false);
110 select_in_button.set_mode (false);
112 get_action_area()->set_layout(BUTTONBOX_SPREAD);
113 get_action_area()->pack_start(clear_button);
114 get_action_area()->pack_start(revert_button);
115 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
116 ok_button = add_button ("OK", RESPONSE_ACCEPT);
118 if (fade_in_presets == 0) {
122 point_grabbed = false;
125 canvas = new ArdourCanvas::CanvasAA ();
126 canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation));
127 canvas->set_size_request (425, 200);
129 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
130 toplevel->property_x1() = 0.0;
131 toplevel->property_y1() = 0.0;
132 toplevel->property_x2() = 10.0;
133 toplevel->property_y2() = 10.0;
134 toplevel->property_fill() = true;
135 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
136 toplevel->property_outline_pixels() = 0;
137 toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
139 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
140 fade[Out].line->property_width_pixels() = 1;
141 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
143 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
144 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
146 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
147 fade[In].line->property_width_pixels() = 1;
148 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
150 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
151 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
153 fade[In].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
154 fade[In].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
155 fade[Out].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
156 fade[Out].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
158 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
159 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
161 select_in_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
162 select_out_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
164 HBox* acbox = manage (new HBox);
166 audition_box.set_border_width (7);
167 audition_box.set_spacing (5);
168 audition_box.set_homogeneous (false);
169 audition_box.pack_start (audition_left_dry_button, false, false);
170 audition_box.pack_start (audition_left_button, false, false);
171 audition_box.pack_start (audition_both_button, false, false);
172 audition_box.pack_start (audition_right_button, false, false);
173 audition_box.pack_start (audition_right_dry_button, false, false);
175 Frame* audition_frame = manage (new Frame (_("Audition")));
177 audition_frame->set_name (X_("CrossfadeEditFrame"));
178 audition_frame->add (audition_box);
180 acbox->pack_start (*audition_frame, true, false);
182 Frame* canvas_frame = manage (new Frame);
183 canvas_frame->add (*canvas);
184 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
186 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
187 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
197 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
199 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
200 pbutton = manage (new Button);
201 pbutton->add (*pxmap);
202 pbutton->set_name ("CrossfadeEditButton");
203 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
204 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
205 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
206 fade_in_buttons.push_back (pbutton);
219 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
221 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
222 pbutton = manage (new Button);
223 pbutton->add (*pxmap);
224 pbutton->set_name ("CrossfadeEditButton");
225 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
226 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
227 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
228 fade_out_buttons.push_back (pbutton);
238 clear_button.set_name ("CrossfadeEditButton");
239 revert_button.set_name ("CrossfadeEditButton");
240 ok_button->set_name ("CrossfadeEditButton");
241 cancel_button->set_name ("CrossfadeEditButton");
242 preroll_button.set_name ("CrossfadeEditButton");
243 postroll_button.set_name ("CrossfadeEditButton");
244 audition_both_button.set_name ("CrossfadeEditAuditionButton");
245 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
246 audition_left_button.set_name ("CrossfadeEditAuditionButton");
247 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
248 audition_right_button.set_name ("CrossfadeEditAuditionButton");
250 clear_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear));
251 revert_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset));
252 audition_both_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled));
253 audition_right_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
254 audition_right_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
255 audition_left_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
256 audition_left_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
258 roll_box.pack_start (preroll_button, false, false);
259 roll_box.pack_start (postroll_button, false, false);
261 Gtk::HBox* rcenter_box = manage (new HBox);
262 rcenter_box->pack_start (roll_box, true, false);
264 VBox* vpacker2 = manage (new (VBox));
266 vpacker2->set_border_width (12);
267 vpacker2->set_spacing (7);
268 vpacker2->pack_start (*acbox, false, false);
269 vpacker2->pack_start (*rcenter_box, false, false);
271 curve_button_box.set_spacing (7);
272 curve_button_box.pack_start (fade_out_table, false, false, 12);
273 curve_button_box.pack_start (*vpacker2, false, false, 12);
274 curve_button_box.pack_start (fade_in_table, false, false, 12);
276 get_vbox()->pack_start (*canvas_frame, true, true);
277 get_vbox()->pack_start (curve_button_box, false, false);
279 /* button to allow hackers to check the actual curve values */
281 // Button* foobut = manage (new Button ("dump"));
282 // foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
283 // vpacker.pack_start (*foobut, false, false);
286 set (xfade->fade_in(), In);
289 set (xfade->fade_out(), Out);
291 curve_select_clicked (In);
293 xfade->StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed));
295 session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed));
299 CrossfadeEditor::~CrossfadeEditor()
301 /* most objects will be destroyed when the toplevel window is. */
303 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
307 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
313 CrossfadeEditor::dump ()
315 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
316 cerr << (*i)->when << ' ' << (*i)->value << endl;
321 CrossfadeEditor::audition_state_changed (bool yn)
323 ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn));
326 audition_both_button.set_active (false);
327 audition_left_button.set_active (false);
328 audition_right_button.set_active (false);
329 audition_left_dry_button.set_active (false);
330 audition_right_dry_button.set_active (false);
335 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
338 ARDOUR::AutomationList::const_iterator the_end;
340 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
344 fade[which].points.clear ();
345 fade[which].gain_curve.clear ();
346 fade[which].normative_curve.clear ();
352 the_end = curve.end();
355 firstx = (*curve.begin())->when;
356 endx = (*the_end)->when;
358 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
360 double xfract = ((*i)->when - firstx) / (endx - firstx);
361 double yfract = ((*i)->value - miny) / (maxy - miny);
363 Point* p = make_point ();
365 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
368 fade[which].points.push_back (p);
371 /* no need to sort because curve is already time-ordered */
375 swap (which, current);
377 swap (which, current);
381 CrossfadeEditor::curve_event (GdkEvent* event)
383 /* treat it like a toplevel event */
385 return canvas_event (event);
389 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
392 if (point->curve != fade[current].line) {
396 switch (event->type) {
397 case GDK_BUTTON_PRESS:
398 point_grabbed = true;
400 case GDK_BUTTON_RELEASE:
401 point_grabbed = false;
403 if (Keyboard::is_delete_event (&event->button)) {
404 fade[current].points.remove (point);
411 case GDK_MOTION_NOTIFY:
415 /* can't drag first or last points horizontally */
417 if (point == fade[current].points.front() || point == fade[current].points.back()) {
420 new_x = (event->motion.x - canvas_border)/effective_width();
423 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
424 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
436 CrossfadeEditor::canvas_event (GdkEvent* event)
438 switch (event->type) {
439 case GDK_BUTTON_PRESS:
440 add_control_point ((event->button.x - canvas_border)/effective_width(),
441 1.0 - ((event->button.y - canvas_border)/effective_height()));
450 CrossfadeEditor::Point::~Point()
455 CrossfadeEditor::Point*
456 CrossfadeEditor::make_point ()
458 Point* p = new Point;
460 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
461 p->box->property_fill() = true;
462 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
463 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
464 p->box->property_outline_pixels() = 1;
466 p->curve = fade[current].line;
468 p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p));
474 CrossfadeEditor::add_control_point (double x, double y)
478 /* enforce end point x location */
480 if (fade[current].points.empty()) {
482 } else if (fade[current].points.size() == 1) {
486 Point* p = make_point ();
488 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
490 fade[current].points.push_back (p);
491 fade[current].points.sort (cmp);
497 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
499 const double half_size = rint(size/2.0);
500 double x1 = nx - half_size;
501 double x2 = nx + half_size;
503 box->property_x1() = x1;
504 box->property_x2() = x2;
506 box->property_y1() = ny - half_size;
507 box->property_y2() = ny + half_size;
514 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
517 toplevel->property_x1() = 0.0;
518 toplevel->property_y1() = 0.0;
519 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
520 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
523 canvas->set_scroll_region (0.0, 0.0,
524 canvas->get_allocation().get_width(),
525 canvas->get_allocation().get_height());
527 Point* end = make_point ();
530 if (fade[In].points.size() > 1) {
531 Point* old_end = fade[In].points.back();
532 fade[In].points.pop_back ();
533 end->move_to (x_coordinate (old_end->x),
534 y_coordinate (old_end->y),
535 old_end->x, old_end->y);
540 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
544 fade[In].points.push_back (end);
545 fade[In].points.sort (cmp);
547 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
548 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
554 if (fade[Out].points.size() > 1) {
555 Point* old_end = fade[Out].points.back();
556 fade[Out].points.pop_back ();
557 end->move_to (x_coordinate (old_end->x),
558 y_coordinate (old_end->y),
559 old_end->x, old_end->y);
564 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
568 fade[Out].points.push_back (end);
569 fade[Out].points.sort (cmp);
571 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
572 (*i)->move_to (x_coordinate ((*i)->x),
573 y_coordinate ((*i)->y),
577 WhichFade old_current = current;
582 current = old_current;
584 double spu = xfade->length() / (double) effective_width();
586 if (fade[In].waves.empty()) {
587 make_waves (xfade->in(), In);
590 if (fade[Out].waves.empty()) {
591 make_waves (xfade->out(), Out);
595 vector<ArdourCanvas::WaveView*>::iterator i;
598 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
600 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
605 (*i)->property_y() = yoff;
606 (*i)->property_height() = ht;
607 (*i)->property_samples_per_unit() = spu;
610 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
612 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
617 (*i)->property_y() = yoff;
618 (*i)->property_height() = ht;
619 (*i)->property_samples_per_unit() = spu;
626 CrossfadeEditor::xfade_changed (Change ignored)
628 set (xfade->fade_in(), In);
629 set (xfade->fade_out(), Out);
633 CrossfadeEditor::redraw ()
635 if (canvas->get_allocation().get_width() < 2) {
639 nframes_t len = xfade->length ();
641 fade[current].normative_curve.clear ();
642 fade[current].gain_curve.clear ();
644 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
645 fade[current].normative_curve.add ((*i)->x, (*i)->y);
648 offset = xfade->in()->start();
650 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
651 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
655 size_t npoints = (size_t) effective_width();
658 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
660 ArdourCanvas::Points pts;
661 ArdourCanvas::Points spts;
663 while (pts.size() < npoints) {
664 pts.push_back (Gnome::Art::Point (0,0));
667 while (spts.size() < npoints + 3) {
668 spts.push_back (Gnome::Art::Point (0,0));
671 /* the shade coordinates *MUST* be in anti-clockwise order.
678 spts[0].set_x (canvas_border);
679 spts[0].set_y (effective_height() + canvas_border);
683 spts[1].set_x (effective_width() + canvas_border);
684 spts[1].set_y (effective_height() + canvas_border);
688 spts[2].set_x (effective_width() + canvas_border);
689 spts[2].set_y (canvas_border);
696 spts[0].set_x (canvas_border);
697 spts[0].set_y (canvas_border);
701 spts[1].set_x (canvas_border);
702 spts[1].set_y (effective_height() + canvas_border);
706 spts[2].set_x (effective_width() + canvas_border);
707 spts[2].set_y (effective_height() + canvas_border);
711 size_t last_spt = (npoints + 3) - 1;
713 for (size_t i = 0; i < npoints; ++i) {
717 pts[i].set_x (canvas_border + i);
718 pts[i].set_y (y_coordinate (y));
720 spts[last_spt - i].set_x (canvas_border + i);
721 spts[last_spt - i].set_y (pts[i].get_y());
724 fade[current].line->property_points() = pts;
725 fade[current].shading->property_points() = spts;
727 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
728 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
733 CrossfadeEditor::apply_preset (Preset *preset)
736 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
741 select_in_button.clicked();
743 select_out_button.clicked();
746 curve_select_clicked (wf);
749 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
753 fade[current].points.clear ();
755 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
756 Point* p = make_point ();
757 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
759 fade[current].points.push_back (p);
766 CrossfadeEditor::apply ()
772 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
774 ARDOUR::AutomationList& in (xf->fade_in());
775 ARDOUR::AutomationList& out (xf->fade_out());
780 ARDOUR::AutomationList::const_iterator the_end = in.end();
783 double firstx = (*in.begin())->when;
784 double endx = (*the_end)->when;
785 double miny = in.get_min_y ();
786 double maxy = in.get_max_y ();
791 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
793 double when = firstx + ((*i)->x * (endx - firstx));
794 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
795 in.add (when, value);
803 firstx = (*out.begin())->when;
804 endx = (*the_end)->when;
805 miny = out.get_min_y ();
806 maxy = out.get_max_y ();
811 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
813 double when = firstx + ((*i)->x * (endx - firstx));
814 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
815 out.add (when, value);
823 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
826 xfade->set_active (true);
827 xfade->fade_in().curve().solve ();
828 xfade->fade_out().curve().solve ();
832 CrossfadeEditor::clear ()
834 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
838 fade[current].points.clear ();
844 CrossfadeEditor::reset ()
846 set (xfade->fade_in(), In);
847 set (xfade->fade_out(), Out);
849 curve_select_clicked (current);
853 CrossfadeEditor::build_presets ()
857 fade_in_presets = new Presets;
858 fade_out_presets = new Presets;
862 p = new Preset ("Linear (-6dB)", "crossfade_in_dipped");
863 p->push_back (PresetPoint (0, 0));
864 p->push_back (PresetPoint (0.000000, 0.000000));
865 p->push_back (PresetPoint (0.166667, 0.166366));
866 p->push_back (PresetPoint (0.333333, 0.332853));
867 p->push_back (PresetPoint (0.500000, 0.499459));
868 p->push_back (PresetPoint (0.666667, 0.666186));
869 p->push_back (PresetPoint (0.833333, 0.833033));
870 p->push_back (PresetPoint (1.000000, 1.000000));
871 fade_in_presets->push_back (p);
873 p = new Preset ("S(1)-curve", "crossfade_in_default");
874 p->push_back (PresetPoint (0, 0));
875 p->push_back (PresetPoint (0.1, 0.01));
876 p->push_back (PresetPoint (0.2, 0.03));
877 p->push_back (PresetPoint (0.8, 0.97));
878 p->push_back (PresetPoint (0.9, 0.99));
879 p->push_back (PresetPoint (1, 1));
880 fade_in_presets->push_back (p);
882 p = new Preset ("S(2)-curve", "crossfade_in_default");
883 p->push_back (PresetPoint (0.0, 0.0));
884 p->push_back (PresetPoint (0.055, 0.222));
885 p->push_back (PresetPoint (0.163, 0.35));
886 p->push_back (PresetPoint (0.837, 0.678));
887 p->push_back (PresetPoint (0.945, 0.783));
888 p->push_back (PresetPoint (1.0, 1.0));
889 fade_in_presets->push_back (p);
891 p = new Preset ("Constant Power (-3dB)", "crossfade_in_constant");
893 p->push_back (PresetPoint (0.000000, 0.000000));
894 p->push_back (PresetPoint (0.166667, 0.282192));
895 p->push_back (PresetPoint (0.333333, 0.518174));
896 p->push_back (PresetPoint (0.500000, 0.707946));
897 p->push_back (PresetPoint (0.666667, 0.851507));
898 p->push_back (PresetPoint (0.833333, 0.948859));
899 p->push_back (PresetPoint (1.000000, 1.000000));
901 fade_in_presets->push_back (p);
903 if (!Profile->get_sae()) {
904 // p = new Preset ("hiin.xpm");
905 p = new Preset ("Long cut", "crossfade_in_fast-cut");
906 p->push_back (PresetPoint (0, 0));
907 p->push_back (PresetPoint (0.0207373, 0.197222));
908 p->push_back (PresetPoint (0.0645161, 0.525));
909 p->push_back (PresetPoint (0.152074, 0.802778));
910 p->push_back (PresetPoint (0.276498, 0.919444));
911 p->push_back (PresetPoint (0.481567, 0.980556));
912 p->push_back (PresetPoint (0.767281, 1));
913 p->push_back (PresetPoint (1, 1));
914 fade_in_presets->push_back (p);
916 // p = new Preset ("loin.xpm");
917 p = new Preset ("Short cut", "crossfade_in_transition");
918 p->push_back (PresetPoint (0, 0));
919 p->push_back (PresetPoint (0.389401, 0.0333333));
920 p->push_back (PresetPoint (0.629032, 0.0861111));
921 p->push_back (PresetPoint (0.829493, 0.233333));
922 p->push_back (PresetPoint (0.9447, 0.483333));
923 p->push_back (PresetPoint (0.976959, 0.697222));
924 p->push_back (PresetPoint (1, 1));
925 fade_in_presets->push_back (p);
928 // p = new Preset ("regin2.xpm");
929 p = new Preset ("Slow cut", "crossfade_in_slow-cut");
930 p->push_back (PresetPoint (0, 0));
931 p->push_back (PresetPoint (0.304147, 0.0694444));
932 p->push_back (PresetPoint (0.529954, 0.152778));
933 p->push_back (PresetPoint (0.725806, 0.333333));
934 p->push_back (PresetPoint (0.847926, 0.558333));
935 p->push_back (PresetPoint (0.919355, 0.730556));
936 p->push_back (PresetPoint (1, 1));
937 fade_in_presets->push_back (p);
942 // p = new Preset ("regout.xpm");
943 p = new Preset ("Linear (-6dB cut)", "crossfade_out_dipped");
944 p->push_back (PresetPoint (0, 1));
945 p->push_back (PresetPoint (0.000000, 1.000000));
946 p->push_back (PresetPoint (0.166667, 0.833033));
947 p->push_back (PresetPoint (0.333333, 0.666186));
948 p->push_back (PresetPoint (0.500000, 0.499459));
949 p->push_back (PresetPoint (0.666667, 0.332853));
950 p->push_back (PresetPoint (0.833333, 0.166366));
951 p->push_back (PresetPoint (1.000000, 0.000000));
952 fade_out_presets->push_back (p);
954 p = new Preset ("S(1)-Curve", "crossfade_out_default");
955 p->push_back (PresetPoint (0, 1));
956 p->push_back (PresetPoint (0.1, 0.99));
957 p->push_back (PresetPoint (0.2, 0.97));
958 p->push_back (PresetPoint (0.8, 0.03));
959 p->push_back (PresetPoint (0.9, 0.01));
960 p->push_back (PresetPoint (1, 0));
961 fade_out_presets->push_back (p);
963 p = new Preset ("S(2)-Curve", "crossfade_out_default");
964 p->push_back (PresetPoint (0.0, 1.0));
965 p->push_back (PresetPoint (0.163, 0.678));
966 p->push_back (PresetPoint (0.055, 0.783));
967 p->push_back (PresetPoint (0.837, 0.35));
968 p->push_back (PresetPoint (0.945, 0.222));
969 p->push_back (PresetPoint (1.0, 0.0));
970 fade_out_presets->push_back (p);
972 // p = new Preset ("linout.xpm");
973 p = new Preset ("Constant Power (-3dB cut)", "crossfade_out_constant");
974 p->push_back (PresetPoint (0.000000, 1.000000));
975 p->push_back (PresetPoint (0.166667, 0.948859));
976 p->push_back (PresetPoint (0.333333, 0.851507));
977 p->push_back (PresetPoint (0.500000, 0.707946));
978 p->push_back (PresetPoint (0.666667, 0.518174));
979 p->push_back (PresetPoint (0.833333, 0.282192));
980 p->push_back (PresetPoint (1.000000, 0.000000));
981 fade_out_presets->push_back (p);
983 if (!Profile->get_sae()) {
984 // p = new Preset ("hiout.xpm");
985 p = new Preset ("Slow end/cut", "crossfade_out_fast-cut");
986 p->push_back (PresetPoint (0, 1));
987 p->push_back (PresetPoint (0.305556, 1));
988 p->push_back (PresetPoint (0.548611, 0.991736));
989 p->push_back (PresetPoint (0.759259, 0.931129));
990 p->push_back (PresetPoint (0.918981, 0.68595));
991 p->push_back (PresetPoint (0.976852, 0.22865));
992 p->push_back (PresetPoint (1, 0));
993 fade_out_presets->push_back (p);
995 // p = new Preset ("loout.xpm");
996 p = new Preset ("Fast start/cut", "crossfade_out_transition");
997 p->push_back (PresetPoint (0, 1));
998 p->push_back (PresetPoint (0.023041, 0.697222));
999 p->push_back (PresetPoint (0.0553, 0.483333));
1000 p->push_back (PresetPoint (0.170507, 0.233333));
1001 p->push_back (PresetPoint (0.370968, 0.0861111));
1002 p->push_back (PresetPoint (0.610599, 0.0333333));
1003 p->push_back (PresetPoint (1, 0));
1004 fade_out_presets->push_back (p);
1006 // p = new Preset ("regout2.xpm");
1007 p = new Preset ("Slow Fade", "crossfade_out_slow-fade");
1008 p->push_back (PresetPoint (0, 1));
1009 p->push_back (PresetPoint (0.080645, 0.730556));
1010 p->push_back (PresetPoint (0.277778, 0.289256));
1011 p->push_back (PresetPoint (0.470046, 0.152778));
1012 p->push_back (PresetPoint (0.695853, 0.0694444));
1013 p->push_back (PresetPoint (1, 0));
1014 fade_out_presets->push_back (p);
1019 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1025 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1026 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1027 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1030 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1031 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1032 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1035 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1036 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1037 fade[Out].shading->hide();
1038 fade[In].shading->show();
1040 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1044 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1050 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1051 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1052 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1055 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1056 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1057 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1060 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1061 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1062 fade[In].shading->hide();
1063 fade[Out].shading->show();
1065 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1069 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1077 CrossfadeEditor::x_coordinate (double& xfract) const
1079 xfract = min (1.0, xfract);
1080 xfract = max (0.0, xfract);
1082 return canvas_border + (xfract * effective_width());
1086 CrossfadeEditor::y_coordinate (double& yfract) const
1088 yfract = min (1.0, yfract);
1089 yfract = max (0.0, yfract);
1091 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1095 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1098 uint32_t nchans = region->n_channels();
1103 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1105 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1108 ht = canvas->get_allocation().get_height() / (double) nchans;
1109 spu = xfade->length() / (double) effective_width();
1111 for (uint32_t n = 0; n < nchans; ++n) {
1113 gdouble yoff = n * ht;
1115 if (region->audio_source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1116 WaveView* waveview = new WaveView (*(canvas->root()));
1118 waveview->property_data_src() = region.get();
1119 waveview->property_cache_updater() = true;
1120 waveview->property_cache() = WaveView::create_cache();
1121 waveview->property_channel() = n;
1122 waveview->property_length_function() = (void*) region_length_from_c;
1123 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1124 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1125 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1126 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1127 waveview->property_x() = canvas_border;
1128 waveview->property_y() = yoff;
1129 waveview->property_height() = ht;
1130 waveview->property_samples_per_unit() = spu;
1131 waveview->property_amplitude_above_axis() = 2.0;
1132 waveview->property_wave_color() = color;
1133 waveview->property_fill_color() = color;
1136 waveview->property_region_start() = region->start();
1138 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1140 waveview->lower_to_bottom();
1141 fade[which].waves.push_back (waveview);
1145 toplevel->lower_to_bottom();
1149 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1151 /* this should never be called, because the peak files for an xfade
1152 will be ready by the time we want them. but our API forces us
1153 to provide this, so ..
1155 peaks_ready_connection.disconnect ();
1156 make_waves (r, which);
1160 CrossfadeEditor::audition (Audition which)
1162 AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1165 nframes_t left_start_offset;
1166 nframes_t right_length;
1167 nframes_t left_length;
1169 if (which != Right && preroll_button.get_active()) {
1170 preroll = session.frame_rate() * 2; //2 second hardcoded preroll for now
1175 if (which != Left && postroll_button.get_active()) {
1176 postroll = session.frame_rate() * 2; //2 second hardcoded postroll for now
1181 // Is there enough data for the whole preroll?
1182 left_length = xfade->length();
1183 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1184 left_start_offset -= preroll;
1186 preroll = left_start_offset;
1187 left_start_offset = 0;
1189 left_length += preroll;
1191 // Is there enough data for the whole postroll?
1192 right_length = xfade->length();
1193 if ((xfade->in()->length() - right_length) > postroll) {
1194 right_length += postroll;
1196 right_length = xfade->in()->length();
1199 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out",
1200 0, Region::DefaultFlags, false)));
1201 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, right_length, "xfade in",
1202 0, Region::DefaultFlags, false)));
1204 //apply a 20ms declicking fade at the start and end of auditioning
1205 left->set_fade_in_active(true);
1206 left->set_fade_in_length(session.frame_rate() / 50);
1207 right->set_fade_out_active(true);
1208 right->set_fade_out_length(session.frame_rate() / 50);
1210 pl.add_region (left, 0);
1211 pl.add_region (right, 1 + preroll);
1213 if (which == Left) {
1214 right->set_scale_amplitude (0.0);
1215 } else if (which == Right) {
1216 left->set_scale_amplitude (0.0);
1219 /* there is only one ... */
1220 pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1222 session.audition_playlist ();
1226 CrossfadeEditor::audition_both ()
1232 CrossfadeEditor::audition_left_dry ()
1234 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left",
1235 0, Region::DefaultFlags, false)));
1237 session.audition_region (left);
1241 CrossfadeEditor::audition_left ()
1247 CrossfadeEditor::audition_right_dry ()
1249 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in",
1250 0, Region::DefaultFlags, false)));
1251 session.audition_region (right);
1255 CrossfadeEditor::audition_right ()
1261 CrossfadeEditor::cancel_audition ()
1263 session.cancel_audition ();
1267 CrossfadeEditor::audition_toggled ()
1271 if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1282 CrossfadeEditor::audition_right_toggled ()
1286 if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1297 CrossfadeEditor::audition_right_dry_toggled ()
1301 if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1304 audition_right_dry ();
1312 CrossfadeEditor::audition_left_toggled ()
1316 if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1327 CrossfadeEditor::audition_left_dry_toggled ()
1331 if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1334 audition_left_dry ();
1342 CrossfadeEditor::on_key_press_event (GdkEventKey *ev)
1348 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1350 switch (ev->keyval) {
1352 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1353 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1355 audition_right_button.set_active (!audition_right_button.get_active());
1360 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1361 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1363 audition_left_button.set_active (!audition_left_button.get_active());
1368 if (session.is_auditioning()) {
1371 audition_both_button.set_active (!audition_both_button.get_active());