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>
40 #include <gtkmm2ext/gtk_ui.h>
42 #include "ardour_ui.h"
43 #include "crossfade_edit.h"
44 #include "rgb_macros.h"
47 #include "gui_thread.h"
48 #include "canvas_impl.h"
49 #include "simplerect.h"
53 using namespace ARDOUR;
57 using namespace Editing;
61 const int32_t CrossfadeEditor::Point::size = 7;
62 const double CrossfadeEditor::canvas_border = 10;
63 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
64 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
66 CrossfadeEditor::Half::Half ()
68 //normative_curve (Evoral::Parameter(GainAutomation, 0.0, 1.0, 1.0)), // FIXME: GainAutomation?
69 normative_curve (Evoral::Parameter(GainAutomation)),
70 gain_curve (Evoral::Parameter(GainAutomation))
74 CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
75 : ArdourDialog (_("ardour: x-fade edit")),
78 clear_button (_("Clear")),
79 revert_button (_("Reset")),
80 audition_both_button (_("Fade")),
81 audition_left_dry_button (_("Out (dry)")),
82 audition_left_button (_("Out")),
83 audition_right_dry_button (_("In (dry)")),
84 audition_right_button (_("In")),
86 preroll_button (_("With Pre-roll")),
87 postroll_button (_("With Post-roll")),
93 fade_out_table (3, 3),
95 select_in_button (_("Fade In")),
96 select_out_button (_("Fade Out"))
98 set_wmclass (X_("ardour_automationedit"), "Ardour");
99 set_name ("CrossfadeEditWindow");
100 set_position (Gtk::WIN_POS_MOUSE);
102 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
104 RadioButtonGroup sel_but_group = select_in_button.get_group();
105 select_out_button.set_group (sel_but_group);
106 select_out_button.set_mode (false);
107 select_in_button.set_mode (false);
109 get_action_area()->set_layout(BUTTONBOX_SPREAD);
110 get_action_area()->pack_start(clear_button);
111 get_action_area()->pack_start(revert_button);
112 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
113 ok_button = add_button ("OK", RESPONSE_ACCEPT);
115 if (fade_in_presets == 0) {
119 point_grabbed = false;
122 canvas = new ArdourCanvas::CanvasAA ();
123 canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation));
124 canvas->set_size_request (425, 200);
126 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
127 toplevel->property_x1() = 0.0;
128 toplevel->property_y1() = 0.0;
129 toplevel->property_x2() = 10.0;
130 toplevel->property_y2() = 10.0;
131 toplevel->property_fill() = true;
132 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
133 toplevel->property_outline_pixels() = 0;
134 toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
136 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
137 fade[Out].line->property_width_pixels() = 1;
138 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
140 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
141 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
143 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
144 fade[In].line->property_width_pixels() = 1;
145 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
147 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
148 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
150 fade[In].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
151 fade[In].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
152 fade[Out].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
153 fade[Out].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
155 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
156 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
158 select_in_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
159 select_out_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
161 HBox* acbox = manage (new HBox);
163 audition_box.set_border_width (7);
164 audition_box.set_spacing (5);
165 audition_box.set_homogeneous (false);
166 audition_box.pack_start (audition_left_dry_button, false, false);
167 audition_box.pack_start (audition_left_button, false, false);
168 audition_box.pack_start (audition_both_button, false, false);
169 audition_box.pack_start (audition_right_button, false, false);
170 audition_box.pack_start (audition_right_dry_button, false, false);
172 Frame* audition_frame = manage (new Frame (_("Audition")));
174 audition_frame->set_name (X_("CrossfadeEditFrame"));
175 audition_frame->add (audition_box);
177 acbox->pack_start (*audition_frame, true, false);
179 Frame* canvas_frame = manage (new Frame);
180 canvas_frame->add (*canvas);
181 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
183 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
184 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
194 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
196 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
197 pbutton = manage (new Button);
198 pbutton->add (*pxmap);
199 pbutton->set_name ("CrossfadeEditButton");
200 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
201 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
202 fade_in_buttons.push_back (pbutton);
215 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
217 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
218 pbutton = manage (new Button);
219 pbutton->add (*pxmap);
220 pbutton->set_name ("CrossfadeEditButton");
221 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
222 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
223 fade_out_buttons.push_back (pbutton);
233 clear_button.set_name ("CrossfadeEditButton");
234 revert_button.set_name ("CrossfadeEditButton");
235 ok_button->set_name ("CrossfadeEditButton");
236 cancel_button->set_name ("CrossfadeEditButton");
237 preroll_button.set_name ("CrossfadeEditButton");
238 postroll_button.set_name ("CrossfadeEditButton");
239 audition_both_button.set_name ("CrossfadeEditAuditionButton");
240 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
241 audition_left_button.set_name ("CrossfadeEditAuditionButton");
242 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
243 audition_right_button.set_name ("CrossfadeEditAuditionButton");
245 clear_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear));
246 revert_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset));
247 audition_both_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled));
248 audition_right_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
249 audition_right_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
250 audition_left_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
251 audition_left_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
253 roll_box.pack_start (preroll_button, false, false);
254 roll_box.pack_start (postroll_button, false, false);
256 Gtk::HBox* rcenter_box = manage (new HBox);
257 rcenter_box->pack_start (roll_box, true, false);
259 VBox* vpacker2 = manage (new (VBox));
261 vpacker2->set_border_width (12);
262 vpacker2->set_spacing (7);
263 vpacker2->pack_start (*acbox, false, false);
264 vpacker2->pack_start (*rcenter_box, false, false);
266 curve_button_box.set_spacing (7);
267 curve_button_box.pack_start (fade_out_table, false, false, 12);
268 curve_button_box.pack_start (*vpacker2, false, false, 12);
269 curve_button_box.pack_start (fade_in_table, false, false, 12);
271 get_vbox()->pack_start (*canvas_frame, true, true);
272 get_vbox()->pack_start (curve_button_box, false, false);
274 /* button to allow hackers to check the actual curve values */
276 // Button* foobut = manage (new Button ("dump"));
277 // foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
278 // vpacker.pack_start (*foobut, false, false);
281 set (xfade->fade_in(), In);
284 set (xfade->fade_out(), Out);
286 curve_select_clicked (In);
288 xfade->StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed));
290 session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed));
294 CrossfadeEditor::~CrossfadeEditor()
296 /* most objects will be destroyed when the toplevel window is. */
298 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
302 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
308 CrossfadeEditor::dump ()
310 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
311 cerr << (*i)->when << ' ' << (*i)->value << endl;
316 CrossfadeEditor::audition_state_changed (bool yn)
318 ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn));
321 audition_both_button.set_active (false);
322 audition_left_button.set_active (false);
323 audition_right_button.set_active (false);
324 audition_left_dry_button.set_active (false);
325 audition_right_dry_button.set_active (false);
330 CrossfadeEditor::set (const ARDOUR::AutomationList& curve, WhichFade which)
333 ARDOUR::AutomationList::const_iterator the_end;
335 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
339 fade[which].points.clear ();
340 fade[which].gain_curve.clear ();
341 fade[which].normative_curve.clear ();
347 the_end = curve.end();
350 firstx = (*curve.begin())->when;
351 endx = (*the_end)->when;
353 for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.end(); ++i) {
355 double xfract = ((*i)->when - firstx) / (endx - firstx);
356 double yfract = ((*i)->value - miny) / (maxy - miny);
358 Point* p = make_point ();
360 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
363 fade[which].points.push_back (p);
366 /* no need to sort because curve is already time-ordered */
370 swap (which, current);
372 swap (which, current);
376 CrossfadeEditor::curve_event (GdkEvent* event)
378 /* treat it like a toplevel event */
380 return canvas_event (event);
384 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
387 if (point->curve != fade[current].line) {
391 switch (event->type) {
392 case GDK_BUTTON_PRESS:
393 point_grabbed = true;
395 case GDK_BUTTON_RELEASE:
396 point_grabbed = false;
398 if (Keyboard::is_delete_event (&event->button)) {
399 fade[current].points.remove (point);
406 case GDK_MOTION_NOTIFY:
410 /* can't drag first or last points horizontally */
412 if (point == fade[current].points.front() || point == fade[current].points.back()) {
415 new_x = (event->motion.x - canvas_border)/effective_width();
418 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
419 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
431 CrossfadeEditor::canvas_event (GdkEvent* event)
433 switch (event->type) {
434 case GDK_BUTTON_PRESS:
435 add_control_point ((event->button.x - canvas_border)/effective_width(),
436 1.0 - ((event->button.y - canvas_border)/effective_height()));
445 CrossfadeEditor::Point::~Point()
450 CrossfadeEditor::Point*
451 CrossfadeEditor::make_point ()
453 Point* p = new Point;
455 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
456 p->box->property_fill() = true;
457 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
458 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
459 p->box->property_outline_pixels() = 1;
461 p->curve = fade[current].line;
463 p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p));
469 CrossfadeEditor::add_control_point (double x, double y)
473 /* enforce end point x location */
475 if (fade[current].points.empty()) {
477 } else if (fade[current].points.size() == 1) {
481 Point* p = make_point ();
483 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
485 fade[current].points.push_back (p);
486 fade[current].points.sort (cmp);
492 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
494 const double half_size = rint(size/2.0);
495 double x1 = nx - half_size;
496 double x2 = nx + half_size;
498 box->property_x1() = x1;
499 box->property_x2() = x2;
501 box->property_y1() = ny - half_size;
502 box->property_y2() = ny + half_size;
509 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
512 toplevel->property_x1() = 0.0;
513 toplevel->property_y1() = 0.0;
514 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
515 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
518 canvas->set_scroll_region (0.0, 0.0,
519 canvas->get_allocation().get_width(),
520 canvas->get_allocation().get_height());
522 Point* end = make_point ();
525 if (fade[In].points.size() > 1) {
526 Point* old_end = fade[In].points.back();
527 fade[In].points.pop_back ();
528 end->move_to (x_coordinate (old_end->x),
529 y_coordinate (old_end->y),
530 old_end->x, old_end->y);
535 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
539 fade[In].points.push_back (end);
540 fade[In].points.sort (cmp);
542 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
543 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
549 if (fade[Out].points.size() > 1) {
550 Point* old_end = fade[Out].points.back();
551 fade[Out].points.pop_back ();
552 end->move_to (x_coordinate (old_end->x),
553 y_coordinate (old_end->y),
554 old_end->x, old_end->y);
559 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
563 fade[Out].points.push_back (end);
564 fade[Out].points.sort (cmp);
566 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
567 (*i)->move_to (x_coordinate ((*i)->x),
568 y_coordinate ((*i)->y),
572 WhichFade old_current = current;
577 current = old_current;
579 double spu = xfade->length() / (double) effective_width();
581 if (fade[In].waves.empty()) {
582 make_waves (xfade->in(), In);
585 if (fade[Out].waves.empty()) {
586 make_waves (xfade->out(), Out);
590 vector<ArdourCanvas::WaveView*>::iterator i;
593 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
595 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
600 (*i)->property_y() = yoff;
601 (*i)->property_height() = ht;
602 (*i)->property_samples_per_unit() = spu;
605 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
607 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
612 (*i)->property_y() = yoff;
613 (*i)->property_height() = ht;
614 (*i)->property_samples_per_unit() = spu;
621 CrossfadeEditor::xfade_changed (Change ignored)
623 set (xfade->fade_in(), In);
624 set (xfade->fade_out(), Out);
628 CrossfadeEditor::redraw ()
630 if (canvas->get_allocation().get_width() < 2) {
634 nframes_t len = xfade->length ();
636 fade[current].normative_curve.clear ();
637 fade[current].gain_curve.clear ();
639 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
640 fade[current].normative_curve.add ((*i)->x, (*i)->y);
643 offset = xfade->in()->start();
645 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
646 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
650 size_t npoints = (size_t) effective_width();
653 fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
655 ArdourCanvas::Points pts;
656 ArdourCanvas::Points spts;
658 while (pts.size() < npoints) {
659 pts.push_back (Gnome::Art::Point (0,0));
662 while (spts.size() < npoints + 3) {
663 spts.push_back (Gnome::Art::Point (0,0));
666 /* the shade coordinates *MUST* be in anti-clockwise order.
673 spts[0].set_x (canvas_border);
674 spts[0].set_y (effective_height() + canvas_border);
678 spts[1].set_x (effective_width() + canvas_border);
679 spts[1].set_y (effective_height() + canvas_border);
683 spts[2].set_x (effective_width() + canvas_border);
684 spts[2].set_y (canvas_border);
691 spts[0].set_x (canvas_border);
692 spts[0].set_y (canvas_border);
696 spts[1].set_x (canvas_border);
697 spts[1].set_y (effective_height() + canvas_border);
701 spts[2].set_x (effective_width() + canvas_border);
702 spts[2].set_y (effective_height() + canvas_border);
706 size_t last_spt = (npoints + 3) - 1;
708 for (size_t i = 0; i < npoints; ++i) {
712 pts[i].set_x (canvas_border + i);
713 pts[i].set_y (y_coordinate (y));
715 spts[last_spt - i].set_x (canvas_border + i);
716 spts[last_spt - i].set_y (pts[i].get_y());
719 fade[current].line->property_points() = pts;
720 fade[current].shading->property_points() = spts;
722 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
723 (*i)->property_gain_src() = &fade[current].gain_curve;
728 CrossfadeEditor::apply_preset (Preset *preset)
731 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
736 select_in_button.clicked();
738 select_out_button.clicked();
741 curve_select_clicked (wf);
744 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
748 fade[current].points.clear ();
750 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
751 Point* p = make_point ();
752 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
754 fade[current].points.push_back (p);
761 CrossfadeEditor::apply ()
767 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
769 ARDOUR::AutomationList& in (xf->fade_in());
770 ARDOUR::AutomationList& out (xf->fade_out());
775 ARDOUR::AutomationList::const_iterator the_end = in.end();
778 double firstx = (*in.begin())->when;
779 double endx = (*the_end)->when;
780 double miny = in.get_min_y ();
781 double maxy = in.get_max_y ();
786 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
788 double when = firstx + ((*i)->x * (endx - firstx));
789 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
790 in.add (when, value);
798 firstx = (*out.begin())->when;
799 endx = (*the_end)->when;
800 miny = out.get_min_y ();
801 maxy = out.get_max_y ();
806 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
808 double when = firstx + ((*i)->x * (endx - firstx));
809 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
810 out.add (when, value);
818 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
821 xfade->set_active (true);
822 xfade->fade_in().curve().solve ();
823 xfade->fade_out().curve().solve ();
827 CrossfadeEditor::clear ()
829 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
833 fade[current].points.clear ();
839 CrossfadeEditor::reset ()
841 set (xfade->fade_in(), In);
842 set (xfade->fade_out(), Out);
844 curve_select_clicked (current);
848 CrossfadeEditor::build_presets ()
852 fade_in_presets = new Presets;
853 fade_out_presets = new Presets;
856 // p = new Preset ("hiin.xpm");
857 p = new Preset ("crossfade_in_fast-cut");
858 p->push_back (PresetPoint (0, 0));
859 p->push_back (PresetPoint (0.0207373, 0.197222));
860 p->push_back (PresetPoint (0.0645161, 0.525));
861 p->push_back (PresetPoint (0.152074, 0.802778));
862 p->push_back (PresetPoint (0.276498, 0.919444));
863 p->push_back (PresetPoint (0.481567, 0.980556));
864 p->push_back (PresetPoint (0.767281, 1));
865 p->push_back (PresetPoint (1, 1));
866 fade_in_presets->push_back (p);
868 // p = new Preset ("loin.xpm");
869 p = new Preset ("crossfade_in_transition");
870 p->push_back (PresetPoint (0, 0));
871 p->push_back (PresetPoint (0.389401, 0.0333333));
872 p->push_back (PresetPoint (0.629032, 0.0861111));
873 p->push_back (PresetPoint (0.829493, 0.233333));
874 p->push_back (PresetPoint (0.9447, 0.483333));
875 p->push_back (PresetPoint (0.976959, 0.697222));
876 p->push_back (PresetPoint (1, 1));
877 fade_in_presets->push_back (p);
879 // p = new Preset ("regin.xpm");
880 p = new Preset ("crossfade_in_constant");
881 p->push_back (PresetPoint (0, 0));
882 p->push_back (PresetPoint (0.0737327, 0.308333));
883 p->push_back (PresetPoint (0.246544, 0.658333));
884 p->push_back (PresetPoint (0.470046, 0.886111));
885 p->push_back (PresetPoint (0.652074, 0.972222));
886 p->push_back (PresetPoint (0.771889, 0.988889));
887 p->push_back (PresetPoint (1, 1));
888 fade_in_presets->push_back (p);
890 // p = new Preset ("regin2.xpm");
891 p = new Preset ("crossfade_in_slow-cut");
892 p->push_back (PresetPoint (0, 0));
893 p->push_back (PresetPoint (0.304147, 0.0694444));
894 p->push_back (PresetPoint (0.529954, 0.152778));
895 p->push_back (PresetPoint (0.725806, 0.333333));
896 p->push_back (PresetPoint (0.847926, 0.558333));
897 p->push_back (PresetPoint (0.919355, 0.730556));
898 p->push_back (PresetPoint (1, 1));
899 fade_in_presets->push_back (p);
901 // p = new Preset ("linin.xpm");
902 p = new Preset ("crossfade_in_dipped");
903 p->push_back (PresetPoint (0, 0));
904 p->push_back (PresetPoint (1, 1));
905 fade_in_presets->push_back (p);
907 p = new Preset ("crossfade_in_default");
908 p->push_back (PresetPoint (0, 0));
909 p->push_back (PresetPoint (0.1, 0.01));
910 p->push_back (PresetPoint (0.2, 0.03));
911 p->push_back (PresetPoint (0.8, 0.97));
912 p->push_back (PresetPoint (0.9, 0.99));
913 p->push_back (PresetPoint (1, 1));
914 fade_in_presets->push_back (p);
918 // p = new Preset ("hiout.xpm");
919 p = new Preset ("crossfade_out_fast-cut");
920 p->push_back (PresetPoint (0, 1));
921 p->push_back (PresetPoint (0.305556, 1));
922 p->push_back (PresetPoint (0.548611, 0.991736));
923 p->push_back (PresetPoint (0.759259, 0.931129));
924 p->push_back (PresetPoint (0.918981, 0.68595));
925 p->push_back (PresetPoint (0.976852, 0.22865));
926 p->push_back (PresetPoint (1, 0));
927 fade_out_presets->push_back (p);
929 // p = new Preset ("loout.xpm");
930 p = new Preset ("crossfade_out_transition");
931 p->push_back (PresetPoint (0, 1));
932 p->push_back (PresetPoint (0.023041, 0.697222));
933 p->push_back (PresetPoint (0.0553, 0.483333));
934 p->push_back (PresetPoint (0.170507, 0.233333));
935 p->push_back (PresetPoint (0.370968, 0.0861111));
936 p->push_back (PresetPoint (0.610599, 0.0333333));
937 p->push_back (PresetPoint (1, 0));
938 fade_out_presets->push_back (p);
940 // p = new Preset ("regout.xpm");
941 p = new Preset ("crossfade_out_constant");
942 p->push_back (PresetPoint (0, 1));
943 p->push_back (PresetPoint (0.228111, 0.988889));
944 p->push_back (PresetPoint (0.347926, 0.972222));
945 p->push_back (PresetPoint (0.529954, 0.886111));
946 p->push_back (PresetPoint (0.753456, 0.658333));
947 p->push_back (PresetPoint (0.9262673, 0.308333));
948 p->push_back (PresetPoint (1, 0));
949 fade_out_presets->push_back (p);
951 // p = new Preset ("regout2.xpm");
952 p = new Preset ("crossfade_out_slow-fade");
953 p->push_back (PresetPoint (0, 1));
954 p->push_back (PresetPoint (0.080645, 0.730556));
955 p->push_back (PresetPoint (0.277778, 0.289256));
956 p->push_back (PresetPoint (0.470046, 0.152778));
957 p->push_back (PresetPoint (0.695853, 0.0694444));
958 p->push_back (PresetPoint (1, 0));
959 fade_out_presets->push_back (p);
961 // p = new Preset ("linout.xpm");
962 p = new Preset ("crossfade_out_dipped");
963 p->push_back (PresetPoint (0, 1));
964 p->push_back (PresetPoint (1, 0));
965 fade_out_presets->push_back (p);
967 p = new Preset ("crossfade_out_default");
968 p->push_back (PresetPoint (0, 1));
969 p->push_back (PresetPoint (0.1, 0.99));
970 p->push_back (PresetPoint (0.2, 0.97));
971 p->push_back (PresetPoint (0.8, 0.03));
972 p->push_back (PresetPoint (0.9, 0.01));
973 p->push_back (PresetPoint (1, 0));
974 fade_out_presets->push_back (p);
978 CrossfadeEditor::curve_select_clicked (WhichFade wf)
984 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
985 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
986 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
989 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
990 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
991 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
994 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
995 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
996 fade[Out].shading->hide();
997 fade[In].shading->show();
999 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1003 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1009 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1010 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1011 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1014 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1015 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1016 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1019 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1020 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1021 fade[In].shading->hide();
1022 fade[Out].shading->show();
1024 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1028 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1036 CrossfadeEditor::x_coordinate (double& xfract) const
1038 xfract = min (1.0, xfract);
1039 xfract = max (0.0, xfract);
1041 return canvas_border + (xfract * effective_width());
1045 CrossfadeEditor::y_coordinate (double& yfract) const
1047 yfract = min (1.0, yfract);
1048 yfract = max (0.0, yfract);
1050 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1054 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1057 uint32_t nchans = region->n_channels();
1062 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1064 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1067 ht = canvas->get_allocation().get_height() / (double) nchans;
1068 spu = xfade->length() / (double) effective_width();
1070 for (uint32_t n = 0; n < nchans; ++n) {
1072 gdouble yoff = n * ht;
1074 if (region->audio_source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1075 WaveView* waveview = new WaveView (*(canvas->root()));
1077 waveview->property_data_src() = region.get();
1078 waveview->property_cache_updater() = true;
1079 waveview->property_cache() = WaveView::create_cache();
1080 waveview->property_channel() = n;
1081 waveview->property_length_function() = (void*) region_length_from_c;
1082 waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1083 waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1084 waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1085 waveview->property_gain_src() = &fade[which].gain_curve;
1086 waveview->property_x() = canvas_border;
1087 waveview->property_y() = yoff;
1088 waveview->property_height() = ht;
1089 waveview->property_samples_per_unit() = spu;
1090 waveview->property_amplitude_above_axis() = 2.0;
1091 waveview->property_wave_color() = color;
1092 waveview->property_fill_color() = color;
1095 waveview->property_region_start() = region->start();
1097 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1099 waveview->lower_to_bottom();
1100 fade[which].waves.push_back (waveview);
1104 toplevel->lower_to_bottom();
1108 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1110 /* this should never be called, because the peak files for an xfade
1111 will be ready by the time we want them. but our API forces us
1112 to provide this, so ..
1114 peaks_ready_connection.disconnect ();
1115 make_waves (r, which);
1119 CrossfadeEditor::audition (Audition which)
1121 AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1124 nframes_t left_start_offset;
1125 nframes_t right_length;
1126 nframes_t left_length;
1128 if (which != Right && preroll_button.get_active()) {
1129 preroll = session.frame_rate() * 2; //2 second hardcoded preroll for now
1134 if (which != Left && postroll_button.get_active()) {
1135 postroll = session.frame_rate() * 2; //2 second hardcoded postroll for now
1140 // Is there enough data for the whole preroll?
1141 left_length = xfade->length();
1142 if ((left_start_offset = xfade->out()->length() - xfade->length()) > preroll) {
1143 left_start_offset -= preroll;
1145 preroll = left_start_offset;
1146 left_start_offset = 0;
1148 left_length += preroll;
1150 // Is there enough data for the whole postroll?
1151 right_length = xfade->length();
1152 if ((xfade->in()->length() - right_length) > postroll) {
1153 right_length += postroll;
1155 right_length = xfade->in()->length();
1158 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out",
1159 0, Region::DefaultFlags, false)));
1160 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, right_length, "xfade in",
1161 0, Region::DefaultFlags, false)));
1163 //apply a 20ms declicking fade at the start and end of auditioning
1164 left->set_fade_in_active(true);
1165 left->set_fade_in_length(session.frame_rate() / 50);
1166 right->set_fade_out_active(true);
1167 right->set_fade_out_length(session.frame_rate() / 50);
1169 pl.add_region (left, 0);
1170 pl.add_region (right, 1 + preroll);
1172 if (which == Left) {
1173 right->set_scale_amplitude (0.0);
1174 } else if (which == Right) {
1175 left->set_scale_amplitude (0.0);
1178 /* there is only one ... */
1179 pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1181 session.audition_playlist ();
1185 CrossfadeEditor::audition_both ()
1191 CrossfadeEditor::audition_left_dry ()
1193 boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left",
1194 0, Region::DefaultFlags, false)));
1196 session.audition_region (left);
1200 CrossfadeEditor::audition_left ()
1206 CrossfadeEditor::audition_right_dry ()
1208 boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in",
1209 0, Region::DefaultFlags, false)));
1210 session.audition_region (right);
1214 CrossfadeEditor::audition_right ()
1220 CrossfadeEditor::cancel_audition ()
1222 session.cancel_audition ();
1226 CrossfadeEditor::audition_toggled ()
1230 if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1241 CrossfadeEditor::audition_right_toggled ()
1245 if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1256 CrossfadeEditor::audition_right_dry_toggled ()
1260 if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1263 audition_right_dry ();
1271 CrossfadeEditor::audition_left_toggled ()
1275 if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1286 CrossfadeEditor::audition_left_dry_toggled ()
1290 if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1293 audition_left_dry ();