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 if (!Profile->get_sae()) {
929 p = new Preset ("Short cut", "fadein-short-cut");
930 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
937 fade_in_presets->push_back (p);
939 p = new Preset ("Slow cut", "fadein-slow-cut");
940 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
947 fade_in_presets->push_back (p);
949 p = new Preset ("Fast cut", "fadein-fast-cut");
950 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
957 fade_in_presets->push_back (p);
959 p = new Preset ("Long cut", "fadein-long-cut");
960 p->push_back (PresetPoint (0, GAIN_COEFF_SMALL));
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, GAIN_COEFF_UNITY));
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.000000, GAIN_COEFF_UNITY));
976 p->push_back (PresetPoint (0.166667, 0.833033));
977 p->push_back (PresetPoint (0.333333, 0.666186));
978 p->push_back (PresetPoint (0.500000, 0.499459));
979 p->push_back (PresetPoint (0.666667, 0.332853));
980 p->push_back (PresetPoint (0.833333, 0.166366));
981 p->push_back (PresetPoint (1.000000, GAIN_COEFF_SMALL));
982 fade_out_presets->push_back (p);
984 p = new Preset ("S(1)-Curve", "fadeout-S1");
985 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
986 p->push_back (PresetPoint (0.1, 0.99));
987 p->push_back (PresetPoint (0.2, 0.97));
988 p->push_back (PresetPoint (0.8, 0.03));
989 p->push_back (PresetPoint (0.9, 0.01));
990 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
991 fade_out_presets->push_back (p);
993 p = new Preset ("S(2)-Curve", "fadeout-S2");
994 p->push_back (PresetPoint (0.0, GAIN_COEFF_UNITY));
995 p->push_back (PresetPoint (0.163, 0.678));
996 p->push_back (PresetPoint (0.055, 0.783));
997 p->push_back (PresetPoint (0.837, 0.35));
998 p->push_back (PresetPoint (0.945, 0.222));
999 p->push_back (PresetPoint (1.0, GAIN_COEFF_SMALL));
1000 fade_out_presets->push_back (p);
1002 // p = new Preset ("linout.xpm");
1003 p = new Preset ("Constant power (-3dB cut)", "fadeout-constant-power");
1004 p->push_back (PresetPoint (0.000000, GAIN_COEFF_UNITY));
1005 p->push_back (PresetPoint (0.166667, 0.948859));
1006 p->push_back (PresetPoint (0.333333, 0.851507));
1007 p->push_back (PresetPoint (0.500000, 0.707946));
1008 p->push_back (PresetPoint (0.666667, 0.518174));
1009 p->push_back (PresetPoint (0.833333, 0.282192));
1010 p->push_back (PresetPoint (1.000000, GAIN_COEFF_SMALL));
1011 fade_out_presets->push_back (p);
1013 if (!Profile->get_sae()) {
1014 // p = new Preset ("hiout.xpm");
1015 p = new Preset ("Short cut", "fadeout-short-cut");
1016 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1017 p->push_back (PresetPoint (0.305556, GAIN_COEFF_UNITY));
1018 p->push_back (PresetPoint (0.548611, 0.991736));
1019 p->push_back (PresetPoint (0.759259, 0.931129));
1020 p->push_back (PresetPoint (0.918981, 0.68595));
1021 p->push_back (PresetPoint (0.976852, 0.22865));
1022 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1023 fade_out_presets->push_back (p);
1025 p = new Preset ("Slow cut", "fadeout-slow-cut");
1026 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1027 p->push_back (PresetPoint (0.228111, 0.988889));
1028 p->push_back (PresetPoint (0.347926, 0.972222));
1029 p->push_back (PresetPoint (0.529954, 0.886111));
1030 p->push_back (PresetPoint (0.753456, 0.658333));
1031 p->push_back (PresetPoint (0.9262673, 0.308333));
1032 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1033 fade_out_presets->push_back (p);
1035 p = new Preset ("Fast cut", "fadeout-fast-cut");
1036 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1037 p->push_back (PresetPoint (0.080645, 0.730556));
1038 p->push_back (PresetPoint (0.277778, 0.289256));
1039 p->push_back (PresetPoint (0.470046, 0.152778));
1040 p->push_back (PresetPoint (0.695853, 0.0694444));
1041 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1042 fade_out_presets->push_back (p);
1044 // p = new Preset ("loout.xpm");
1045 p = new Preset ("Long cut", "fadeout-long-cut");
1046 p->push_back (PresetPoint (0, GAIN_COEFF_UNITY));
1047 p->push_back (PresetPoint (0.023041, 0.697222));
1048 p->push_back (PresetPoint (0.0553, 0.483333));
1049 p->push_back (PresetPoint (0.170507, 0.233333));
1050 p->push_back (PresetPoint (0.370968, 0.0861111));
1051 p->push_back (PresetPoint (0.610599, 0.0333333));
1052 p->push_back (PresetPoint (1, GAIN_COEFF_SMALL));
1053 fade_out_presets->push_back (p);
1059 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1065 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1066 (*i)->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1067 (*i)->set_fill_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1070 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1071 (*i)->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1072 (*i)->set_fill_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1075 fade[In].line->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorLine());
1076 fade[Out].line->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorLine());
1077 fade[Out].shading->hide();
1078 fade[In].shading->show();
1080 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1084 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1090 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1091 (*i)->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1092 (*i)->set_fill_color (UIConfiguration::instance().get_CrossfadeEditorWave());
1095 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1096 (*i)->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1097 (*i)->set_fill_color (UIConfiguration::instance().get_SelectedCrossfadeEditorWave());
1100 fade[Out].line->set_outline_color (UIConfiguration::instance().get_SelectedCrossfadeEditorLine());
1101 fade[In].line->set_outline_color (UIConfiguration::instance().get_CrossfadeEditorLine());
1102 fade[In].shading->hide();
1103 fade[Out].shading->show();
1105 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1109 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1117 CrossfadeEditor::x_coordinate (double& xfract) const
1119 xfract = min (1.0, xfract);
1120 xfract = max (0.0, xfract);
1122 return canvas_border + (xfract * effective_width());
1126 CrossfadeEditor::y_coordinate (double& yfract) const
1128 yfract = min (1.0, yfract);
1129 yfract = max (0.0, yfract);
1131 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1135 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1138 uint32_t nchans = region->n_channels();
1143 color = UIConfiguration::instance().get_SelectedCrossfadeEditorWave();
1145 color = UIConfiguration::instance().get_CrossfadeEditorWave();
1148 ht = canvas->get_allocation().get_height() / (double) nchans;
1149 spu = xfade->length() / (double) effective_width();
1151 delete _peaks_ready_connection;
1152 _peaks_ready_connection = 0;
1154 for (uint32_t n = 0; n < nchans; ++n) {
1156 gdouble yoff = n * ht;
1158 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1159 ArdourCanvas::WaveView* waveview = new ArdourCanvas::WaveView (canvas->root(), region);
1161 waveview->set_channel (n);
1162 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1163 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1164 waveview->set_x_position (canvas_border);
1165 waveview->set_y_position (yoff);
1166 waveview->set_height (ht);
1167 waveview->set_samples_per_pixel (spu);
1168 waveview->property_amplitude_above_axis() = 2.0;
1169 waveview->set_outline_color (color);
1170 waveview->set_fill_color (color);
1173 waveview->set_region_start (region->start() + region->length() - xfade->length());
1176 waveview->lower_to_bottom();
1177 fade[which].waves.push_back (waveview);
1181 toplevel->lower_to_bottom();
1185 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1187 boost::shared_ptr<AudioRegion> r (wr.lock());
1193 /* this should never be called, because the peak files for an xfade
1194 will be ready by the time we want them. but our API forces us
1195 to provide this, so ..
1197 delete _peaks_ready_connection;
1198 _peaks_ready_connection = 0;
1200 make_waves (r, which);
1204 CrossfadeEditor::audition (Audition which)
1206 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1208 framecnt_t postroll;
1209 framecnt_t left_start_offset;
1210 framecnt_t right_length;
1211 framecnt_t left_length;
1213 if (which != Right && preroll_button.get_active()) {
1214 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1219 if (which != Left && postroll_button.get_active()) {
1220 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1225 // Is there enough data for the whole preroll?
1226 left_length = xfade->length();
1227 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1228 left_start_offset -= preroll;
1230 preroll = left_start_offset;
1231 left_start_offset = 0;
1233 left_length += preroll;
1235 // Is there enough data for the whole postroll?
1236 right_length = xfade->length();
1237 if ((xfade->in()->length() - right_length) > postroll) {
1238 right_length += postroll;
1240 right_length = xfade->in()->length();
1243 PropertyList left_plist;
1244 PropertyList right_plist;
1247 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1248 left_plist.add (ARDOUR::Properties::length, left_length);
1249 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1250 left_plist.add (ARDOUR::Properties::layer, 0);
1251 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1253 right_plist.add (ARDOUR::Properties::start, 0);
1254 right_plist.add (ARDOUR::Properties::length, right_length);
1255 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1256 right_plist.add (ARDOUR::Properties::layer, 0);
1257 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1259 if (which == Left) {
1260 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1261 } else if (which == Right) {
1262 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1265 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1266 (RegionFactory::create (xfade->out(), left_plist, false)));
1267 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1268 (RegionFactory::create (xfade->in(), right_plist, false)));
1270 // apply a 20ms declicking fade at the start and end of auditioning
1271 // XXX this should really be a property
1273 left->set_fade_in_length (_session->frame_rate() / 50);
1274 right->set_fade_out_length (_session->frame_rate() / 50);
1276 pl.add_region (left, 0);
1277 pl.add_region (right, 1 + preroll);
1279 /* there is only one ... */
1280 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1282 _session->audition_playlist ();
1286 CrossfadeEditor::audition_both ()
1292 CrossfadeEditor::audition_left_dry ()
1296 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1297 plist.add (ARDOUR::Properties::length, xfade->length());
1298 plist.add (ARDOUR::Properties::name, string("xfade left"));
1299 plist.add (ARDOUR::Properties::layer, 0);
1301 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1302 (RegionFactory::create (xfade->out(), plist, false)));
1304 _session->audition_region (left);
1308 CrossfadeEditor::audition_left ()
1314 CrossfadeEditor::audition_right_dry ()
1318 plist.add (ARDOUR::Properties::start, 0);
1319 plist.add (ARDOUR::Properties::length, xfade->length());
1320 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1321 plist.add (ARDOUR::Properties::layer, 0);
1323 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1324 (RegionFactory::create (xfade->in(), plist, false)));
1326 _session->audition_region (right);
1330 CrossfadeEditor::audition_right ()
1336 CrossfadeEditor::cancel_audition ()
1338 _session->cancel_audition ();
1342 CrossfadeEditor::audition_toggled ()
1346 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1357 CrossfadeEditor::audition_right_toggled ()
1361 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1372 CrossfadeEditor::audition_right_dry_toggled ()
1376 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1379 audition_right_dry ();
1387 CrossfadeEditor::audition_left_toggled ()
1391 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1402 CrossfadeEditor::audition_left_dry_toggled ()
1406 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1409 audition_left_dry ();
1417 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1423 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1425 switch (ev->keyval) {
1427 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1428 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1430 audition_right_button.set_active (!audition_right_button.get_active());
1435 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1436 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1438 audition_left_button.set_active (!audition_left_button.get_active());
1443 if (_session->is_auditioning()) {
1446 audition_both_button.set_active (!audition_both_button.get_active());