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"
53 #include "gui_thread.h"
57 using namespace ARDOUR;
60 using namespace Editing;
62 using Gtkmm2ext::Keyboard;
66 const int32_t CrossfadeEditor::Point::size = 7;
67 const double CrossfadeEditor::canvas_border = 10;
68 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
69 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
71 CrossfadeEditor::Half::Half ()
73 , normative_curve (Evoral::Parameter(GainAutomation))
74 , gain_curve (Evoral::Parameter(GainAutomation))
78 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
79 : ArdourDialog (_("Edit Crossfade")),
81 clear_button (_("Clear")),
82 revert_button (_("Reset")),
83 audition_both_button (_("Fade")),
84 audition_left_dry_button (_("Out (dry)")),
85 audition_left_button (_("Out")),
86 audition_right_dry_button (_("In (dry)")),
87 audition_right_button (_("In")),
89 preroll_button (_("With Pre-roll")),
90 postroll_button (_("With Post-roll")),
96 fade_out_table (3, 3),
98 select_in_button (_("Fade In")),
99 select_out_button (_("Fade Out")),
101 _peaks_ready_connection (0)
106 set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
107 set_name ("CrossfadeEditWindow");
109 add_accel_group (ActionManager::ui_manager->get_accel_group());
111 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
113 RadioButtonGroup sel_but_group = select_in_button.get_group();
114 select_out_button.set_group (sel_but_group);
115 select_out_button.set_mode (false);
116 select_in_button.set_mode (false);
118 get_action_area()->set_layout(BUTTONBOX_SPREAD);
119 get_action_area()->pack_start(clear_button);
120 get_action_area()->pack_start(revert_button);
121 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
122 ok_button = add_button ("OK", RESPONSE_ACCEPT);
124 if (fade_in_presets == 0) {
128 point_grabbed = false;
131 canvas = new ArdourCanvas::GtkCanvas ();
132 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
133 canvas->set_size_request (425, 200);
135 toplevel = new ArdourCanvas::Rectangle (canvas->root());
136 toplevel->set (ArdourCanvas::Rect (0, 0, 10, 10));
137 toplevel->set_fill (true);
138 toplevel->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorBase());
139 toplevel->set_outline (false);
140 toplevel->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
142 fade[Out].line = new ArdourCanvas::PolyLine (canvas->root());
143 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
145 fade[Out].shading = new ArdourCanvas::Polygon (canvas->root());
146 fade[Out].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
148 fade[In].line = new ArdourCanvas::PolyLine (canvas->root());
149 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
151 fade[In].shading = new ArdourCanvas::Polygon (canvas->root());
152 fade[In].shading->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLineShading());
154 fade[In].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
155 fade[In].line->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
156 fade[Out].shading->Event.connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
157 fade[Out].line->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->PropertyChanged.connect (state_connection, invalidator (*this), boost::bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
296 _session->AuditionActive.connect (_session_connections, invalidator (*this), boost::bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
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) {
312 delete _peaks_ready_connection;
316 CrossfadeEditor::dump ()
318 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
319 cerr << (*i)->when << ' ' << (*i)->value << endl;
324 CrossfadeEditor::audition_state_changed (bool yn)
326 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
329 audition_both_button.set_active (false);
330 audition_left_button.set_active (false);
331 audition_right_button.set_active (false);
332 audition_left_dry_button.set_active (false);
333 audition_right_dry_button.set_active (false);
338 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
341 ARDOUR::AutomationList::const_iterator the_end;
343 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
347 fade[which].points.clear ();
348 fade[which].gain_curve.clear ();
349 fade[which].normative_curve.clear ();
355 the_end = curve.end();
358 firstx = (*curve.begin())->when;
359 endx = (*the_end)->when;
361 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
363 double xfract = ((*i)->when - firstx) / (endx - firstx);
364 double yfract = ((*i)->value - miny) / (maxy - miny);
366 Point* p = make_point ();
368 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
371 fade[which].points.push_back (p);
374 /* no need to sort because curve is already time-ordered */
378 swap (which, current);
380 swap (which, current);
384 CrossfadeEditor::curve_event (GdkEvent* event)
386 /* treat it like a toplevel event */
388 return canvas_event (event);
392 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
395 if (point->curve != fade[current].line) {
399 switch (event->type) {
400 case GDK_BUTTON_PRESS:
401 point_grabbed = true;
403 case GDK_BUTTON_RELEASE:
404 point_grabbed = false;
406 if (Keyboard::is_delete_event (&event->button)) {
407 fade[current].points.remove (point);
414 case GDK_MOTION_NOTIFY:
418 /* can't drag first or last points horizontally or vertically */
420 if (point == fade[current].points.front() || point == fade[current].points.back()) {
424 new_x = (event->motion.x - canvas_border)/effective_width();
425 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
428 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
440 CrossfadeEditor::canvas_event (GdkEvent* event)
442 switch (event->type) {
443 case GDK_BUTTON_PRESS:
444 add_control_point ((event->button.x - canvas_border)/effective_width(),
445 1.0 - ((event->button.y - canvas_border)/effective_height()));
454 CrossfadeEditor::Point::~Point()
459 CrossfadeEditor::Point*
460 CrossfadeEditor::make_point ()
462 Point* p = new Point;
464 p->box = new ArdourCanvas::Rectangle (canvas->root());
465 p->box->set_fill (true);
466 p->box->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointFill());
467 p->box->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorPointOutline());
469 p->curve = fade[current].line;
471 p->box->Event.connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
477 CrossfadeEditor::add_control_point (double x, double y)
481 /* enforce end point x location */
483 if (fade[current].points.empty()) {
485 } else if (fade[current].points.size() == 1) {
489 Point* p = make_point ();
491 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
493 fade[current].points.push_back (p);
494 fade[current].points.sort (cmp);
500 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
502 if ( xfract < 0.0 ) {
504 } else if ( xfract > 1.0 ) {
508 if ( yfract < 0.0 ) {
510 } else if ( yfract > 1.0 ) {
514 const double half_size = rint(size/2.0);
515 double x1 = nx - half_size;
516 double x2 = nx + half_size;
518 box->set (ArdourCanvas::Rect (x1, ny - half_size, x2, ny + half_size));
525 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
532 canvas->get_allocation().get_width() + canvas_border,
533 canvas->get_allocation().get_height() + canvas_border
539 // canvas->set_scroll_region (0.0, 0.0,
540 // canvas->get_allocation().get_width(),
541 // canvas->get_allocation().get_height());
543 Point* end = make_point ();
546 if (fade[In].points.size() > 1) {
547 Point* old_end = fade[In].points.back();
548 fade[In].points.pop_back ();
549 end->move_to (x_coordinate (old_end->x),
550 y_coordinate (old_end->y),
551 old_end->x, old_end->y);
556 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
560 fade[In].points.push_back (end);
561 fade[In].points.sort (cmp);
563 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
564 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
570 if (fade[Out].points.size() > 1) {
571 Point* old_end = fade[Out].points.back();
572 fade[Out].points.pop_back ();
573 end->move_to (x_coordinate (old_end->x),
574 y_coordinate (old_end->y),
575 old_end->x, old_end->y);
580 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
584 fade[Out].points.push_back (end);
585 fade[Out].points.sort (cmp);
587 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
588 (*i)->move_to (x_coordinate ((*i)->x),
589 y_coordinate ((*i)->y),
593 WhichFade old_current = current;
598 current = old_current;
600 double spu = xfade->length() / (double) effective_width();
602 if (fade[In].waves.empty()) {
603 make_waves (xfade->in(), In);
606 if (fade[Out].waves.empty()) {
607 make_waves (xfade->out(), Out);
611 vector<ArdourCanvas::WaveView*>::iterator i;
614 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
616 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
621 (*i)->set_y_position (yoff);
622 (*i)->set_height (ht);
623 (*i)->set_samples_per_pixel (spu);
626 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
628 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
633 (*i)->set_y_position (yoff);
634 (*i)->set_height (ht);
635 (*i)->set_samples_per_pixel (spu);
642 CrossfadeEditor::xfade_changed (const PropertyChange&)
644 set (xfade->fade_in(), In);
645 set (xfade->fade_out(), Out);
649 CrossfadeEditor::redraw ()
651 if (canvas->get_allocation().get_width() < 2) {
655 framecnt_t len = xfade->length ();
657 fade[current].normative_curve.clear ();
658 fade[current].gain_curve.clear ();
660 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
661 fade[current].normative_curve.add ((*i)->x, (*i)->y);
664 offset = xfade->in()->start();
666 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
667 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
671 size_t npoints = (size_t) effective_width();
674 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
676 ArdourCanvas::Points pts;
677 ArdourCanvas::Points spts;
679 while (pts.size() < npoints) {
680 pts.push_back (ArdourCanvas::Duple (0,0));
683 while (spts.size() < npoints + 3) {
684 spts.push_back (ArdourCanvas::Duple (0,0));
687 /* the shade coordinates *MUST* be in anti-clockwise order.
694 spts[0].x = canvas_border;
695 spts[0].y = effective_height() + canvas_border;
699 spts[1].x = effective_width() + canvas_border;
700 spts[1].y = effective_height() + canvas_border;
704 spts[2].x = effective_width() + canvas_border;
705 spts[2].y = canvas_border;
712 spts[0].x = canvas_border;
713 spts[0].y = canvas_border;
717 spts[1].x = canvas_border;
718 spts[1].y = effective_height() + canvas_border;
722 spts[2].x = effective_width() + canvas_border;
723 spts[2].y = effective_height() + canvas_border;
727 size_t last_spt = (npoints + 3) - 1;
729 for (size_t i = 0; i < npoints; ++i) {
733 pts[i].x = canvas_border + i;
734 pts[i].y = y_coordinate (y);
736 spts[last_spt - i].x = canvas_border + i;
737 spts[last_spt - i].y = pts[i].y;
740 fade[current].line->set (pts);
741 fade[current].shading->set (pts);
743 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
744 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
749 CrossfadeEditor::apply_preset (Preset *preset)
752 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
757 select_in_button.clicked();
759 select_out_button.clicked();
762 curve_select_clicked (wf);
765 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
769 fade[current].points.clear ();
771 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
772 Point* p = make_point ();
773 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
775 fade[current].points.push_back (p);
782 CrossfadeEditor::apply ()
784 _session->begin_reversible_command (_("Edit crossfade"));
786 XMLNode& before = xfade->get_state ();
790 _session->add_command (
791 new MementoCommand<Crossfade> (
792 new ARDOUR::CrossfadeBinder (_session->playlists, xfade->id ()),
793 &before, &xfade->get_state ()
797 _session->commit_reversible_command ();
801 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
803 ARDOUR::AutomationList& in (xf->fade_in());
804 ARDOUR::AutomationList& out (xf->fade_out());
809 ARDOUR::AutomationList::const_iterator the_end = in.end();
812 double firstx = (*in.begin())->when;
813 double endx = (*the_end)->when;
818 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
820 double when = firstx + ((*i)->x * (endx - firstx));
821 double value = (*i)->y;
822 in.add (when, value);
830 firstx = (*out.begin())->when;
831 endx = (*the_end)->when;
836 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
838 double when = firstx + ((*i)->x * (endx - firstx));
839 double value = (*i)->y;
840 out.add (when, value);
848 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
851 xfade->set_active (true);
852 xfade->fade_in().curve().solve ();
853 xfade->fade_out().curve().solve ();
857 CrossfadeEditor::clear ()
859 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
863 fade[current].points.clear ();
869 CrossfadeEditor::reset ()
871 set (xfade->fade_in(), In);
872 set (xfade->fade_out(), Out);
874 curve_select_clicked (current);
878 CrossfadeEditor::build_presets ()
882 fade_in_presets = new Presets;
883 fade_out_presets = new Presets;
887 p = new Preset ("Linear (-6dB)", "fadein-linear");
888 p->push_back (PresetPoint (0, 0));
889 p->push_back (PresetPoint (0.000000, 0.000000));
890 p->push_back (PresetPoint (0.166667, 0.166366));
891 p->push_back (PresetPoint (0.333333, 0.332853));
892 p->push_back (PresetPoint (0.500000, 0.499459));
893 p->push_back (PresetPoint (0.666667, 0.666186));
894 p->push_back (PresetPoint (0.833333, 0.833033));
895 p->push_back (PresetPoint (1.000000, 1.000000));
896 fade_in_presets->push_back (p);
898 p = new Preset ("S(1)-curve", "fadein-S1");
899 p->push_back (PresetPoint (0, 0));
900 p->push_back (PresetPoint (0.1, 0.01));
901 p->push_back (PresetPoint (0.2, 0.03));
902 p->push_back (PresetPoint (0.8, 0.97));
903 p->push_back (PresetPoint (0.9, 0.99));
904 p->push_back (PresetPoint (1, 1));
905 fade_in_presets->push_back (p);
907 p = new Preset ("S(2)-curve", "fadein-S2");
908 p->push_back (PresetPoint (0.0, 0.0));
909 p->push_back (PresetPoint (0.055, 0.222));
910 p->push_back (PresetPoint (0.163, 0.35));
911 p->push_back (PresetPoint (0.837, 0.678));
912 p->push_back (PresetPoint (0.945, 0.783));
913 p->push_back (PresetPoint (1.0, 1.0));
914 fade_in_presets->push_back (p);
916 p = new Preset ("Constant power (-3dB)", "fadein-constant-power");
918 p->push_back (PresetPoint (0.000000, 0.000000));
919 p->push_back (PresetPoint (0.166667, 0.282192));
920 p->push_back (PresetPoint (0.333333, 0.518174));
921 p->push_back (PresetPoint (0.500000, 0.707946));
922 p->push_back (PresetPoint (0.666667, 0.851507));
923 p->push_back (PresetPoint (0.833333, 0.948859));
924 p->push_back (PresetPoint (1.000000, 1.000000));
926 fade_in_presets->push_back (p);
928 if (!Profile->get_sae()) {
930 p = new Preset ("Short cut", "fadein-short-cut");
931 p->push_back (PresetPoint (0, 0));
932 p->push_back (PresetPoint (0.389401, 0.0333333));
933 p->push_back (PresetPoint (0.629032, 0.0861111));
934 p->push_back (PresetPoint (0.829493, 0.233333));
935 p->push_back (PresetPoint (0.9447, 0.483333));
936 p->push_back (PresetPoint (0.976959, 0.697222));
937 p->push_back (PresetPoint (1, 1));
938 fade_in_presets->push_back (p);
940 p = new Preset ("Slow cut", "fadein-slow-cut");
941 p->push_back (PresetPoint (0, 0));
942 p->push_back (PresetPoint (0.304147, 0.0694444));
943 p->push_back (PresetPoint (0.529954, 0.152778));
944 p->push_back (PresetPoint (0.725806, 0.333333));
945 p->push_back (PresetPoint (0.847926, 0.558333));
946 p->push_back (PresetPoint (0.919355, 0.730556));
947 p->push_back (PresetPoint (1, 1));
948 fade_in_presets->push_back (p);
950 p = new Preset ("Fast cut", "fadein-fast-cut");
951 p->push_back (PresetPoint (0, 0));
952 p->push_back (PresetPoint (0.0737327, 0.308333));
953 p->push_back (PresetPoint (0.246544, 0.658333));
954 p->push_back (PresetPoint (0.470046, 0.886111));
955 p->push_back (PresetPoint (0.652074, 0.972222));
956 p->push_back (PresetPoint (0.771889, 0.988889));
957 p->push_back (PresetPoint (1, 1));
958 fade_in_presets->push_back (p);
960 p = new Preset ("Long cut", "fadein-long-cut");
961 p->push_back (PresetPoint (0, 0));
962 p->push_back (PresetPoint (0.0207373, 0.197222));
963 p->push_back (PresetPoint (0.0645161, 0.525));
964 p->push_back (PresetPoint (0.152074, 0.802778));
965 p->push_back (PresetPoint (0.276498, 0.919444));
966 p->push_back (PresetPoint (0.481567, 0.980556));
967 p->push_back (PresetPoint (0.767281, 1));
968 p->push_back (PresetPoint (1, 1));
969 fade_in_presets->push_back (p);
974 // p = new Preset ("regout.xpm");
975 p = new Preset ("Linear (-6dB cut)", "fadeout-linear");
976 p->push_back (PresetPoint (0, 1));
977 p->push_back (PresetPoint (0.000000, 1.000000));
978 p->push_back (PresetPoint (0.166667, 0.833033));
979 p->push_back (PresetPoint (0.333333, 0.666186));
980 p->push_back (PresetPoint (0.500000, 0.499459));
981 p->push_back (PresetPoint (0.666667, 0.332853));
982 p->push_back (PresetPoint (0.833333, 0.166366));
983 p->push_back (PresetPoint (1.000000, 0.000000));
984 fade_out_presets->push_back (p);
986 p = new Preset ("S(1)-Curve", "fadeout-S1");
987 p->push_back (PresetPoint (0, 1));
988 p->push_back (PresetPoint (0.1, 0.99));
989 p->push_back (PresetPoint (0.2, 0.97));
990 p->push_back (PresetPoint (0.8, 0.03));
991 p->push_back (PresetPoint (0.9, 0.01));
992 p->push_back (PresetPoint (1, 0));
993 fade_out_presets->push_back (p);
995 p = new Preset ("S(2)-Curve", "fadeout-S2");
996 p->push_back (PresetPoint (0.0, 1.0));
997 p->push_back (PresetPoint (0.163, 0.678));
998 p->push_back (PresetPoint (0.055, 0.783));
999 p->push_back (PresetPoint (0.837, 0.35));
1000 p->push_back (PresetPoint (0.945, 0.222));
1001 p->push_back (PresetPoint (1.0, 0.0));
1002 fade_out_presets->push_back (p);
1004 // p = new Preset ("linout.xpm");
1005 p = new Preset ("Constant power (-3dB cut)", "fadeout-constant-power");
1006 p->push_back (PresetPoint (0.000000, 1.000000));
1007 p->push_back (PresetPoint (0.166667, 0.948859));
1008 p->push_back (PresetPoint (0.333333, 0.851507));
1009 p->push_back (PresetPoint (0.500000, 0.707946));
1010 p->push_back (PresetPoint (0.666667, 0.518174));
1011 p->push_back (PresetPoint (0.833333, 0.282192));
1012 p->push_back (PresetPoint (1.000000, 0.000000));
1013 fade_out_presets->push_back (p);
1015 if (!Profile->get_sae()) {
1016 // p = new Preset ("hiout.xpm");
1017 p = new Preset ("Short cut", "fadeout-short-cut");
1018 p->push_back (PresetPoint (0, 1));
1019 p->push_back (PresetPoint (0.305556, 1));
1020 p->push_back (PresetPoint (0.548611, 0.991736));
1021 p->push_back (PresetPoint (0.759259, 0.931129));
1022 p->push_back (PresetPoint (0.918981, 0.68595));
1023 p->push_back (PresetPoint (0.976852, 0.22865));
1024 p->push_back (PresetPoint (1, 0));
1025 fade_out_presets->push_back (p);
1027 p = new Preset ("Slow cut", "fadeout-slow-cut");
1028 p->push_back (PresetPoint (0, 1));
1029 p->push_back (PresetPoint (0.228111, 0.988889));
1030 p->push_back (PresetPoint (0.347926, 0.972222));
1031 p->push_back (PresetPoint (0.529954, 0.886111));
1032 p->push_back (PresetPoint (0.753456, 0.658333));
1033 p->push_back (PresetPoint (0.9262673, 0.308333));
1034 p->push_back (PresetPoint (1, 0));
1035 fade_out_presets->push_back (p);
1037 p = new Preset ("Fast cut", "fadeout-fast-cut");
1038 p->push_back (PresetPoint (0, 1));
1039 p->push_back (PresetPoint (0.080645, 0.730556));
1040 p->push_back (PresetPoint (0.277778, 0.289256));
1041 p->push_back (PresetPoint (0.470046, 0.152778));
1042 p->push_back (PresetPoint (0.695853, 0.0694444));
1043 p->push_back (PresetPoint (1, 0));
1044 fade_out_presets->push_back (p);
1046 // p = new Preset ("loout.xpm");
1047 p = new Preset ("Long cut", "fadeout-long-cut");
1048 p->push_back (PresetPoint (0, 1));
1049 p->push_back (PresetPoint (0.023041, 0.697222));
1050 p->push_back (PresetPoint (0.0553, 0.483333));
1051 p->push_back (PresetPoint (0.170507, 0.233333));
1052 p->push_back (PresetPoint (0.370968, 0.0861111));
1053 p->push_back (PresetPoint (0.610599, 0.0333333));
1054 p->push_back (PresetPoint (1, 0));
1055 fade_out_presets->push_back (p);
1061 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1067 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1068 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1069 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1072 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1073 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1074 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1077 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1078 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1079 fade[Out].shading->hide();
1080 fade[In].shading->show();
1082 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1086 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1092 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1093 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1094 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave());
1097 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1098 (*i)->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1099 (*i)->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave());
1102 fade[Out].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorLine());
1103 fade[In].line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorLine());
1104 fade[In].shading->hide();
1105 fade[Out].shading->show();
1107 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1111 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1119 CrossfadeEditor::x_coordinate (double& xfract) const
1121 xfract = min (1.0, xfract);
1122 xfract = max (0.0, xfract);
1124 return canvas_border + (xfract * effective_width());
1128 CrossfadeEditor::y_coordinate (double& yfract) const
1130 yfract = min (1.0, yfract);
1131 yfract = max (0.0, yfract);
1133 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1137 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1140 uint32_t nchans = region->n_channels();
1145 color = ARDOUR_UI::config()->get_canvasvar_SelectedCrossfadeEditorWave();
1147 color = ARDOUR_UI::config()->get_canvasvar_CrossfadeEditorWave();
1150 ht = canvas->get_allocation().get_height() / (double) nchans;
1151 spu = xfade->length() / (double) effective_width();
1153 delete _peaks_ready_connection;
1154 _peaks_ready_connection = 0;
1156 for (uint32_t n = 0; n < nchans; ++n) {
1158 gdouble yoff = n * ht;
1160 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1161 ArdourCanvas::WaveView* waveview = new ArdourCanvas::WaveView (canvas->root(), region);
1163 waveview->set_channel (n);
1164 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1165 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1166 waveview->set_x_position (canvas_border);
1167 waveview->set_y_position (yoff);
1168 waveview->set_height (ht);
1169 waveview->set_samples_per_pixel (spu);
1170 waveview->property_amplitude_above_axis() = 2.0;
1171 waveview->set_outline_color (color);
1172 waveview->set_fill_color (color);
1175 waveview->set_region_start (region->start() + region->length() - xfade->length());
1178 waveview->lower_to_bottom();
1179 fade[which].waves.push_back (waveview);
1183 toplevel->lower_to_bottom();
1187 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1189 boost::shared_ptr<AudioRegion> r (wr.lock());
1195 /* this should never be called, because the peak files for an xfade
1196 will be ready by the time we want them. but our API forces us
1197 to provide this, so ..
1199 delete _peaks_ready_connection;
1200 _peaks_ready_connection = 0;
1202 make_waves (r, which);
1206 CrossfadeEditor::audition (Audition which)
1208 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1210 framecnt_t postroll;
1211 framecnt_t left_start_offset;
1212 framecnt_t right_length;
1213 framecnt_t left_length;
1215 if (which != Right && preroll_button.get_active()) {
1216 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1221 if (which != Left && postroll_button.get_active()) {
1222 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1227 // Is there enough data for the whole preroll?
1228 left_length = xfade->length();
1229 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1230 left_start_offset -= preroll;
1232 preroll = left_start_offset;
1233 left_start_offset = 0;
1235 left_length += preroll;
1237 // Is there enough data for the whole postroll?
1238 right_length = xfade->length();
1239 if ((xfade->in()->length() - right_length) > postroll) {
1240 right_length += postroll;
1242 right_length = xfade->in()->length();
1245 PropertyList left_plist;
1246 PropertyList right_plist;
1249 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1250 left_plist.add (ARDOUR::Properties::length, left_length);
1251 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1252 left_plist.add (ARDOUR::Properties::layer, 0);
1253 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1255 right_plist.add (ARDOUR::Properties::start, 0);
1256 right_plist.add (ARDOUR::Properties::length, right_length);
1257 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1258 right_plist.add (ARDOUR::Properties::layer, 0);
1259 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1261 if (which == Left) {
1262 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1263 } else if (which == Right) {
1264 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1267 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1268 (RegionFactory::create (xfade->out(), left_plist, false)));
1269 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1270 (RegionFactory::create (xfade->in(), right_plist, false)));
1272 // apply a 20ms declicking fade at the start and end of auditioning
1273 // XXX this should really be a property
1275 left->set_fade_in_length (_session->frame_rate() / 50);
1276 right->set_fade_out_length (_session->frame_rate() / 50);
1278 pl.add_region (left, 0);
1279 pl.add_region (right, 1 + preroll);
1281 /* there is only one ... */
1282 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1284 _session->audition_playlist ();
1288 CrossfadeEditor::audition_both ()
1294 CrossfadeEditor::audition_left_dry ()
1298 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1299 plist.add (ARDOUR::Properties::length, xfade->length());
1300 plist.add (ARDOUR::Properties::name, string("xfade left"));
1301 plist.add (ARDOUR::Properties::layer, 0);
1303 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1304 (RegionFactory::create (xfade->out(), plist, false)));
1306 _session->audition_region (left);
1310 CrossfadeEditor::audition_left ()
1316 CrossfadeEditor::audition_right_dry ()
1320 plist.add (ARDOUR::Properties::start, 0);
1321 plist.add (ARDOUR::Properties::length, xfade->length());
1322 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1323 plist.add (ARDOUR::Properties::layer, 0);
1325 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1326 (RegionFactory::create (xfade->in(), plist, false)));
1328 _session->audition_region (right);
1332 CrossfadeEditor::audition_right ()
1338 CrossfadeEditor::cancel_audition ()
1340 _session->cancel_audition ();
1344 CrossfadeEditor::audition_toggled ()
1348 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1359 CrossfadeEditor::audition_right_toggled ()
1363 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1374 CrossfadeEditor::audition_right_dry_toggled ()
1378 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1381 audition_right_dry ();
1389 CrossfadeEditor::audition_left_toggled ()
1393 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1404 CrossfadeEditor::audition_left_dry_toggled ()
1408 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1411 audition_left_dry ();
1419 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1425 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1427 switch (ev->keyval) {
1429 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1430 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1432 audition_right_button.set_active (!audition_right_button.get_active());
1437 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1438 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1440 audition_left_button.set_active (!audition_left_button.get_active());
1445 if (_session->is_auditioning()) {
1448 audition_both_button.set_active (!audition_both_button.get_active());