2 Copyright (C) 2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <sigc++/bind.h>
24 #include <gtkmm/frame.h>
25 #include <gtkmm/image.h>
26 #include <gtkmm/scrolledwindow.h>
28 #include <libgnomecanvasmm/line.h>
30 #include "pbd/memento_command.h"
31 #include "ardour/automation_list.h"
32 #include "evoral/Curve.hpp"
33 #include "ardour/crossfade.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 "ardour_ui.h"
45 #include "crossfade_edit.h"
46 #include "rgb_macros.h"
49 #include "gui_thread.h"
50 #include "canvas_impl.h"
51 #include "simplerect.h"
56 using namespace ARDOUR;
59 using namespace Editing;
61 using Gtkmm2ext::Keyboard;
65 const int32_t CrossfadeEditor::Point::size = 7;
66 const double CrossfadeEditor::canvas_border = 10;
67 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
68 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
70 CrossfadeEditor::Half::Half ()
72 , normative_curve (Evoral::Parameter(GainAutomation))
73 , gain_curve (Evoral::Parameter(GainAutomation))
77 CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
78 : ArdourDialog (_("Edit Crossfade")),
80 clear_button (_("Clear")),
81 revert_button (_("Reset")),
82 audition_both_button (_("Fade")),
83 audition_left_dry_button (_("Out (dry)")),
84 audition_left_button (_("Out")),
85 audition_right_dry_button (_("In (dry)")),
86 audition_right_button (_("In")),
88 preroll_button (_("With Pre-roll")),
89 postroll_button (_("With Post-roll")),
95 fade_out_table (3, 3),
97 select_in_button (_("Fade In")),
98 select_out_button (_("Fade Out")),
100 _peaks_ready_connection (0)
105 set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME);
106 set_name ("CrossfadeEditWindow");
107 set_position (Gtk::WIN_POS_MOUSE);
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::CanvasAA ();
132 canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation));
133 canvas->set_size_request (425, 200);
135 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
136 toplevel->property_x1() = 0.0;
137 toplevel->property_y1() = 0.0;
138 toplevel->property_x2() = 10.0;
139 toplevel->property_y2() = 10.0;
140 toplevel->property_fill() = true;
141 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
142 toplevel->property_outline_pixels() = 0;
143 toplevel->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
145 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
146 fade[Out].line->property_width_pixels() = 1;
147 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
149 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
150 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
152 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
153 fade[In].line->property_width_pixels() = 1;
154 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
156 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
157 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
159 fade[In].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
160 fade[In].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
161 fade[Out].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event));
162 fade[Out].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event));
164 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
165 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
167 select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
168 select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
170 HBox* acbox = manage (new HBox);
172 audition_box.set_border_width (7);
173 audition_box.set_spacing (5);
174 audition_box.set_homogeneous (false);
175 audition_box.pack_start (audition_left_dry_button, false, false);
176 audition_box.pack_start (audition_left_button, false, false);
177 audition_box.pack_start (audition_both_button, false, false);
178 audition_box.pack_start (audition_right_button, false, false);
179 audition_box.pack_start (audition_right_dry_button, false, false);
181 Frame* audition_frame = manage (new Frame (_("Audition")));
183 audition_frame->set_name (X_("CrossfadeEditFrame"));
184 audition_frame->add (audition_box);
186 acbox->pack_start (*audition_frame, true, false);
188 Frame* canvas_frame = manage (new Frame);
189 canvas_frame->add (*canvas);
190 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
192 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
193 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
203 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
205 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
206 pbutton = manage (new Button);
207 pbutton->add (*pxmap);
208 pbutton->set_name ("CrossfadeEditButton");
209 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
210 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
211 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
212 fade_in_buttons.push_back (pbutton);
225 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
227 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
228 pbutton = manage (new Button);
229 pbutton->add (*pxmap);
230 pbutton->set_name ("CrossfadeEditButton");
231 pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
232 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
233 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
234 fade_out_buttons.push_back (pbutton);
244 clear_button.set_name ("CrossfadeEditButton");
245 revert_button.set_name ("CrossfadeEditButton");
246 ok_button->set_name ("CrossfadeEditButton");
247 cancel_button->set_name ("CrossfadeEditButton");
248 preroll_button.set_name ("CrossfadeEditButton");
249 postroll_button.set_name ("CrossfadeEditButton");
250 audition_both_button.set_name ("CrossfadeEditAuditionButton");
251 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
252 audition_left_button.set_name ("CrossfadeEditAuditionButton");
253 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
254 audition_right_button.set_name ("CrossfadeEditAuditionButton");
256 clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear));
257 revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset));
258 audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled));
259 audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
260 audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
261 audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
262 audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
264 roll_box.pack_start (preroll_button, false, false);
265 roll_box.pack_start (postroll_button, false, false);
267 Gtk::HBox* rcenter_box = manage (new HBox);
268 rcenter_box->pack_start (roll_box, true, false);
270 VBox* vpacker2 = manage (new (VBox));
272 vpacker2->set_border_width (12);
273 vpacker2->set_spacing (7);
274 vpacker2->pack_start (*acbox, false, false);
275 vpacker2->pack_start (*rcenter_box, false, false);
277 curve_button_box.set_spacing (7);
278 curve_button_box.pack_start (fade_out_table, false, false, 12);
279 curve_button_box.pack_start (*vpacker2, false, false, 12);
280 curve_button_box.pack_start (fade_in_table, false, false, 12);
282 get_vbox()->pack_start (*canvas_frame, true, true);
283 get_vbox()->pack_start (curve_button_box, false, false);
285 /* button to allow hackers to check the actual curve values */
287 // Button* foobut = manage (new Button ("dump"));
288 // foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump));
289 // vpacker.pack_start (*foobut, false, false);
292 set (xfade->fade_in(), In);
295 set (xfade->fade_out(), Out);
297 curve_select_clicked (In);
299 xfade->PropertyChanged.connect (state_connection, invalidator (*this), ui_bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context());
301 _session->AuditionActive.connect (_session_connections, invalidator (*this), ui_bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context());
305 CrossfadeEditor::~CrossfadeEditor()
307 /* most objects will be destroyed when the toplevel window is. */
309 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
313 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
317 delete _peaks_ready_connection;
321 CrossfadeEditor::dump ()
323 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
324 cerr << (*i)->when << ' ' << (*i)->value << endl;
329 CrossfadeEditor::audition_state_changed (bool yn)
331 ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn)
334 audition_both_button.set_active (false);
335 audition_left_button.set_active (false);
336 audition_right_button.set_active (false);
337 audition_left_dry_button.set_active (false);
338 audition_right_dry_button.set_active (false);
343 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
346 ARDOUR::AutomationList::const_iterator the_end;
348 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
352 fade[which].points.clear ();
353 fade[which].gain_curve.clear ();
354 fade[which].normative_curve.clear ();
360 the_end = curve.end();
363 firstx = (*curve.begin())->when;
364 endx = (*the_end)->when;
366 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
368 double xfract = ((*i)->when - firstx) / (endx - firstx);
369 double yfract = ((*i)->value - miny) / (maxy - miny);
371 Point* p = make_point ();
373 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
376 fade[which].points.push_back (p);
379 /* no need to sort because curve is already time-ordered */
383 swap (which, current);
385 swap (which, current);
389 CrossfadeEditor::curve_event (GdkEvent* event)
391 /* treat it like a toplevel event */
393 return canvas_event (event);
397 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
400 if (point->curve != fade[current].line) {
404 switch (event->type) {
405 case GDK_BUTTON_PRESS:
406 point_grabbed = true;
408 case GDK_BUTTON_RELEASE:
409 point_grabbed = false;
411 if (Keyboard::is_delete_event (&event->button)) {
412 fade[current].points.remove (point);
419 case GDK_MOTION_NOTIFY:
423 /* can't drag first or last points horizontally or vertically */
425 if (point == fade[current].points.front() || point == fade[current].points.back()) {
429 new_x = (event->motion.x - canvas_border)/effective_width();
430 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
433 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
445 CrossfadeEditor::canvas_event (GdkEvent* event)
447 switch (event->type) {
448 case GDK_BUTTON_PRESS:
449 add_control_point ((event->button.x - canvas_border)/effective_width(),
450 1.0 - ((event->button.y - canvas_border)/effective_height()));
459 CrossfadeEditor::Point::~Point()
464 CrossfadeEditor::Point*
465 CrossfadeEditor::make_point ()
467 Point* p = new Point;
469 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
470 p->box->property_fill() = true;
471 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
472 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
473 p->box->property_outline_pixels() = 1;
475 p->curve = fade[current].line;
477 p->box->signal_event().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p));
483 CrossfadeEditor::add_control_point (double x, double y)
487 /* enforce end point x location */
489 if (fade[current].points.empty()) {
491 } else if (fade[current].points.size() == 1) {
495 Point* p = make_point ();
497 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
499 fade[current].points.push_back (p);
500 fade[current].points.sort (cmp);
506 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
508 if ( xfract < 0.0 ) {
510 } else if ( xfract > 1.0 ) {
514 if ( yfract < 0.0 ) {
516 } else if ( yfract > 1.0 ) {
520 const double half_size = rint(size/2.0);
521 double x1 = nx - half_size;
522 double x2 = nx + half_size;
524 box->property_x1() = x1;
525 box->property_x2() = x2;
527 box->property_y1() = ny - half_size;
528 box->property_y2() = ny + half_size;
535 CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/)
538 toplevel->property_x1() = 0.0;
539 toplevel->property_y1() = 0.0;
540 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
541 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
544 canvas->set_scroll_region (0.0, 0.0,
545 canvas->get_allocation().get_width(),
546 canvas->get_allocation().get_height());
548 Point* end = make_point ();
551 if (fade[In].points.size() > 1) {
552 Point* old_end = fade[In].points.back();
553 fade[In].points.pop_back ();
554 end->move_to (x_coordinate (old_end->x),
555 y_coordinate (old_end->y),
556 old_end->x, old_end->y);
561 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
565 fade[In].points.push_back (end);
566 fade[In].points.sort (cmp);
568 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
569 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
575 if (fade[Out].points.size() > 1) {
576 Point* old_end = fade[Out].points.back();
577 fade[Out].points.pop_back ();
578 end->move_to (x_coordinate (old_end->x),
579 y_coordinate (old_end->y),
580 old_end->x, old_end->y);
585 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
589 fade[Out].points.push_back (end);
590 fade[Out].points.sort (cmp);
592 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
593 (*i)->move_to (x_coordinate ((*i)->x),
594 y_coordinate ((*i)->y),
598 WhichFade old_current = current;
603 current = old_current;
605 double spu = xfade->length() / (double) effective_width();
607 if (fade[In].waves.empty()) {
608 make_waves (xfade->in(), In);
611 if (fade[Out].waves.empty()) {
612 make_waves (xfade->out(), Out);
616 vector<ArdourCanvas::WaveView*>::iterator i;
619 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
621 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
626 (*i)->property_y() = yoff;
627 (*i)->property_height() = ht;
628 (*i)->property_samples_per_unit() = spu;
631 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
633 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
638 (*i)->property_y() = yoff;
639 (*i)->property_height() = ht;
640 (*i)->property_samples_per_unit() = spu;
647 CrossfadeEditor::xfade_changed (const PropertyChange&)
649 set (xfade->fade_in(), In);
650 set (xfade->fade_out(), Out);
654 CrossfadeEditor::redraw ()
656 if (canvas->get_allocation().get_width() < 2) {
660 framecnt_t len = xfade->length ();
662 fade[current].normative_curve.clear ();
663 fade[current].gain_curve.clear ();
665 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
666 fade[current].normative_curve.add ((*i)->x, (*i)->y);
669 offset = xfade->in()->start();
671 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
672 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
676 size_t npoints = (size_t) effective_width();
679 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
681 ArdourCanvas::Points pts;
682 ArdourCanvas::Points spts;
684 while (pts.size() < npoints) {
685 pts.push_back (Gnome::Art::Point (0,0));
688 while (spts.size() < npoints + 3) {
689 spts.push_back (Gnome::Art::Point (0,0));
692 /* the shade coordinates *MUST* be in anti-clockwise order.
699 spts[0].set_x (canvas_border);
700 spts[0].set_y (effective_height() + canvas_border);
704 spts[1].set_x (effective_width() + canvas_border);
705 spts[1].set_y (effective_height() + canvas_border);
709 spts[2].set_x (effective_width() + canvas_border);
710 spts[2].set_y (canvas_border);
717 spts[0].set_x (canvas_border);
718 spts[0].set_y (canvas_border);
722 spts[1].set_x (canvas_border);
723 spts[1].set_y (effective_height() + canvas_border);
727 spts[2].set_x (effective_width() + canvas_border);
728 spts[2].set_y (effective_height() + canvas_border);
732 size_t last_spt = (npoints + 3) - 1;
734 for (size_t i = 0; i < npoints; ++i) {
738 pts[i].set_x (canvas_border + i);
739 pts[i].set_y (y_coordinate (y));
741 spts[last_spt - i].set_x (canvas_border + i);
742 spts[last_spt - i].set_y (pts[i].get_y());
745 fade[current].line->property_points() = pts;
746 fade[current].shading->property_points() = spts;
748 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
749 (*i)->property_gain_src() = static_cast<Evoral::Curve*>(&fade[current].gain_curve.curve());
754 CrossfadeEditor::apply_preset (Preset *preset)
757 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
762 select_in_button.clicked();
764 select_out_button.clicked();
767 curve_select_clicked (wf);
770 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
774 fade[current].points.clear ();
776 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
777 Point* p = make_point ();
778 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
780 fade[current].points.push_back (p);
787 CrossfadeEditor::apply ()
789 _session->begin_reversible_command (_("Edit crossfade"));
791 XMLNode& before = xfade->get_state ();
795 _session->add_command (
796 new MementoCommand<Crossfade> (
797 new ARDOUR::CrossfadeBinder (_session->playlists, xfade->id ()),
798 &before, &xfade->get_state ()
802 _session->commit_reversible_command ();
806 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
808 ARDOUR::AutomationList& in (xf->fade_in());
809 ARDOUR::AutomationList& out (xf->fade_out());
814 ARDOUR::AutomationList::const_iterator the_end = in.end();
817 double firstx = (*in.begin())->when;
818 double endx = (*the_end)->when;
823 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
825 double when = firstx + ((*i)->x * (endx - firstx));
826 double value = (*i)->y;
827 in.add (when, value);
835 firstx = (*out.begin())->when;
836 endx = (*the_end)->when;
841 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
843 double when = firstx + ((*i)->x * (endx - firstx));
844 double value = (*i)->y;
845 out.add (when, value);
853 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
856 xfade->set_active (true);
857 xfade->fade_in().curve().solve ();
858 xfade->fade_out().curve().solve ();
862 CrossfadeEditor::clear ()
864 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
868 fade[current].points.clear ();
874 CrossfadeEditor::reset ()
876 set (xfade->fade_in(), In);
877 set (xfade->fade_out(), Out);
879 curve_select_clicked (current);
883 CrossfadeEditor::build_presets ()
887 fade_in_presets = new Presets;
888 fade_out_presets = new Presets;
892 p = new Preset ("Linear (-6dB)", "crossfade-in-linear");
893 p->push_back (PresetPoint (0, 0));
894 p->push_back (PresetPoint (0.000000, 0.000000));
895 p->push_back (PresetPoint (0.166667, 0.166366));
896 p->push_back (PresetPoint (0.333333, 0.332853));
897 p->push_back (PresetPoint (0.500000, 0.499459));
898 p->push_back (PresetPoint (0.666667, 0.666186));
899 p->push_back (PresetPoint (0.833333, 0.833033));
900 p->push_back (PresetPoint (1.000000, 1.000000));
901 fade_in_presets->push_back (p);
903 p = new Preset ("S(1)-curve", "crossfade-in-S1");
904 p->push_back (PresetPoint (0, 0));
905 p->push_back (PresetPoint (0.1, 0.01));
906 p->push_back (PresetPoint (0.2, 0.03));
907 p->push_back (PresetPoint (0.8, 0.97));
908 p->push_back (PresetPoint (0.9, 0.99));
909 p->push_back (PresetPoint (1, 1));
910 fade_in_presets->push_back (p);
912 p = new Preset ("S(2)-curve", "crossfade-in-S2");
913 p->push_back (PresetPoint (0.0, 0.0));
914 p->push_back (PresetPoint (0.055, 0.222));
915 p->push_back (PresetPoint (0.163, 0.35));
916 p->push_back (PresetPoint (0.837, 0.678));
917 p->push_back (PresetPoint (0.945, 0.783));
918 p->push_back (PresetPoint (1.0, 1.0));
919 fade_in_presets->push_back (p);
921 p = new Preset ("Constant Power (-3dB)", "crossfade-in-constant-power");
923 p->push_back (PresetPoint (0.000000, 0.000000));
924 p->push_back (PresetPoint (0.166667, 0.282192));
925 p->push_back (PresetPoint (0.333333, 0.518174));
926 p->push_back (PresetPoint (0.500000, 0.707946));
927 p->push_back (PresetPoint (0.666667, 0.851507));
928 p->push_back (PresetPoint (0.833333, 0.948859));
929 p->push_back (PresetPoint (1.000000, 1.000000));
931 fade_in_presets->push_back (p);
933 if (!Profile->get_sae()) {
935 p = new Preset ("Short cut", "crossfade-in-short-cut");
936 p->push_back (PresetPoint (0, 0));
937 p->push_back (PresetPoint (0.389401, 0.0333333));
938 p->push_back (PresetPoint (0.629032, 0.0861111));
939 p->push_back (PresetPoint (0.829493, 0.233333));
940 p->push_back (PresetPoint (0.9447, 0.483333));
941 p->push_back (PresetPoint (0.976959, 0.697222));
942 p->push_back (PresetPoint (1, 1));
943 fade_in_presets->push_back (p);
945 p = new Preset ("Slow cut", "crossfade-in-slow-cut");
946 p->push_back (PresetPoint (0, 0));
947 p->push_back (PresetPoint (0.304147, 0.0694444));
948 p->push_back (PresetPoint (0.529954, 0.152778));
949 p->push_back (PresetPoint (0.725806, 0.333333));
950 p->push_back (PresetPoint (0.847926, 0.558333));
951 p->push_back (PresetPoint (0.919355, 0.730556));
952 p->push_back (PresetPoint (1, 1));
953 fade_in_presets->push_back (p);
955 p = new Preset ("Fast cut", "crossfade-in-fast-cut");
956 p->push_back (PresetPoint (0, 0));
957 p->push_back (PresetPoint (0.0737327, 0.308333));
958 p->push_back (PresetPoint (0.246544, 0.658333));
959 p->push_back (PresetPoint (0.470046, 0.886111));
960 p->push_back (PresetPoint (0.652074, 0.972222));
961 p->push_back (PresetPoint (0.771889, 0.988889));
962 p->push_back (PresetPoint (1, 1));
963 fade_in_presets->push_back (p);
965 p = new Preset ("Long cut", "crossfade-in-long-cut");
966 p->push_back (PresetPoint (0, 0));
967 p->push_back (PresetPoint (0.0207373, 0.197222));
968 p->push_back (PresetPoint (0.0645161, 0.525));
969 p->push_back (PresetPoint (0.152074, 0.802778));
970 p->push_back (PresetPoint (0.276498, 0.919444));
971 p->push_back (PresetPoint (0.481567, 0.980556));
972 p->push_back (PresetPoint (0.767281, 1));
973 p->push_back (PresetPoint (1, 1));
974 fade_in_presets->push_back (p);
979 // p = new Preset ("regout.xpm");
980 p = new Preset ("Linear (-6dB cut)", "crossfade-out-linear");
981 p->push_back (PresetPoint (0, 1));
982 p->push_back (PresetPoint (0.000000, 1.000000));
983 p->push_back (PresetPoint (0.166667, 0.833033));
984 p->push_back (PresetPoint (0.333333, 0.666186));
985 p->push_back (PresetPoint (0.500000, 0.499459));
986 p->push_back (PresetPoint (0.666667, 0.332853));
987 p->push_back (PresetPoint (0.833333, 0.166366));
988 p->push_back (PresetPoint (1.000000, 0.000000));
989 fade_out_presets->push_back (p);
991 p = new Preset ("S(1)-Curve", "crossfade-out-S1");
992 p->push_back (PresetPoint (0, 1));
993 p->push_back (PresetPoint (0.1, 0.99));
994 p->push_back (PresetPoint (0.2, 0.97));
995 p->push_back (PresetPoint (0.8, 0.03));
996 p->push_back (PresetPoint (0.9, 0.01));
997 p->push_back (PresetPoint (1, 0));
998 fade_out_presets->push_back (p);
1000 p = new Preset ("S(2)-Curve", "crossfade-out-S2");
1001 p->push_back (PresetPoint (0.0, 1.0));
1002 p->push_back (PresetPoint (0.163, 0.678));
1003 p->push_back (PresetPoint (0.055, 0.783));
1004 p->push_back (PresetPoint (0.837, 0.35));
1005 p->push_back (PresetPoint (0.945, 0.222));
1006 p->push_back (PresetPoint (1.0, 0.0));
1007 fade_out_presets->push_back (p);
1009 // p = new Preset ("linout.xpm");
1010 p = new Preset ("Constant Power (-3dB cut)", "crossfade-out-constant-power");
1011 p->push_back (PresetPoint (0.000000, 1.000000));
1012 p->push_back (PresetPoint (0.166667, 0.948859));
1013 p->push_back (PresetPoint (0.333333, 0.851507));
1014 p->push_back (PresetPoint (0.500000, 0.707946));
1015 p->push_back (PresetPoint (0.666667, 0.518174));
1016 p->push_back (PresetPoint (0.833333, 0.282192));
1017 p->push_back (PresetPoint (1.000000, 0.000000));
1018 fade_out_presets->push_back (p);
1020 if (!Profile->get_sae()) {
1021 // p = new Preset ("hiout.xpm");
1022 p = new Preset ("Short cut", "crossfade-out-short-cut");
1023 p->push_back (PresetPoint (0, 1));
1024 p->push_back (PresetPoint (0.305556, 1));
1025 p->push_back (PresetPoint (0.548611, 0.991736));
1026 p->push_back (PresetPoint (0.759259, 0.931129));
1027 p->push_back (PresetPoint (0.918981, 0.68595));
1028 p->push_back (PresetPoint (0.976852, 0.22865));
1029 p->push_back (PresetPoint (1, 0));
1030 fade_out_presets->push_back (p);
1032 p = new Preset ("Slow cut", "crossfade-out-slow-cut");
1033 p->push_back (PresetPoint (0, 1));
1034 p->push_back (PresetPoint (0.228111, 0.988889));
1035 p->push_back (PresetPoint (0.347926, 0.972222));
1036 p->push_back (PresetPoint (0.529954, 0.886111));
1037 p->push_back (PresetPoint (0.753456, 0.658333));
1038 p->push_back (PresetPoint (0.9262673, 0.308333));
1039 p->push_back (PresetPoint (1, 0));
1040 fade_out_presets->push_back (p);
1042 p = new Preset ("Fast cut", "crossfade-out-fast-cut");
1043 p->push_back (PresetPoint (0, 1));
1044 p->push_back (PresetPoint (0.080645, 0.730556));
1045 p->push_back (PresetPoint (0.277778, 0.289256));
1046 p->push_back (PresetPoint (0.470046, 0.152778));
1047 p->push_back (PresetPoint (0.695853, 0.0694444));
1048 p->push_back (PresetPoint (1, 0));
1049 fade_out_presets->push_back (p);
1051 // p = new Preset ("loout.xpm");
1052 p = new Preset ("Long cut", "crossfade-out-long-cut");
1053 p->push_back (PresetPoint (0, 1));
1054 p->push_back (PresetPoint (0.023041, 0.697222));
1055 p->push_back (PresetPoint (0.0553, 0.483333));
1056 p->push_back (PresetPoint (0.170507, 0.233333));
1057 p->push_back (PresetPoint (0.370968, 0.0861111));
1058 p->push_back (PresetPoint (0.610599, 0.0333333));
1059 p->push_back (PresetPoint (1, 0));
1060 fade_out_presets->push_back (p);
1066 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1072 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1073 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1074 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1077 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1078 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1079 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1082 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1083 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1084 fade[Out].shading->hide();
1085 fade[In].shading->show();
1087 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1091 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1097 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1098 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1099 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1102 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1103 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1104 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1107 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1108 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1109 fade[In].shading->hide();
1110 fade[Out].shading->show();
1112 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1116 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1124 CrossfadeEditor::x_coordinate (double& xfract) const
1126 xfract = min (1.0, xfract);
1127 xfract = max (0.0, xfract);
1129 return canvas_border + (xfract * effective_width());
1133 CrossfadeEditor::y_coordinate (double& yfract) const
1135 yfract = min (1.0, yfract);
1136 yfract = max (0.0, yfract);
1138 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1142 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1145 uint32_t nchans = region->n_channels();
1150 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1152 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1155 ht = canvas->get_allocation().get_height() / (double) nchans;
1156 spu = xfade->length() / (double) effective_width();
1158 delete _peaks_ready_connection;
1159 _peaks_ready_connection = 0;
1161 for (uint32_t n = 0; n < nchans; ++n) {
1163 gdouble yoff = n * ht;
1165 if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr<AudioRegion>(region), which), &_peaks_ready_connection, gui_context())) {
1166 WaveView* waveview = new WaveView (*(canvas->root()));
1168 waveview->property_data_src() = region.get();
1169 waveview->property_cache_updater() = true;
1170 waveview->property_cache() = WaveView::create_cache();
1171 waveview->property_channel() = n;
1172 waveview->property_length_function() = (void*) region_length_from_c;
1173 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1174 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1175 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1176 waveview->property_gain_src() = static_cast<Evoral::Curve*>(&fade[which].gain_curve.curve());
1177 waveview->property_x() = canvas_border;
1178 waveview->property_y() = yoff;
1179 waveview->property_height() = ht;
1180 waveview->property_samples_per_unit() = spu;
1181 waveview->property_amplitude_above_axis() = 2.0;
1182 waveview->property_wave_color() = color;
1183 waveview->property_fill_color() = color;
1186 waveview->property_region_start() = region->start();
1188 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1190 waveview->lower_to_bottom();
1191 fade[which].waves.push_back (waveview);
1195 toplevel->lower_to_bottom();
1199 CrossfadeEditor::peaks_ready (boost::weak_ptr<AudioRegion> wr, WhichFade which)
1201 boost::shared_ptr<AudioRegion> r (wr.lock());
1207 /* this should never be called, because the peak files for an xfade
1208 will be ready by the time we want them. but our API forces us
1209 to provide this, so ..
1211 delete _peaks_ready_connection;
1212 _peaks_ready_connection = 0;
1214 make_waves (r, which);
1218 CrossfadeEditor::audition (Audition which)
1220 AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist());
1222 framecnt_t postroll;
1223 framecnt_t left_start_offset;
1224 framecnt_t right_length;
1225 framecnt_t left_length;
1227 if (which != Right && preroll_button.get_active()) {
1228 preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now
1233 if (which != Left && postroll_button.get_active()) {
1234 postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now
1239 // Is there enough data for the whole preroll?
1240 left_length = xfade->length();
1241 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1242 left_start_offset -= preroll;
1244 preroll = left_start_offset;
1245 left_start_offset = 0;
1247 left_length += preroll;
1249 // Is there enough data for the whole postroll?
1250 right_length = xfade->length();
1251 if ((xfade->in()->length() - right_length) > postroll) {
1252 right_length += postroll;
1254 right_length = xfade->in()->length();
1257 PropertyList left_plist;
1258 PropertyList right_plist;
1261 left_plist.add (ARDOUR::Properties::start, left_start_offset);
1262 left_plist.add (ARDOUR::Properties::length, left_length);
1263 left_plist.add (ARDOUR::Properties::name, string ("xfade out"));
1264 left_plist.add (ARDOUR::Properties::layer, 0);
1265 left_plist.add (ARDOUR::Properties::fade_in_active, true);
1267 right_plist.add (ARDOUR::Properties::start, 0);
1268 right_plist.add (ARDOUR::Properties::length, right_length);
1269 right_plist.add (ARDOUR::Properties::name, string("xfade in"));
1270 right_plist.add (ARDOUR::Properties::layer, 0);
1271 right_plist.add (ARDOUR::Properties::fade_out_active, true);
1273 if (which == Left) {
1274 right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1275 } else if (which == Right) {
1276 left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f);
1279 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1280 (RegionFactory::create (xfade->out(), left_plist, false)));
1281 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1282 (RegionFactory::create (xfade->in(), right_plist, false)));
1284 // apply a 20ms declicking fade at the start and end of auditioning
1285 // XXX this should really be a property
1287 left->set_fade_in_length (_session->frame_rate() / 50);
1288 right->set_fade_out_length (_session->frame_rate() / 50);
1290 pl.add_region (left, 0);
1291 pl.add_region (right, 1 + preroll);
1293 /* there is only one ... */
1294 pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup));
1296 _session->audition_playlist ();
1300 CrossfadeEditor::audition_both ()
1306 CrossfadeEditor::audition_left_dry ()
1310 plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length());
1311 plist.add (ARDOUR::Properties::length, xfade->length());
1312 plist.add (ARDOUR::Properties::name, string("xfade left"));
1313 plist.add (ARDOUR::Properties::layer, 0);
1315 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion>
1316 (RegionFactory::create (xfade->out(), plist, false)));
1318 _session->audition_region (left);
1322 CrossfadeEditor::audition_left ()
1328 CrossfadeEditor::audition_right_dry ()
1332 plist.add (ARDOUR::Properties::start, 0);
1333 plist.add (ARDOUR::Properties::length, xfade->length());
1334 plist.add (ARDOUR::Properties::name, string ("xfade right"));
1335 plist.add (ARDOUR::Properties::layer, 0);
1337 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion>
1338 (RegionFactory::create (xfade->in(), plist, false)));
1340 _session->audition_region (right);
1344 CrossfadeEditor::audition_right ()
1350 CrossfadeEditor::cancel_audition ()
1352 _session->cancel_audition ();
1356 CrossfadeEditor::audition_toggled ()
1360 if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) {
1371 CrossfadeEditor::audition_right_toggled ()
1375 if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) {
1386 CrossfadeEditor::audition_right_dry_toggled ()
1390 if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) {
1393 audition_right_dry ();
1401 CrossfadeEditor::audition_left_toggled ()
1405 if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) {
1416 CrossfadeEditor::audition_left_dry_toggled ()
1420 if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) {
1423 audition_left_dry ();
1431 CrossfadeEditor::on_key_press_event (GdkEventKey */*ev*/)
1437 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1439 switch (ev->keyval) {
1441 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1442 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1444 audition_right_button.set_active (!audition_right_button.get_active());
1449 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1450 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1452 audition_left_button.set_active (!audition_left_button.get_active());
1457 if (_session->is_auditioning()) {
1460 audition_both_button.set_active (!audition_both_button.get_active());