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/dB.h"
34 #include "ardour/session.h"
35 #include "ardour/auditioner.h"
36 #include "ardour/audioplaylist.h"
37 #include "ardour/audiosource.h"
38 #include "ardour/region_factory.h"
39 #include "ardour/profile.h"
40 #include "ardour/crossfade_binder.h"
42 #include <gtkmm2ext/gtk_ui.h>
44 #include "canvas/rectangle.h"
45 #include "canvas/wave_view.h"
46 #include "canvas/line.h"
47 #include "canvas/polygon.h"
49 #include "ardour_ui.h"
50 #include "crossfade_edit.h"
51 #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 (UIConfiguration::instance().get_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 (UIConfiguration::instance().get_CrossfadeEditorLine());
145 fade[Out].shading = new ArdourCanvas::Polygon (canvas->root());
146 fade[Out].shading->set_fill_color (UIConfiguration::instance().get_CrossfadeEditorLineShading());
148 fade[In].line = new ArdourCanvas::PolyLine (canvas->root());
149 fade[In].line->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorLine());
151 fade[In].shading = new ArdourCanvas::Polygon (canvas->root());
152 fade[In].shading->set_fill_color (UIConfiguration::instance().get_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 (UIConfiguration::instance().get_CrossfadeEditorPointFill());
467 p->box->set_outline_color (UIConfiguration::instance().get_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 the_editor().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 the_editor().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.000000, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
895 fade_in_presets->push_back (p);
897 p = new Preset ("S(1)-curve", "fadein-S1");
898 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
904 fade_in_presets->push_back (p);
906 p = new Preset ("S(2)-curve", "fadein-S2");
907 p->push_back (PresetPoint (0.0, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
913 fade_in_presets->push_back (p);
915 p = new Preset ("Constant power (-3dB)", "fadein-constant-power");
917 p->push_back (PresetPoint (0.000000, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
925 fade_in_presets->push_back (p);
927 p = new Preset ("Short cut", "fadein-short-cut");
928 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
929 p->push_back (PresetPoint (0.389401, 0.0333333));
930 p->push_back (PresetPoint (0.629032, 0.0861111));
931 p->push_back (PresetPoint (0.829493, 0.233333));
932 p->push_back (PresetPoint (0.9447, 0.483333));
933 p->push_back (PresetPoint (0.976959, 0.697222));
934 p->push_back (PresetPoint (1, GAIN_COEFF_UNITY));
935 fade_in_presets->push_back (p);
937 p = new Preset ("Slow cut", "fadein-slow-cut");
938 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
939 p->push_back (PresetPoint (0.304147, 0.0694444));
940 p->push_back (PresetPoint (0.529954, 0.152778));
941 p->push_back (PresetPoint (0.725806, 0.333333));
942 p->push_back (PresetPoint (0.847926, 0.558333));
943 p->push_back (PresetPoint (0.919355, 0.730556));
944 p->push_back (PresetPoint (1, GAIN_COEFF_UNITY));
945 fade_in_presets->push_back (p);
947 p = new Preset ("Fast cut", "fadein-fast-cut");
948 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
949 p->push_back (PresetPoint (0.0737327, 0.308333));
950 p->push_back (PresetPoint (0.246544, 0.658333));
951 p->push_back (PresetPoint (0.470046, 0.886111));
952 p->push_back (PresetPoint (0.652074, 0.972222));
953 p->push_back (PresetPoint (0.771889, 0.988889));
954 p->push_back (PresetPoint (1, GAIN_COEFF_UNITY));
955 fade_in_presets->push_back (p);
957 p = new Preset ("Long cut", "fadein-long-cut");
958 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
959 p->push_back (PresetPoint (0.0207373, 0.197222));
960 p->push_back (PresetPoint (0.0645161, 0.525));
961 p->push_back (PresetPoint (0.152074, 0.802778));
962 p->push_back (PresetPoint (0.276498, 0.919444));
963 p->push_back (PresetPoint (0.481567, 0.980556));
964 p->push_back (PresetPoint (0.767281, 1));
965 p->push_back (PresetPoint (1, GAIN_COEFF_UNITY));
966 fade_in_presets->push_back (p);
970 // p = new Preset ("regout.xpm");
971 p = new Preset ("Linear (-6dB cut)", "fadeout-linear");
972 p->push_back (PresetPoint (0.000000, GAIN_COEFF_UNITY));
973 p->push_back (PresetPoint (0.166667, 0.833033));
974 p->push_back (PresetPoint (0.333333, 0.666186));
975 p->push_back (PresetPoint (0.500000, 0.499459));
976 p->push_back (PresetPoint (0.666667, 0.332853));
977 p->push_back (PresetPoint (0.833333, 0.166366));
978 p->push_back (PresetPoint (1.000000, GAIN_COEFF_SMALL));
979 fade_out_presets->push_back (p);
981 p = new Preset ("S(1)-Curve", "fadeout-S1");
982 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
983 p->push_back (PresetPoint (0.1, 0.99));
984 p->push_back (PresetPoint (0.2, 0.97));
985 p->push_back (PresetPoint (0.8, 0.03));
986 p->push_back (PresetPoint (0.9, 0.01));
987 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
988 fade_out_presets->push_back (p);
990 p = new Preset ("S(2)-Curve", "fadeout-S2");
991 p->push_back (PresetPoint (0.0, GAIN_COEFF_UNITY));
992 p->push_back (PresetPoint (0.163, 0.678));
993 p->push_back (PresetPoint (0.055, 0.783));
994 p->push_back (PresetPoint (0.837, 0.35));
995 p->push_back (PresetPoint (0.945, 0.222));
996 p->push_back (PresetPoint (1.0, GAIN_COEFF_SMALL));
997 fade_out_presets->push_back (p);
999 // p = new Preset ("linout.xpm");
1000 p = new Preset ("Constant power (-3dB cut)", "fadeout-constant-power");
1001 p->push_back (PresetPoint (0.000000, GAIN_COEFF_UNITY));
1002 p->push_back (PresetPoint (0.166667, 0.948859));
1003 p->push_back (PresetPoint (0.333333, 0.851507));
1004 p->push_back (PresetPoint (0.500000, 0.707946));
1005 p->push_back (PresetPoint (0.666667, 0.518174));
1006 p->push_back (PresetPoint (0.833333, 0.282192));
1007 p->push_back (PresetPoint (1.000000, GAIN_COEFF_SMALL));
1008 fade_out_presets->push_back (p);
1010 // p = new Preset ("hiout.xpm");
1011 p = new Preset ("Short cut", "fadeout-short-cut");
1012 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1013 p->push_back (PresetPoint (0.305556, GAIN_COEFF_UNITY));
1014 p->push_back (PresetPoint (0.548611, 0.991736));
1015 p->push_back (PresetPoint (0.759259, 0.931129));
1016 p->push_back (PresetPoint (0.918981, 0.68595));
1017 p->push_back (PresetPoint (0.976852, 0.22865));
1018 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1019 fade_out_presets->push_back (p);
1021 p = new Preset ("Slow cut", "fadeout-slow-cut");
1022 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1023 p->push_back (PresetPoint (0.228111, 0.988889));
1024 p->push_back (PresetPoint (0.347926, 0.972222));
1025 p->push_back (PresetPoint (0.529954, 0.886111));
1026 p->push_back (PresetPoint (0.753456, 0.658333));
1027 p->push_back (PresetPoint (0.9262673, 0.308333));
1028 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1029 fade_out_presets->push_back (p);
1031 p = new Preset ("Fast cut", "fadeout-fast-cut");
1032 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1033 p->push_back (PresetPoint (0.080645, 0.730556));
1034 p->push_back (PresetPoint (0.277778, 0.289256));
1035 p->push_back (PresetPoint (0.470046, 0.152778));
1036 p->push_back (PresetPoint (0.695853, 0.0694444));
1037 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1038 fade_out_presets->push_back (p);
1040 // p = new Preset ("loout.xpm");
1041 p = new Preset ("Long cut", "fadeout-long-cut");
1042 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1043 p->push_back (PresetPoint (0.023041, 0.697222));
1044 p->push_back (PresetPoint (0.0553, 0.483333));
1045 p->push_back (PresetPoint (0.170507, 0.233333));
1046 p->push_back (PresetPoint (0.370968, 0.0861111));
1047 p->push_back (PresetPoint (0.610599, 0.0333333));
1048 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1049 fade_out_presets->push_back (p);
1053 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1059 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1060 (*i)->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1061 (*i)->set_fill_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1064 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1065 (*i)->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1066 (*i)->set_fill_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1069 fade[In].line->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorLine());
1070 fade[Out].line->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorLine());
1071 fade[Out].shading->hide();
1072 fade[In].shading->show();
1074 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1078 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1084 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1085 (*i)->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1086 (*i)->set_fill_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1089 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1090 (*i)->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1091 (*i)->set_fill_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1094 fade[Out].line->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorLine());
1095 fade[In].line->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorLine());
1096 fade[In].shading->hide();
1097 fade[Out].shading->show();
1099 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1103 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1111 CrossfadeEditor::x_coordinate (double& xfract) const
1113 xfract = min (1.0, xfract);
1114 xfract = max (0.0, xfract);
1116 return canvas_border + (xfract * effective_width());
1120 CrossfadeEditor::y_coordinate (double& yfract) const
1122 yfract = min (1.0, yfract);
1123 yfract = max (0.0, yfract);
1125 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1129 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1132 uint32_t nchans = region->n_channels();
1137 color = UIConfiguration::instance().get_SelectedCrossfadeEditorWave();
1139 color = UIConfiguration::instance().get_CrossfadeEditorWave();
1142 ht = canvas->get_allocation().get_height() / (double) nchans;
1143 spu = xfade->length() / (double) effective_width();
1145 delete _peaks_ready_connection;
1146 _peaks_ready_connection = 0;
1148 for (uint32_t n = 0; n < nchans; ++n) {
1150 gdouble yoff = n * ht;
1152 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1153 ArdourCanvas::WaveView* waveview = new ArdourCanvas::WaveView (canvas->root(), region);
1155 waveview->set_channel (n);
1156 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1157 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1158 waveview->set_x_position (canvas_border);
1159 waveview->set_y_position (yoff);
1160 waveview->set_height (ht);
1161 waveview->set_samples_per_pixel (spu);
1162 waveview->property_amplitude_above_axis() = 2.0;
1163 waveview->set_outline_color (color);
1164 waveview->set_fill_color (color);
1167 waveview->set_region_start (region->start() + region->length() - xfade->length());
1170 waveview->lower_to_bottom();
1171 fade[which].waves.push_back (waveview);
1175 toplevel->lower_to_bottom();
1179 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1181 boost::shared_ptr<AudioRegion> r (wr.lock());
1187 /* this should never be called, because the peak files for an xfade
1188 will be ready by the time we want them. but our API forces us
1189 to provide this, so ..
1191 delete _peaks_ready_connection;
1192 _peaks_ready_connection = 0;
1194 make_waves (r, which);
1198 CrossfadeEditor::audition (Audition which)
1200 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1202 framecnt_t postroll;
1203 framecnt_t left_start_offset;
1204 framecnt_t right_length;
1205 framecnt_t left_length;
1207 if (which != Right && preroll_button.get_active()) {
1208 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1213 if (which != Left && postroll_button.get_active()) {
1214 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1219 // Is there enough data for the whole preroll?
1220 left_length = xfade->length();
1221 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1222 left_start_offset -= preroll;
1224 preroll = left_start_offset;
1225 left_start_offset = 0;
1227 left_length += preroll;
1229 // Is there enough data for the whole postroll?
1230 right_length = xfade->length();
1231 if ((xfade->in()->length() - right_length) > postroll) {
1232 right_length += postroll;
1234 right_length = xfade->in()->length();
1237 PropertyList left_plist;
1238 PropertyList right_plist;
1241 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1242 left_plist.add (ARDOUR::Properties::length, left_length);
1243 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1244 left_plist.add (ARDOUR::Properties::layer, 0);
1245 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1247 right_plist.add (ARDOUR::Properties::start, 0);
1248 right_plist.add (ARDOUR::Properties::length, right_length);
1249 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1250 right_plist.add (ARDOUR::Properties::layer, 0);
1251 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1253 if (which == Left) {
1254 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1255 } else if (which == Right) {
1256 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1259 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1260 (RegionFactory::create (xfade->out(), left_plist, false)));
1261 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1262 (RegionFactory::create (xfade->in(), right_plist, false)));
1264 // apply a 20ms declicking fade at the start and end of auditioning
1265 // XXX this should really be a property
1267 left->set_fade_in_length (_session->frame_rate() / 50);
1268 right->set_fade_out_length (_session->frame_rate() / 50);
1270 pl.add_region (left, 0);
1271 pl.add_region (right, 1 + preroll);
1273 /* there is only one ... */
1274 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1276 _session->audition_playlist ();
1280 CrossfadeEditor::audition_both ()
1286 CrossfadeEditor::audition_left_dry ()
1290 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1291 plist.add (ARDOUR::Properties::length, xfade->length());
1292 plist.add (ARDOUR::Properties::name, string("xfade left"));
1293 plist.add (ARDOUR::Properties::layer, 0);
1295 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1296 (RegionFactory::create (xfade->out(), plist, false)));
1298 _session->audition_region (left);
1302 CrossfadeEditor::audition_left ()
1308 CrossfadeEditor::audition_right_dry ()
1312 plist.add (ARDOUR::Properties::start, 0);
1313 plist.add (ARDOUR::Properties::length, xfade->length());
1314 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1315 plist.add (ARDOUR::Properties::layer, 0);
1317 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1318 (RegionFactory::create (xfade->in(), plist, false)));
1320 _session->audition_region (right);
1324 CrossfadeEditor::audition_right ()
1330 CrossfadeEditor::cancel_audition ()
1332 _session->cancel_audition ();
1336 CrossfadeEditor::audition_toggled ()
1340 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1351 CrossfadeEditor::audition_right_toggled ()
1355 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1366 CrossfadeEditor::audition_right_dry_toggled ()
1370 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1373 audition_right_dry ();
1381 CrossfadeEditor::audition_left_toggled ()
1385 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1396 CrossfadeEditor::audition_left_dry_toggled ()
1400 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1403 audition_left_dry ();
1411 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1417 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1419 switch (ev->keyval) {
1421 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1422 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1424 audition_right_button.set_active (!audition_right_button.get_active());
1429 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1430 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1432 audition_left_button.set_active (!audition_left_button.get_active());
1437 if (_session->is_auditioning()) {
1440 audition_both_button.set_active (!audition_both_button.get_active());