2 Copyright (C) 2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <sigc++/bind.h>
24 #include <gtkmm/frame.h>
25 #include <gtkmm/image.h>
26 #include <gtkmm/scrolledwindow.h>
29 #include "pbd/memento_command.h"
30 #include "ardour/automation_list.h"
31 #include "evoral/Curve.hpp"
32 #include "ardour/crossfade.h"
33 #include "ardour/session.h"
34 #include "ardour/auditioner.h"
35 #include "ardour/audioplaylist.h"
36 #include "ardour/audiosource.h"
37 #include "ardour/region_factory.h"
38 #include "ardour/profile.h"
39 #include "ardour/crossfade_binder.h"
41 #include <gtkmm2ext/gtk_ui.h>
43 #include "canvas/rectangle.h"
44 #include "canvas/wave_view.h"
45 #include "canvas/line.h"
46 #include "canvas/polygon.h"
48 #include "ardour_ui.h"
49 #include "crossfade_edit.h"
50 #include "rgb_macros.h"
52 #include "gui_thread.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::GtkCanvas ();
131 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
132 canvas->set_size_request (425, 200);
134 toplevel = new ArdourCanvas::Rectangle (canvas->root());
135 toplevel->set (ArdourCanvas::Rect (0, 0, 10, 10));
136 toplevel->set_fill (true);
137 toplevel->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorBase());
138 toplevel->set_outline (false);
139 toplevel->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
141 fade[Out].line = new ArdourCanvas::PolyLine (canvas->root());
142 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
144 fade[Out].shading = new ArdourCanvas::Polygon (canvas->root());
145 fade[Out].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
147 fade[In].line = new ArdourCanvas::PolyLine (canvas->root());
148 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
150 fade[In].shading = new ArdourCanvas::Polygon (canvas->root());
151 fade[In].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
153 fade[In].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
154 fade[In].line->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
155 fade[Out].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
156 fade[Out].line->Event.connect (sigc::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 (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
162 select_out_button.signal_clicked().connect (sigc::bind (sigc::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 (sigc::bind (sigc::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 (sigc::bind (sigc::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 (sigc::mem_fun(*this, &CrossfadeEditor::clear));
251 revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
252 audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
253 audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
254 audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
255 audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
256 audition_left_dry_button.signal_toggled().connect (sigc::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 (sigc::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->PropertyChanged.connect (state_connection, invalidator (*this), boost::bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
295 _session->AuditionActive.connect (_session_connections, invalidator (*this), boost::bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
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) {
311 delete _peaks_ready_connection;
315 CrossfadeEditor::dump ()
317 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
318 cerr << (*i)->when << ' ' << (*i)->value << endl;
323 CrossfadeEditor::audition_state_changed (bool yn)
325 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
328 audition_both_button.set_active (false);
329 audition_left_button.set_active (false);
330 audition_right_button.set_active (false);
331 audition_left_dry_button.set_active (false);
332 audition_right_dry_button.set_active (false);
337 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
340 ARDOUR::AutomationList::const_iterator the_end;
342 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
346 fade[which].points.clear ();
347 fade[which].gain_curve.clear ();
348 fade[which].normative_curve.clear ();
354 the_end = curve.end();
357 firstx = (*curve.begin())->when;
358 endx = (*the_end)->when;
360 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
362 double xfract = ((*i)->when - firstx) / (endx - firstx);
363 double yfract = ((*i)->value - miny) / (maxy - miny);
365 Point* p = make_point ();
367 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
370 fade[which].points.push_back (p);
373 /* no need to sort because curve is already time-ordered */
377 swap (which, current);
379 swap (which, current);
383 CrossfadeEditor::curve_event (GdkEvent* event)
385 /* treat it like a toplevel event */
387 return canvas_event (event);
391 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
394 if (point->curve != fade[current].line) {
398 switch (event->type) {
399 case GDK_BUTTON_PRESS:
400 point_grabbed = true;
402 case GDK_BUTTON_RELEASE:
403 point_grabbed = false;
405 if (Keyboard::is_delete_event (&event->button)) {
406 fade[current].points.remove (point);
413 case GDK_MOTION_NOTIFY:
417 /* can't drag first or last points horizontally or vertically */
419 if (point == fade[current].points.front() || point == fade[current].points.back()) {
423 new_x = (event->motion.x - canvas_border)/effective_width();
424 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
427 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
439 CrossfadeEditor::canvas_event (GdkEvent* event)
441 switch (event->type) {
442 case GDK_BUTTON_PRESS:
443 add_control_point ((event->button.x - canvas_border)/effective_width(),
444 1.0 - ((event->button.y - canvas_border)/effective_height()));
453 CrossfadeEditor::Point::~Point()
458 CrossfadeEditor::Point*
459 CrossfadeEditor::make_point ()
461 Point* p = new Point;
463 p->box = new ArdourCanvas::Rectangle (canvas->root());
464 p->box->set_fill (true);
465 p->box->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointFill());
466 p->box->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointOutline());
468 p->curve = fade[current].line;
470 p->box->Event.connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
476 CrossfadeEditor::add_control_point (double x, double y)
480 /* enforce end point x location */
482 if (fade[current].points.empty()) {
484 } else if (fade[current].points.size() == 1) {
488 Point* p = make_point ();
490 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
492 fade[current].points.push_back (p);
493 fade[current].points.sort (cmp);
499 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
501 if ( xfract < 0.0 ) {
503 } else if ( xfract > 1.0 ) {
507 if ( yfract < 0.0 ) {
509 } else if ( yfract > 1.0 ) {
513 const double half_size = rint(size/2.0);
514 double x1 = nx - half_size;
515 double x2 = nx + half_size;
517 box->set (ArdourCanvas::Rect (x1, ny - half_size, x2, ny + half_size));
524 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
531 canvas->get_allocation().get_width() + canvas_border,
532 canvas->get_allocation().get_height() + canvas_border
538 // canvas->set_scroll_region (0.0, 0.0,
539 // canvas->get_allocation().get_width(),
540 // canvas->get_allocation().get_height());
542 Point* end = make_point ();
545 if (fade[In].points.size() > 1) {
546 Point* old_end = fade[In].points.back();
547 fade[In].points.pop_back ();
548 end->move_to (x_coordinate (old_end->x),
549 y_coordinate (old_end->y),
550 old_end->x, old_end->y);
555 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
559 fade[In].points.push_back (end);
560 fade[In].points.sort (cmp);
562 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
563 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
569 if (fade[Out].points.size() > 1) {
570 Point* old_end = fade[Out].points.back();
571 fade[Out].points.pop_back ();
572 end->move_to (x_coordinate (old_end->x),
573 y_coordinate (old_end->y),
574 old_end->x, old_end->y);
579 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
583 fade[Out].points.push_back (end);
584 fade[Out].points.sort (cmp);
586 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
587 (*i)->move_to (x_coordinate ((*i)->x),
588 y_coordinate ((*i)->y),
592 WhichFade old_current = current;
597 current = old_current;
599 double spu = xfade->length() / (double) effective_width();
601 if (fade[In].waves.empty()) {
602 make_waves (xfade->in(), In);
605 if (fade[Out].waves.empty()) {
606 make_waves (xfade->out(), Out);
610 vector<ArdourCanvas::WaveView*>::iterator i;
613 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
615 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
620 (*i)->set_y_position (yoff);
621 (*i)->set_height (ht);
622 (*i)->set_samples_per_pixel (spu);
625 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
627 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
632 (*i)->set_y_position (yoff);
633 (*i)->set_height (ht);
634 (*i)->set_samples_per_pixel (spu);
641 CrossfadeEditor::xfade_changed (const PropertyChange&)
643 set (xfade->fade_in(), In);
644 set (xfade->fade_out(), Out);
648 CrossfadeEditor::redraw ()
650 if (canvas->get_allocation().get_width() < 2) {
654 framecnt_t len = xfade->length ();
656 fade[current].normative_curve.clear ();
657 fade[current].gain_curve.clear ();
659 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
660 fade[current].normative_curve.add ((*i)->x, (*i)->y);
663 offset = xfade->in()->start();
665 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
666 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
670 size_t npoints = (size_t) effective_width();
673 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
675 ArdourCanvas::Points pts;
676 ArdourCanvas::Points spts;
678 while (pts.size() < npoints) {
679 pts.push_back (ArdourCanvas::Duple (0,0));
682 while (spts.size() < npoints + 3) {
683 spts.push_back (ArdourCanvas::Duple (0,0));
686 /* the shade coordinates *MUST* be in anti-clockwise order.
693 spts[0].x = canvas_border;
694 spts[0].y = effective_height() + canvas_border;
698 spts[1].x = effective_width() + canvas_border;
699 spts[1].y = effective_height() + canvas_border;
703 spts[2].x = effective_width() + canvas_border;
704 spts[2].y = canvas_border;
711 spts[0].x = canvas_border;
712 spts[0].y = canvas_border;
716 spts[1].x = canvas_border;
717 spts[1].y = effective_height() + canvas_border;
721 spts[2].x = effective_width() + canvas_border;
722 spts[2].y = effective_height() + canvas_border;
726 size_t last_spt = (npoints + 3) - 1;
728 for (size_t i = 0; i < npoints; ++i) {
732 pts[i].x = canvas_border + i;
733 pts[i].y = y_coordinate (y);
735 spts[last_spt - i].x = canvas_border + i;
736 spts[last_spt - i].y = pts[i].y;
739 fade[current].line->set (pts);
740 fade[current].shading->set (pts);
742 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
743 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
748 CrossfadeEditor::apply_preset (Preset *preset)
751 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
756 select_in_button.clicked();
758 select_out_button.clicked();
761 curve_select_clicked (wf);
764 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
768 fade[current].points.clear ();
770 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
771 Point* p = make_point ();
772 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
774 fade[current].points.push_back (p);
781 CrossfadeEditor::apply ()
783 _session->begin_reversible_command (_("Edit crossfade"));
785 XMLNode& before = xfade->get_state ();
789 _session->add_command (
790 new MementoCommand<Crossfade> (
791 new ARDOUR::CrossfadeBinder (_session->playlists, xfade->id ()),
792 &before, &xfade->get_state ()
796 _session->commit_reversible_command ();
800 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
802 ARDOUR::AutomationList& in (xf->fade_in());
803 ARDOUR::AutomationList& out (xf->fade_out());
808 ARDOUR::AutomationList::const_iterator the_end = in.end();
811 double firstx = (*in.begin())->when;
812 double endx = (*the_end)->when;
817 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
819 double when = firstx + ((*i)->x * (endx - firstx));
820 double value = (*i)->y;
821 in.add (when, value);
829 firstx = (*out.begin())->when;
830 endx = (*the_end)->when;
835 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
837 double when = firstx + ((*i)->x * (endx - firstx));
838 double value = (*i)->y;
839 out.add (when, value);
847 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
850 xfade->set_active (true);
851 xfade->fade_in().curve().solve ();
852 xfade->fade_out().curve().solve ();
856 CrossfadeEditor::clear ()
858 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
862 fade[current].points.clear ();
868 CrossfadeEditor::reset ()
870 set (xfade->fade_in(), In);
871 set (xfade->fade_out(), Out);
873 curve_select_clicked (current);
877 CrossfadeEditor::build_presets ()
881 fade_in_presets = new Presets;
882 fade_out_presets = new Presets;
886 p = new Preset ("Linear (-6dB)", "fadein-linear");
887 p->push_back (PresetPoint (0, 0));
888 p->push_back (PresetPoint (0.000000, 0.000000));
889 p->push_back (PresetPoint (0.166667, 0.166366));
890 p->push_back (PresetPoint (0.333333, 0.332853));
891 p->push_back (PresetPoint (0.500000, 0.499459));
892 p->push_back (PresetPoint (0.666667, 0.666186));
893 p->push_back (PresetPoint (0.833333, 0.833033));
894 p->push_back (PresetPoint (1.000000, 1.000000));
895 fade_in_presets->push_back (p);
897 p = new Preset ("S(1)-curve", "fadein-S1");
898 p->push_back (PresetPoint (0, 0));
899 p->push_back (PresetPoint (0.1, 0.01));
900 p->push_back (PresetPoint (0.2, 0.03));
901 p->push_back (PresetPoint (0.8, 0.97));
902 p->push_back (PresetPoint (0.9, 0.99));
903 p->push_back (PresetPoint (1, 1));
904 fade_in_presets->push_back (p);
906 p = new Preset ("S(2)-curve", "fadein-S2");
907 p->push_back (PresetPoint (0.0, 0.0));
908 p->push_back (PresetPoint (0.055, 0.222));
909 p->push_back (PresetPoint (0.163, 0.35));
910 p->push_back (PresetPoint (0.837, 0.678));
911 p->push_back (PresetPoint (0.945, 0.783));
912 p->push_back (PresetPoint (1.0, 1.0));
913 fade_in_presets->push_back (p);
915 p = new Preset ("Constant power (-3dB)", "fadein-constant-power");
917 p->push_back (PresetPoint (0.000000, 0.000000));
918 p->push_back (PresetPoint (0.166667, 0.282192));
919 p->push_back (PresetPoint (0.333333, 0.518174));
920 p->push_back (PresetPoint (0.500000, 0.707946));
921 p->push_back (PresetPoint (0.666667, 0.851507));
922 p->push_back (PresetPoint (0.833333, 0.948859));
923 p->push_back (PresetPoint (1.000000, 1.000000));
925 fade_in_presets->push_back (p);
927 if (!Profile->get_sae()) {
929 p = new Preset ("Short cut", "fadein-short-cut");
930 p->push_back (PresetPoint (0, 0));
931 p->push_back (PresetPoint (0.389401, 0.0333333));
932 p->push_back (PresetPoint (0.629032, 0.0861111));
933 p->push_back (PresetPoint (0.829493, 0.233333));
934 p->push_back (PresetPoint (0.9447, 0.483333));
935 p->push_back (PresetPoint (0.976959, 0.697222));
936 p->push_back (PresetPoint (1, 1));
937 fade_in_presets->push_back (p);
939 p = new Preset ("Slow cut", "fadein-slow-cut");
940 p->push_back (PresetPoint (0, 0));
941 p->push_back (PresetPoint (0.304147, 0.0694444));
942 p->push_back (PresetPoint (0.529954, 0.152778));
943 p->push_back (PresetPoint (0.725806, 0.333333));
944 p->push_back (PresetPoint (0.847926, 0.558333));
945 p->push_back (PresetPoint (0.919355, 0.730556));
946 p->push_back (PresetPoint (1, 1));
947 fade_in_presets->push_back (p);
949 p = new Preset ("Fast cut", "fadein-fast-cut");
950 p->push_back (PresetPoint (0, 0));
951 p->push_back (PresetPoint (0.0737327, 0.308333));
952 p->push_back (PresetPoint (0.246544, 0.658333));
953 p->push_back (PresetPoint (0.470046, 0.886111));
954 p->push_back (PresetPoint (0.652074, 0.972222));
955 p->push_back (PresetPoint (0.771889, 0.988889));
956 p->push_back (PresetPoint (1, 1));
957 fade_in_presets->push_back (p);
959 p = new Preset ("Long cut", "fadein-long-cut");
960 p->push_back (PresetPoint (0, 0));
961 p->push_back (PresetPoint (0.0207373, 0.197222));
962 p->push_back (PresetPoint (0.0645161, 0.525));
963 p->push_back (PresetPoint (0.152074, 0.802778));
964 p->push_back (PresetPoint (0.276498, 0.919444));
965 p->push_back (PresetPoint (0.481567, 0.980556));
966 p->push_back (PresetPoint (0.767281, 1));
967 p->push_back (PresetPoint (1, 1));
968 fade_in_presets->push_back (p);
973 // p = new Preset ("regout.xpm");
974 p = new Preset ("Linear (-6dB cut)", "fadeout-linear");
975 p->push_back (PresetPoint (0, 1));
976 p->push_back (PresetPoint (0.000000, 1.000000));
977 p->push_back (PresetPoint (0.166667, 0.833033));
978 p->push_back (PresetPoint (0.333333, 0.666186));
979 p->push_back (PresetPoint (0.500000, 0.499459));
980 p->push_back (PresetPoint (0.666667, 0.332853));
981 p->push_back (PresetPoint (0.833333, 0.166366));
982 p->push_back (PresetPoint (1.000000, 0.000000));
983 fade_out_presets->push_back (p);
985 p = new Preset ("S(1)-Curve", "fadeout-S1");
986 p->push_back (PresetPoint (0, 1));
987 p->push_back (PresetPoint (0.1, 0.99));
988 p->push_back (PresetPoint (0.2, 0.97));
989 p->push_back (PresetPoint (0.8, 0.03));
990 p->push_back (PresetPoint (0.9, 0.01));
991 p->push_back (PresetPoint (1, 0));
992 fade_out_presets->push_back (p);
994 p = new Preset ("S(2)-Curve", "fadeout-S2");
995 p->push_back (PresetPoint (0.0, 1.0));
996 p->push_back (PresetPoint (0.163, 0.678));
997 p->push_back (PresetPoint (0.055, 0.783));
998 p->push_back (PresetPoint (0.837, 0.35));
999 p->push_back (PresetPoint (0.945, 0.222));
1000 p->push_back (PresetPoint (1.0, 0.0));
1001 fade_out_presets->push_back (p);
1003 // p = new Preset ("linout.xpm");
1004 p = new Preset ("Constant power (-3dB cut)", "fadeout-constant-power");
1005 p->push_back (PresetPoint (0.000000, 1.000000));
1006 p->push_back (PresetPoint (0.166667, 0.948859));
1007 p->push_back (PresetPoint (0.333333, 0.851507));
1008 p->push_back (PresetPoint (0.500000, 0.707946));
1009 p->push_back (PresetPoint (0.666667, 0.518174));
1010 p->push_back (PresetPoint (0.833333, 0.282192));
1011 p->push_back (PresetPoint (1.000000, 0.000000));
1012 fade_out_presets->push_back (p);
1014 if (!Profile->get_sae()) {
1015 // p = new Preset ("hiout.xpm");
1016 p = new Preset ("Short cut", "fadeout-short-cut");
1017 p->push_back (PresetPoint (0, 1));
1018 p->push_back (PresetPoint (0.305556, 1));
1019 p->push_back (PresetPoint (0.548611, 0.991736));
1020 p->push_back (PresetPoint (0.759259, 0.931129));
1021 p->push_back (PresetPoint (0.918981, 0.68595));
1022 p->push_back (PresetPoint (0.976852, 0.22865));
1023 p->push_back (PresetPoint (1, 0));
1024 fade_out_presets->push_back (p);
1026 p = new Preset ("Slow cut", "fadeout-slow-cut");
1027 p->push_back (PresetPoint (0, 1));
1028 p->push_back (PresetPoint (0.228111, 0.988889));
1029 p->push_back (PresetPoint (0.347926, 0.972222));
1030 p->push_back (PresetPoint (0.529954, 0.886111));
1031 p->push_back (PresetPoint (0.753456, 0.658333));
1032 p->push_back (PresetPoint (0.9262673, 0.308333));
1033 p->push_back (PresetPoint (1, 0));
1034 fade_out_presets->push_back (p);
1036 p = new Preset ("Fast cut", "fadeout-fast-cut");
1037 p->push_back (PresetPoint (0, 1));
1038 p->push_back (PresetPoint (0.080645, 0.730556));
1039 p->push_back (PresetPoint (0.277778, 0.289256));
1040 p->push_back (PresetPoint (0.470046, 0.152778));
1041 p->push_back (PresetPoint (0.695853, 0.0694444));
1042 p->push_back (PresetPoint (1, 0));
1043 fade_out_presets->push_back (p);
1045 // p = new Preset ("loout.xpm");
1046 p = new Preset ("Long cut", "fadeout-long-cut");
1047 p->push_back (PresetPoint (0, 1));
1048 p->push_back (PresetPoint (0.023041, 0.697222));
1049 p->push_back (PresetPoint (0.0553, 0.483333));
1050 p->push_back (PresetPoint (0.170507, 0.233333));
1051 p->push_back (PresetPoint (0.370968, 0.0861111));
1052 p->push_back (PresetPoint (0.610599, 0.0333333));
1053 p->push_back (PresetPoint (1, 0));
1054 fade_out_presets->push_back (p);
1060 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1066 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1067 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1068 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1071 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1072 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1073 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1076 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1077 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1078 fade[Out].shading->hide();
1079 fade[In].shading->show();
1081 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1085 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1091 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1092 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1093 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1096 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1097 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1098 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1101 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1102 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1103 fade[In].shading->hide();
1104 fade[Out].shading->show();
1106 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1110 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1118 CrossfadeEditor::x_coordinate (double& xfract) const
1120 xfract = min (1.0, xfract);
1121 xfract = max (0.0, xfract);
1123 return canvas_border + (xfract * effective_width());
1127 CrossfadeEditor::y_coordinate (double& yfract) const
1129 yfract = min (1.0, yfract);
1130 yfract = max (0.0, yfract);
1132 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1136 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1139 uint32_t nchans = region->n_channels();
1144 color = ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave();
1146 color = ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave();
1149 ht = canvas->get_allocation().get_height() / (double) nchans;
1150 spu = xfade->length() / (double) effective_width();
1152 delete _peaks_ready_connection;
1153 _peaks_ready_connection = 0;
1155 for (uint32_t n = 0; n < nchans; ++n) {
1157 gdouble yoff = n * ht;
1159 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1160 ArdourCanvas::WaveView* waveview = new ArdourCanvas::WaveView (canvas->root(), region);
1162 waveview->set_channel (n);
1163 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1164 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1165 waveview->set_x_position (canvas_border);
1166 waveview->set_y_position (yoff);
1167 waveview->set_height (ht);
1168 waveview->set_samples_per_pixel (spu);
1169 waveview->property_amplitude_above_axis() = 2.0;
1170 waveview->set_outline_color (color);
1171 waveview->set_fill_color (color);
1174 waveview->set_region_start (region->start() + region->length() - xfade->length());
1177 waveview->lower_to_bottom();
1178 fade[which].waves.push_back (waveview);
1182 toplevel->lower_to_bottom();
1186 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1188 boost::shared_ptr<AudioRegion> r (wr.lock());
1194 /* this should never be called, because the peak files for an xfade
1195 will be ready by the time we want them. but our API forces us
1196 to provide this, so ..
1198 delete _peaks_ready_connection;
1199 _peaks_ready_connection = 0;
1201 make_waves (r, which);
1205 CrossfadeEditor::audition (Audition which)
1207 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1209 framecnt_t postroll;
1210 framecnt_t left_start_offset;
1211 framecnt_t right_length;
1212 framecnt_t left_length;
1214 if (which != Right && preroll_button.get_active()) {
1215 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1220 if (which != Left && postroll_button.get_active()) {
1221 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1226 // Is there enough data for the whole preroll?
1227 left_length = xfade->length();
1228 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1229 left_start_offset -= preroll;
1231 preroll = left_start_offset;
1232 left_start_offset = 0;
1234 left_length += preroll;
1236 // Is there enough data for the whole postroll?
1237 right_length = xfade->length();
1238 if ((xfade->in()->length() - right_length) > postroll) {
1239 right_length += postroll;
1241 right_length = xfade->in()->length();
1244 PropertyList left_plist;
1245 PropertyList right_plist;
1248 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1249 left_plist.add (ARDOUR::Properties::length, left_length);
1250 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1251 left_plist.add (ARDOUR::Properties::layer, 0);
1252 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1254 right_plist.add (ARDOUR::Properties::start, 0);
1255 right_plist.add (ARDOUR::Properties::length, right_length);
1256 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1257 right_plist.add (ARDOUR::Properties::layer, 0);
1258 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1260 if (which == Left) {
1261 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1262 } else if (which == Right) {
1263 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1266 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1267 (RegionFactory::create (xfade->out(), left_plist, false)));
1268 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1269 (RegionFactory::create (xfade->in(), right_plist, false)));
1271 // apply a 20ms declicking fade at the start and end of auditioning
1272 // XXX this should really be a property
1274 left->set_fade_in_length (_session->frame_rate() / 50);
1275 right->set_fade_out_length (_session->frame_rate() / 50);
1277 pl.add_region (left, 0);
1278 pl.add_region (right, 1 + preroll);
1280 /* there is only one ... */
1281 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1283 _session->audition_playlist ();
1287 CrossfadeEditor::audition_both ()
1293 CrossfadeEditor::audition_left_dry ()
1297 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1298 plist.add (ARDOUR::Properties::length, xfade->length());
1299 plist.add (ARDOUR::Properties::name, string("xfade left"));
1300 plist.add (ARDOUR::Properties::layer, 0);
1302 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1303 (RegionFactory::create (xfade->out(), plist, false)));
1305 _session->audition_region (left);
1309 CrossfadeEditor::audition_left ()
1315 CrossfadeEditor::audition_right_dry ()
1319 plist.add (ARDOUR::Properties::start, 0);
1320 plist.add (ARDOUR::Properties::length, xfade->length());
1321 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1322 plist.add (ARDOUR::Properties::layer, 0);
1324 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1325 (RegionFactory::create (xfade->in(), plist, false)));
1327 _session->audition_region (right);
1331 CrossfadeEditor::audition_right ()
1337 CrossfadeEditor::cancel_audition ()
1339 _session->cancel_audition ();
1343 CrossfadeEditor::audition_toggled ()
1347 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1358 CrossfadeEditor::audition_right_toggled ()
1362 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1373 CrossfadeEditor::audition_right_dry_toggled ()
1377 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1380 audition_right_dry ();
1388 CrossfadeEditor::audition_left_toggled ()
1392 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1403 CrossfadeEditor::audition_left_dry_toggled ()
1407 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1410 audition_left_dry ();
1418 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1424 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1426 switch (ev->keyval) {
1428 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1429 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1431 audition_right_button.set_active (!audition_right_button.get_active());
1436 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1437 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1439 audition_left_button.set_active (!audition_left_button.get_active());
1444 if (_session->is_auditioning()) {
1447 audition_both_button.set_active (!audition_both_button.get_active());