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 <ardour/automation_list.h>
31 #include <evoral/Curve.hpp>
32 #include <ardour/crossfade.h>
33 #include <ardour/session.h>
34 #include <ardour/auditioner.h>
35 #include <ardour/audioplaylist.h>
36 #include <ardour/audiosource.h>
37 #include <ardour/playlist_templates.h>
38 #include <ardour/region_factory.h>
39 #include <ardour/profile.h>
41 #include <gtkmm2ext/gtk_ui.h>
43 #include "ardour_ui.h"
44 #include "crossfade_edit.h"
45 #include "rgb_macros.h"
48 #include "gui_thread.h"
49 #include "canvas_impl.h"
50 #include "simplerect.h"
55 using namespace ARDOUR;
59 using namespace Editing;
63 const int32_t CrossfadeEditor::Point::size = 7;
64 const double CrossfadeEditor::canvas_border = 10;
65 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
66 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
68 CrossfadeEditor::Half::Half ()
70 //normative_curve (Evoral::Parameter(GainAutomation, 0.0, 1.0, 1.0)), // FIXME: GainAutomation?
71 normative_curve (Evoral::Parameter(GainAutomation)),
72 gain_curve (Evoral::Parameter(GainAutomation))
76 CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
77 : ArdourDialog (_("ardour: x-fade edit")),
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 set_wmclass (X_("ardour_automationedit"), "Ardour");
101 set_name ("CrossfadeEditWindow");
102 set_position (Gtk::WIN_POS_MOUSE);
104 add_accel_group (ActionManager::ui_manager->get_accel_group());
106 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
108 RadioButtonGroup sel_but_group = select_in_button.get_group();
109 select_out_button.set_group (sel_but_group);
110 select_out_button.set_mode (false);
111 select_in_button.set_mode (false);
113 get_action_area()->set_layout(BUTTONBOX_SPREAD);
114 get_action_area()->pack_start(clear_button);
115 get_action_area()->pack_start(revert_button);
116 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
117 ok_button = add_button ("OK", RESPONSE_ACCEPT);
119 if (fade_in_presets == 0) {
123 point_grabbed = false;
126 canvas = new ArdourCanvas::CanvasAA ();
127 canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation));
128 canvas->set_size_request (425, 200);
130 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
131 toplevel->property_x1() = 0.0;
132 toplevel->property_y1() = 0.0;
133 toplevel->property_x2() = 10.0;
134 toplevel->property_y2() = 10.0;
135 toplevel->property_fill() = true;
136 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
137 toplevel->property_outline_pixels() = 0;
138 toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
140 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
141 fade[Out].line->property_width_pixels() = 1;
142 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
144 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
145 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
147 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
148 fade[In].line->property_width_pixels() = 1;
149 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
151 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
152 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
154 fade[In].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
155 fade[In].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
156 fade[Out].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
157 fade[Out].line->signal_event().connect (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 (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
163 select_out_button.signal_clicked().connect (bind (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 (bind (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 (bind (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 (mem_fun(*this, &CrossfadeEditor::clear));
252 revert_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset));
253 audition_both_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled));
254 audition_right_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
255 audition_right_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
256 audition_left_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
257 audition_left_dry_button.signal_toggled().connect (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 (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->StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed));
296 session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed));
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) {
314 CrossfadeEditor::dump ()
316 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
317 cerr << (*i)->when << ' ' << (*i)->value << endl;
322 CrossfadeEditor::audition_state_changed (bool yn)
324 ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn));
327 audition_both_button.set_active (false);
328 audition_left_button.set_active (false);
329 audition_right_button.set_active (false);
330 audition_left_dry_button.set_active (false);
331 audition_right_dry_button.set_active (false);
336 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
339 ARDOUR::AutomationList::const_iterator the_end;
341 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
345 fade[which].points.clear ();
346 fade[which].gain_curve.clear ();
347 fade[which].normative_curve.clear ();
353 the_end = curve.end();
356 firstx = (*curve.begin())->when;
357 endx = (*the_end)->when;
359 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
361 double xfract = ((*i)->when - firstx) / (endx - firstx);
362 double yfract = ((*i)->value - miny) / (maxy - miny);
364 Point* p = make_point ();
366 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
369 fade[which].points.push_back (p);
372 /* no need to sort because curve is already time-ordered */
376 swap (which, current);
378 swap (which, current);
382 CrossfadeEditor::curve_event (GdkEvent* event)
384 /* treat it like a toplevel event */
386 return canvas_event (event);
390 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
393 if (point->curve != fade[current].line) {
397 switch (event->type) {
398 case GDK_BUTTON_PRESS:
399 point_grabbed = true;
401 case GDK_BUTTON_RELEASE:
402 point_grabbed = false;
404 if (Keyboard::is_delete_event (&event->button)) {
405 fade[current].points.remove (point);
412 case GDK_MOTION_NOTIFY:
416 /* can't drag first or last points horizontally */
418 if (point == fade[current].points.front() || point == fade[current].points.back()) {
421 new_x = (event->motion.x - canvas_border)/effective_width();
424 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
425 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
437 CrossfadeEditor::canvas_event (GdkEvent* event)
439 switch (event->type) {
440 case GDK_BUTTON_PRESS:
441 add_control_point ((event->button.x - canvas_border)/effective_width(),
442 1.0 - ((event->button.y - canvas_border)/effective_height()));
451 CrossfadeEditor::Point::~Point()
456 CrossfadeEditor::Point*
457 CrossfadeEditor::make_point ()
459 Point* p = new Point;
461 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
462 p->box->property_fill() = true;
463 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
464 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
465 p->box->property_outline_pixels() = 1;
467 p->curve = fade[current].line;
469 p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p));
475 CrossfadeEditor::add_control_point (double x, double y)
479 /* enforce end point x location */
481 if (fade[current].points.empty()) {
483 } else if (fade[current].points.size() == 1) {
487 Point* p = make_point ();
489 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
491 fade[current].points.push_back (p);
492 fade[current].points.sort (cmp);
498 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
500 const double half_size = rint(size/2.0);
501 double x1 = nx - half_size;
502 double x2 = nx + half_size;
504 box->property_x1() = x1;
505 box->property_x2() = x2;
507 box->property_y1() = ny - half_size;
508 box->property_y2() = ny + half_size;
515 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
518 toplevel->property_x1() = 0.0;
519 toplevel->property_y1() = 0.0;
520 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
521 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
524 canvas->set_scroll_region (0.0, 0.0,
525 canvas->get_allocation().get_width(),
526 canvas->get_allocation().get_height());
528 Point* end = make_point ();
531 if (fade[In].points.size() > 1) {
532 Point* old_end = fade[In].points.back();
533 fade[In].points.pop_back ();
534 end->move_to (x_coordinate (old_end->x),
535 y_coordinate (old_end->y),
536 old_end->x, old_end->y);
541 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
545 fade[In].points.push_back (end);
546 fade[In].points.sort (cmp);
548 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
549 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
555 if (fade[Out].points.size() > 1) {
556 Point* old_end = fade[Out].points.back();
557 fade[Out].points.pop_back ();
558 end->move_to (x_coordinate (old_end->x),
559 y_coordinate (old_end->y),
560 old_end->x, old_end->y);
565 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
569 fade[Out].points.push_back (end);
570 fade[Out].points.sort (cmp);
572 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
573 (*i)->move_to (x_coordinate ((*i)->x),
574 y_coordinate ((*i)->y),
578 WhichFade old_current = current;
583 current = old_current;
585 double spu = xfade->length() / (double) effective_width();
587 if (fade[In].waves.empty()) {
588 make_waves (xfade->in(), In);
591 if (fade[Out].waves.empty()) {
592 make_waves (xfade->out(), Out);
596 vector<ArdourCanvas::WaveView*>::iterator i;
599 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
601 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
606 (*i)->property_y() = yoff;
607 (*i)->property_height() = ht;
608 (*i)->property_samples_per_unit() = spu;
611 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
613 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
618 (*i)->property_y() = yoff;
619 (*i)->property_height() = ht;
620 (*i)->property_samples_per_unit() = spu;
627 CrossfadeEditor::xfade_changed (Change ignored)
629 set (xfade->fade_in(), In);
630 set (xfade->fade_out(), Out);
634 CrossfadeEditor::redraw ()
636 if (canvas->get_allocation().get_width() < 2) {
640 nframes_t len = xfade->length ();
642 fade[current].normative_curve.clear ();
643 fade[current].gain_curve.clear ();
645 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
646 fade[current].normative_curve.add ((*i)->x, (*i)->y);
649 offset = xfade->in()->start();
651 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
652 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
656 size_t npoints = (size_t) effective_width();
659 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
661 ArdourCanvas::Points pts;
662 ArdourCanvas::Points spts;
664 while (pts.size() < npoints) {
665 pts.push_back (Gnome::Art::Point (0,0));
668 while (spts.size() < npoints + 3) {
669 spts.push_back (Gnome::Art::Point (0,0));
672 /* the shade coordinates *MUST* be in anti-clockwise order.
679 spts[0].set_x (canvas_border);
680 spts[0].set_y (effective_height() + canvas_border);
684 spts[1].set_x (effective_width() + canvas_border);
685 spts[1].set_y (effective_height() + canvas_border);
689 spts[2].set_x (effective_width() + canvas_border);
690 spts[2].set_y (canvas_border);
697 spts[0].set_x (canvas_border);
698 spts[0].set_y (canvas_border);
702 spts[1].set_x (canvas_border);
703 spts[1].set_y (effective_height() + canvas_border);
707 spts[2].set_x (effective_width() + canvas_border);
708 spts[2].set_y (effective_height() + canvas_border);
712 size_t last_spt = (npoints + 3) - 1;
714 for (size_t i = 0; i < npoints; ++i) {
718 pts[i].set_x (canvas_border + i);
719 pts[i].set_y (y_coordinate (y));
721 spts[last_spt - i].set_x (canvas_border + i);
722 spts[last_spt - i].set_y (pts[i].get_y());
725 fade[current].line->property_points() = pts;
726 fade[current].shading->property_points() = spts;
728 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
729 (*i)->property_gain_src() = &fade[current].gain_curve;
734 CrossfadeEditor::apply_preset (Preset *preset)
737 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
742 select_in_button.clicked();
744 select_out_button.clicked();
747 curve_select_clicked (wf);
750 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
754 fade[current].points.clear ();
756 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
757 Point* p = make_point ();
758 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
760 fade[current].points.push_back (p);
767 CrossfadeEditor::apply ()
773 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
775 ARDOUR::AutomationList& in (xf->fade_in());
776 ARDOUR::AutomationList& out (xf->fade_out());
781 ARDOUR::AutomationList::const_iterator the_end = in.end();
784 double firstx = (*in.begin())->when;
785 double endx = (*the_end)->when;
786 double miny = in.get_min_y ();
787 double maxy = in.get_max_y ();
792 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
794 double when = firstx + ((*i)->x * (endx - firstx));
795 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
796 in.add (when, value);
804 firstx = (*out.begin())->when;
805 endx = (*the_end)->when;
806 miny = out.get_min_y ();
807 maxy = out.get_max_y ();
812 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
814 double when = firstx + ((*i)->x * (endx - firstx));
815 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
816 out.add (when, value);
824 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
827 xfade->set_active (true);
828 xfade->fade_in().curve().solve ();
829 xfade->fade_out().curve().solve ();
833 CrossfadeEditor::clear ()
835 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
839 fade[current].points.clear ();
845 CrossfadeEditor::reset ()
847 set (xfade->fade_in(), In);
848 set (xfade->fade_out(), Out);
850 curve_select_clicked (current);
854 CrossfadeEditor::build_presets ()
858 fade_in_presets = new Presets;
859 fade_out_presets = new Presets;
863 p = new Preset ("Linear (-6dB)", "crossfade_in_dipped");
864 p->push_back (PresetPoint (0, 0));
865 p->push_back (PresetPoint (0.000000, 0.000000));
866 p->push_back (PresetPoint (0.166667, 0.166366));
867 p->push_back (PresetPoint (0.333333, 0.332853));
868 p->push_back (PresetPoint (0.500000, 0.499459));
869 p->push_back (PresetPoint (0.666667, 0.666186));
870 p->push_back (PresetPoint (0.833333, 0.833033));
871 p->push_back (PresetPoint (1.000000, 1.000000));
872 fade_in_presets->push_back (p);
874 p = new Preset ("S(1)-curve", "crossfade_in_default");
875 p->push_back (PresetPoint (0, 0));
876 p->push_back (PresetPoint (0.1, 0.01));
877 p->push_back (PresetPoint (0.2, 0.03));
878 p->push_back (PresetPoint (0.8, 0.97));
879 p->push_back (PresetPoint (0.9, 0.99));
880 p->push_back (PresetPoint (1, 1));
881 fade_in_presets->push_back (p);
883 p = new Preset ("S(2)-curve", "crossfade_in_default");
884 p->push_back (PresetPoint (0.0, 0.0));
885 p->push_back (PresetPoint (0.055, 0.222));
886 p->push_back (PresetPoint (0.163, 0.35));
887 p->push_back (PresetPoint (0.837, 0.678));
888 p->push_back (PresetPoint (0.945, 0.783));
889 p->push_back (PresetPoint (1.0, 1.0));
890 fade_in_presets->push_back (p);
892 p = new Preset ("Constant Power (-3dB)", "crossfade_in_constant");
894 p->push_back (PresetPoint (0.000000, 0.000000));
895 p->push_back (PresetPoint (0.166667, 0.282192));
896 p->push_back (PresetPoint (0.333333, 0.518174));
897 p->push_back (PresetPoint (0.500000, 0.707946));
898 p->push_back (PresetPoint (0.666667, 0.851507));
899 p->push_back (PresetPoint (0.833333, 0.948859));
900 p->push_back (PresetPoint (1.000000, 1.000000));
902 fade_in_presets->push_back (p);
904 if (!Profile->get_sae()) {
905 // p = new Preset ("hiin.xpm");
906 p = new Preset ("Long cut", "crossfade_in_fast-cut");
907 p->push_back (PresetPoint (0, 0));
908 p->push_back (PresetPoint (0.0207373, 0.197222));
909 p->push_back (PresetPoint (0.0645161, 0.525));
910 p->push_back (PresetPoint (0.152074, 0.802778));
911 p->push_back (PresetPoint (0.276498, 0.919444));
912 p->push_back (PresetPoint (0.481567, 0.980556));
913 p->push_back (PresetPoint (0.767281, 1));
914 p->push_back (PresetPoint (1, 1));
915 fade_in_presets->push_back (p);
917 // p = new Preset ("loin.xpm");
918 p = new Preset ("Short cut", "crossfade_in_transition");
919 p->push_back (PresetPoint (0, 0));
920 p->push_back (PresetPoint (0.389401, 0.0333333));
921 p->push_back (PresetPoint (0.629032, 0.0861111));
922 p->push_back (PresetPoint (0.829493, 0.233333));
923 p->push_back (PresetPoint (0.9447, 0.483333));
924 p->push_back (PresetPoint (0.976959, 0.697222));
925 p->push_back (PresetPoint (1, 1));
926 fade_in_presets->push_back (p);
929 // p = new Preset ("regin2.xpm");
930 p = new Preset ("Slow cut", "crossfade_in_slow-cut");
931 p->push_back (PresetPoint (0, 0));
932 p->push_back (PresetPoint (0.304147, 0.0694444));
933 p->push_back (PresetPoint (0.529954, 0.152778));
934 p->push_back (PresetPoint (0.725806, 0.333333));
935 p->push_back (PresetPoint (0.847926, 0.558333));
936 p->push_back (PresetPoint (0.919355, 0.730556));
937 p->push_back (PresetPoint (1, 1));
938 fade_in_presets->push_back (p);
943 // p = new Preset ("regout.xpm");
944 p = new Preset ("Linear (-6dB cut)", "crossfade_out_dipped");
945 p->push_back (PresetPoint (0, 1));
946 p->push_back (PresetPoint (0.000000, 1.000000));
947 p->push_back (PresetPoint (0.166667, 0.833033));
948 p->push_back (PresetPoint (0.333333, 0.666186));
949 p->push_back (PresetPoint (0.500000, 0.499459));
950 p->push_back (PresetPoint (0.666667, 0.332853));
951 p->push_back (PresetPoint (0.833333, 0.166366));
952 p->push_back (PresetPoint (1.000000, 0.000000));
953 fade_out_presets->push_back (p);
955 p = new Preset ("S(1)-Curve", "crossfade_out_default");
956 p->push_back (PresetPoint (0, 1));
957 p->push_back (PresetPoint (0.1, 0.99));
958 p->push_back (PresetPoint (0.2, 0.97));
959 p->push_back (PresetPoint (0.8, 0.03));
960 p->push_back (PresetPoint (0.9, 0.01));
961 p->push_back (PresetPoint (1, 0));
962 fade_out_presets->push_back (p);
964 p = new Preset ("S(2)-Curve", "crossfade_out_default");
965 p->push_back (PresetPoint (0.0, 1.0));
966 p->push_back (PresetPoint (0.163, 0.678));
967 p->push_back (PresetPoint (0.055, 0.783));
968 p->push_back (PresetPoint (0.837, 0.35));
969 p->push_back (PresetPoint (0.945, 0.222));
970 p->push_back (PresetPoint (1.0, 0.0));
971 fade_out_presets->push_back (p);
973 // p = new Preset ("linout.xpm");
974 p = new Preset ("Constant Power (-3dB cut)", "crossfade_out_constant");
975 p->push_back (PresetPoint (0.000000, 1.000000));
976 p->push_back (PresetPoint (0.166667, 0.948859));
977 p->push_back (PresetPoint (0.333333, 0.851507));
978 p->push_back (PresetPoint (0.500000, 0.707946));
979 p->push_back (PresetPoint (0.666667, 0.518174));
980 p->push_back (PresetPoint (0.833333, 0.282192));
981 p->push_back (PresetPoint (1.000000, 0.000000));
982 fade_out_presets->push_back (p);
984 if (!Profile->get_sae()) {
985 // p = new Preset ("hiout.xpm");
986 p = new Preset ("Slow end/cut", "crossfade_out_fast-cut");
987 p->push_back (PresetPoint (0, 1));
988 p->push_back (PresetPoint (0.305556, 1));
989 p->push_back (PresetPoint (0.548611, 0.991736));
990 p->push_back (PresetPoint (0.759259, 0.931129));
991 p->push_back (PresetPoint (0.918981, 0.68595));
992 p->push_back (PresetPoint (0.976852, 0.22865));
993 p->push_back (PresetPoint (1, 0));
994 fade_out_presets->push_back (p);
996 // p = new Preset ("loout.xpm");
997 p = new Preset ("Fast start/cut", "crossfade_out_transition");
998 p->push_back (PresetPoint (0, 1));
999 p->push_back (PresetPoint (0.023041, 0.697222));
1000 p->push_back (PresetPoint (0.0553, 0.483333));
1001 p->push_back (PresetPoint (0.170507, 0.233333));
1002 p->push_back (PresetPoint (0.370968, 0.0861111));
1003 p->push_back (PresetPoint (0.610599, 0.0333333));
1004 p->push_back (PresetPoint (1, 0));
1005 fade_out_presets->push_back (p);
1007 // p = new Preset ("regout2.xpm");
1008 p = new Preset ("Slow Fade", "crossfade_out_slow-fade");
1009 p->push_back (PresetPoint (0, 1));
1010 p->push_back (PresetPoint (0.080645, 0.730556));
1011 p->push_back (PresetPoint (0.277778, 0.289256));
1012 p->push_back (PresetPoint (0.470046, 0.152778));
1013 p->push_back (PresetPoint (0.695853, 0.0694444));
1014 p->push_back (PresetPoint (1, 0));
1015 fade_out_presets->push_back (p);
1020 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1026 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1027 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1028 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1031 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1032 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1033 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1036 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1037 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1038 fade[Out].shading->hide();
1039 fade[In].shading->show();
1041 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1045 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1051 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1052 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1053 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1056 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1057 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1058 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1061 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1062 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1063 fade[In].shading->hide();
1064 fade[Out].shading->show();
1066 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1070 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1078 CrossfadeEditor::x_coordinate (double& xfract) const
1080 xfract = min (1.0, xfract);
1081 xfract = max (0.0, xfract);
1083 return canvas_border + (xfract * effective_width());
1087 CrossfadeEditor::y_coordinate (double& yfract) const
1089 yfract = min (1.0, yfract);
1090 yfract = max (0.0, yfract);
1092 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1096 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1099 uint32_t nchans = region->n_channels();
1104 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1106 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1109 ht = canvas->get_allocation().get_height() / (double) nchans;
1110 spu = xfade->length() / (double) effective_width();
1112 for (uint32_t n = 0; n < nchans; ++n) {
1114 gdouble yoff = n * ht;
1116 if (region->audio_source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1117 WaveView* waveview = new WaveView (*(canvas->root()));
1119 waveview->property_data_src() = region.get();
1120 waveview->property_cache_updater() = true;
1121 waveview->property_cache() = WaveView::create_cache();
1122 waveview->property_channel() = n;
1123 waveview->property_length_function() = (void*) region_length_from_c;
1124 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1125 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1126 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1127 waveview->property_gain_src() = &fade[which].gain_curve;
1128 waveview->property_x() = canvas_border;
1129 waveview->property_y() = yoff;
1130 waveview->property_height() = ht;
1131 waveview->property_samples_per_unit() = spu;
1132 waveview->property_amplitude_above_axis() = 2.0;
1133 waveview->property_wave_color() = color;
1134 waveview->property_fill_color() = color;
1137 waveview->property_region_start() = region->start();
1139 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1141 waveview->lower_to_bottom();
1142 fade[which].waves.push_back (waveview);
1146 toplevel->lower_to_bottom();
1150 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1152 /* this should never be called, because the peak files for an xfade
1153 will be ready by the time we want them. but our API forces us
1154 to provide this, so ..
1156 peaks_ready_connection.disconnect ();
1157 make_waves (r, which);
1161 CrossfadeEditor::audition (Audition which)
1163 AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1166 nframes_t left_start_offset;
1167 nframes_t right_length;
1168 nframes_t left_length;
1170 if (which != Right && preroll_button.get_active()) {
1171 preroll = session.frame_rate() * 2; //2 second hardcoded preroll for now
1176 if (which != Left && postroll_button.get_active()) {
1177 postroll = session.frame_rate() * 2; //2 second hardcoded postroll for now
1182 // Is there enough data for the whole preroll?
1183 left_length = xfade->length();
1184 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1185 left_start_offset -= preroll;
1187 preroll = left_start_offset;
1188 left_start_offset = 0;
1190 left_length += preroll;
1192 // Is there enough data for the whole postroll?
1193 right_length = xfade->length();
1194 if ((xfade->in()->length() - right_length) > postroll) {
1195 right_length += postroll;
1197 right_length = xfade->in()->length();
1200 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out",
1201 0, Region::DefaultFlags, false)));
1202 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, right_length, "xfade in",
1203 0, Region::DefaultFlags, false)));
1205 //apply a 20ms declicking fade at the start and end of auditioning
1206 left->set_fade_in_active(true);
1207 left->set_fade_in_length(session.frame_rate() / 50);
1208 right->set_fade_out_active(true);
1209 right->set_fade_out_length(session.frame_rate() / 50);
1211 pl.add_region (left, 0);
1212 pl.add_region (right, 1 + preroll);
1214 if (which == Left) {
1215 right->set_scale_amplitude (0.0);
1216 } else if (which == Right) {
1217 left->set_scale_amplitude (0.0);
1220 /* there is only one ... */
1221 pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1223 session.audition_playlist ();
1227 CrossfadeEditor::audition_both ()
1233 CrossfadeEditor::audition_left_dry ()
1235 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left",
1236 0, Region::DefaultFlags, false)));
1238 session.audition_region (left);
1242 CrossfadeEditor::audition_left ()
1248 CrossfadeEditor::audition_right_dry ()
1250 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in",
1251 0, Region::DefaultFlags, false)));
1252 session.audition_region (right);
1256 CrossfadeEditor::audition_right ()
1262 CrossfadeEditor::cancel_audition ()
1264 session.cancel_audition ();
1268 CrossfadeEditor::audition_toggled ()
1272 if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1283 CrossfadeEditor::audition_right_toggled ()
1287 if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1298 CrossfadeEditor::audition_right_dry_toggled ()
1302 if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1305 audition_right_dry ();
1313 CrossfadeEditor::audition_left_toggled ()
1317 if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1328 CrossfadeEditor::audition_left_dry_toggled ()
1332 if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1335 audition_left_dry ();
1343 CrossfadeEditor::on_key_press_event (GdkEventKey *ev)
1349 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1351 switch (ev->keyval) {
1353 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1354 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1356 audition_right_button.set_active (!audition_right_button.get_active());
1361 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1362 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1364 audition_left_button.set_active (!audition_left_button.get_active());
1369 if (session.is_auditioning()) {
1372 audition_both_button.set_active (!audition_both_button.get_active());