AU state handling, including changes to PathScanner so that it can now do recursive...
[ardour2.git] / gtk2_ardour / crossfade_edit.cc
blob99b11c584070fbc7fcf07b45fb9a73afe6ee8771
1 /*
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.
20 #include <cmath>
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_event.h>
31 #include <ardour/curve.h>
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"
46 #include "keyboard.h"
47 #include "utils.h"
48 #include "gui_thread.h"
49 #include "canvas_impl.h"
50 #include "simplerect.h"
51 #include "waveview.h"
52 #include "actions.h"
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57 using namespace Gtk;
58 using namespace sigc;
59 using namespace Editing;
61 #include "i18n.h"
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 ()
69 : line (0),
70 normative_curve (0.0, 1.0, 1.0, true),
71 gain_curve (0.0, 2.0, 1.0, true)
75 CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
76 : ArdourDialog (_("ardour: x-fade edit")),
77 xfade (xf),
78 session (s),
79 clear_button (_("Clear")),
80 revert_button (_("Reset")),
81 audition_both_button (_("Fade")),
82 audition_left_dry_button (_("Out (dry)")),
83 audition_left_button (_("Out")),
84 audition_right_dry_button (_("In (dry)")),
85 audition_right_button (_("In")),
87 preroll_button (_("With Pre-roll")),
88 postroll_button (_("With Post-roll")),
90 miny (my),
91 maxy (mxy),
93 fade_in_table (3, 3),
94 fade_out_table (3, 3),
96 select_in_button (_("Fade In")),
97 select_out_button (_("Fade Out"))
99 set_wmclass (X_("ardour_automationedit"), "Ardour");
100 set_name ("CrossfadeEditWindow");
101 set_position (Gtk::WIN_POS_MOUSE);
103 add_accel_group (ActionManager::ui_manager->get_accel_group());
105 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
107 RadioButtonGroup sel_but_group = select_in_button.get_group();
108 select_out_button.set_group (sel_but_group);
109 select_out_button.set_mode (false);
110 select_in_button.set_mode (false);
112 get_action_area()->set_layout(BUTTONBOX_SPREAD);
113 get_action_area()->pack_start(clear_button);
114 get_action_area()->pack_start(revert_button);
115 cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
116 ok_button = add_button ("OK", RESPONSE_ACCEPT);
118 if (fade_in_presets == 0) {
119 build_presets ();
122 point_grabbed = false;
123 toplevel = 0;
125 canvas = new ArdourCanvas::CanvasAA ();
126 canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation));
127 canvas->set_size_request (425, 200);
129 toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
130 toplevel->property_x1() = 0.0;
131 toplevel->property_y1() = 0.0;
132 toplevel->property_x2() = 10.0;
133 toplevel->property_y2() = 10.0;
134 toplevel->property_fill() = true;
135 toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
136 toplevel->property_outline_pixels() = 0;
137 toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
139 fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
140 fade[Out].line->property_width_pixels() = 1;
141 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
143 fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
144 fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
146 fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
147 fade[In].line->property_width_pixels() = 1;
148 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
150 fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
151 fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
153 fade[In].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
154 fade[In].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
155 fade[Out].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
156 fade[Out].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
158 select_in_button.set_name (X_("CrossfadeEditCurveButton"));
159 select_out_button.set_name (X_("CrossfadeEditCurveButton"));
161 select_in_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
162 select_out_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
164 HBox* acbox = manage (new HBox);
166 audition_box.set_border_width (7);
167 audition_box.set_spacing (5);
168 audition_box.set_homogeneous (false);
169 audition_box.pack_start (audition_left_dry_button, false, false);
170 audition_box.pack_start (audition_left_button, false, false);
171 audition_box.pack_start (audition_both_button, false, false);
172 audition_box.pack_start (audition_right_button, false, false);
173 audition_box.pack_start (audition_right_dry_button, false, false);
175 Frame* audition_frame = manage (new Frame (_("Audition")));
177 audition_frame->set_name (X_("CrossfadeEditFrame"));
178 audition_frame->add (audition_box);
180 acbox->pack_start (*audition_frame, true, false);
182 Frame* canvas_frame = manage (new Frame);
183 canvas_frame->add (*canvas);
184 canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
186 fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
187 fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
189 Image *pxmap;
190 Button* pbutton;
191 int row;
192 int col;
194 row = 1;
195 col = 0;
197 for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
199 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
200 pbutton = manage (new Button);
201 pbutton->add (*pxmap);
202 pbutton->set_name ("CrossfadeEditButton");
203 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
204 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
205 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
206 fade_in_buttons.push_back (pbutton);
208 col++;
210 if (col == 2) {
211 col = 0;
212 row++;
216 row = 1;
217 col = 0;
219 for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
221 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
222 pbutton = manage (new Button);
223 pbutton->add (*pxmap);
224 pbutton->set_name ("CrossfadeEditButton");
225 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
226 ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, "");
227 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
228 fade_out_buttons.push_back (pbutton);
230 col++;
232 if (col == 2) {
233 col = 0;
234 row++;
238 clear_button.set_name ("CrossfadeEditButton");
239 revert_button.set_name ("CrossfadeEditButton");
240 ok_button->set_name ("CrossfadeEditButton");
241 cancel_button->set_name ("CrossfadeEditButton");
242 preroll_button.set_name ("CrossfadeEditButton");
243 postroll_button.set_name ("CrossfadeEditButton");
244 audition_both_button.set_name ("CrossfadeEditAuditionButton");
245 audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
246 audition_left_button.set_name ("CrossfadeEditAuditionButton");
247 audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
248 audition_right_button.set_name ("CrossfadeEditAuditionButton");
250 clear_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear));
251 revert_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset));
252 audition_both_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled));
253 audition_right_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
254 audition_right_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
255 audition_left_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
256 audition_left_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
258 roll_box.pack_start (preroll_button, false, false);
259 roll_box.pack_start (postroll_button, false, false);
261 Gtk::HBox* rcenter_box = manage (new HBox);
262 rcenter_box->pack_start (roll_box, true, false);
264 VBox* vpacker2 = manage (new (VBox));
266 vpacker2->set_border_width (12);
267 vpacker2->set_spacing (7);
268 vpacker2->pack_start (*acbox, false, false);
269 vpacker2->pack_start (*rcenter_box, false, false);
271 curve_button_box.set_spacing (7);
272 curve_button_box.pack_start (fade_out_table, false, false, 12);
273 curve_button_box.pack_start (*vpacker2, false, false, 12);
274 curve_button_box.pack_start (fade_in_table, false, false, 12);
276 get_vbox()->pack_start (*canvas_frame, true, true);
277 get_vbox()->pack_start (curve_button_box, false, false);
279 /* button to allow hackers to check the actual curve values */
281 // Button* foobut = manage (new Button ("dump"));
282 // foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
283 // vpacker.pack_start (*foobut, false, false);
285 current = In;
286 set (xfade->fade_in(), In);
288 current = Out;
289 set (xfade->fade_out(), Out);
291 curve_select_clicked (In);
293 xfade->StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed));
295 session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed));
296 show_all_children();
299 CrossfadeEditor::~CrossfadeEditor()
301 /* most objects will be destroyed when the toplevel window is. */
303 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
304 delete *i;
307 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
308 delete *i;
312 void
313 CrossfadeEditor::dump ()
315 for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
316 cerr << (*i)->when << ' ' << (*i)->value << endl;
320 void
321 CrossfadeEditor::audition_state_changed (bool yn)
323 ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn));
325 if (!yn) {
326 audition_both_button.set_active (false);
327 audition_left_button.set_active (false);
328 audition_right_button.set_active (false);
329 audition_left_dry_button.set_active (false);
330 audition_right_dry_button.set_active (false);
334 void
335 CrossfadeEditor::set (const ARDOUR::Curve& curve, WhichFade which)
337 double firstx, endx;
338 ARDOUR::Curve::const_iterator the_end;
340 for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
341 delete *i;
344 fade[which].points.clear ();
345 fade[which].gain_curve.clear ();
346 fade[which].normative_curve.clear ();
348 if (curve.empty()) {
349 goto out;
352 the_end = curve.const_end();
353 --the_end;
355 firstx = (*curve.const_begin())->when;
356 endx = (*the_end)->when;
358 for (ARDOUR::Curve::const_iterator i = curve.const_begin(); i != curve.const_end(); ++i) {
360 double xfract = ((*i)->when - firstx) / (endx - firstx);
361 double yfract = ((*i)->value - miny) / (maxy - miny);
363 Point* p = make_point ();
365 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
366 xfract, yfract);
368 fade[which].points.push_back (p);
371 /* no need to sort because curve is already time-ordered */
373 out:
375 swap (which, current);
376 redraw ();
377 swap (which, current);
380 bool
381 CrossfadeEditor::curve_event (GdkEvent* event)
383 /* treat it like a toplevel event */
385 return canvas_event (event);
388 bool
389 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
392 if (point->curve != fade[current].line) {
393 return FALSE;
396 switch (event->type) {
397 case GDK_BUTTON_PRESS:
398 point_grabbed = true;
399 break;
400 case GDK_BUTTON_RELEASE:
401 point_grabbed = false;
403 if (Keyboard::is_delete_event (&event->button)) {
404 fade[current].points.remove (point);
405 delete point;
408 redraw ();
409 break;
411 case GDK_MOTION_NOTIFY:
412 if (point_grabbed) {
413 double new_x, new_y;
415 /* can't drag first or last points horizontally */
417 if (point == fade[current].points.front() || point == fade[current].points.back()) {
418 new_x = point->x;
419 } else {
420 new_x = (event->motion.x - canvas_border)/effective_width();
423 new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
424 point->move_to (x_coordinate (new_x), y_coordinate (new_y),
425 new_x, new_y);
426 redraw ();
428 break;
429 default:
430 break;
432 return TRUE;
435 bool
436 CrossfadeEditor::canvas_event (GdkEvent* event)
438 switch (event->type) {
439 case GDK_BUTTON_PRESS:
440 add_control_point ((event->button.x - canvas_border)/effective_width(),
441 1.0 - ((event->button.y - canvas_border)/effective_height()));
442 return TRUE;
443 break;
444 default:
445 break;
447 return FALSE;
450 CrossfadeEditor::Point::~Point()
452 delete box;
455 CrossfadeEditor::Point*
456 CrossfadeEditor::make_point ()
458 Point* p = new Point;
460 p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
461 p->box->property_fill() = true;
462 p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
463 p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
464 p->box->property_outline_pixels() = 1;
466 p->curve = fade[current].line;
468 p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p));
470 return p;
473 void
474 CrossfadeEditor::add_control_point (double x, double y)
476 PointSorter cmp;
478 /* enforce end point x location */
480 if (fade[current].points.empty()) {
481 x = 0.0;
482 } else if (fade[current].points.size() == 1) {
483 x = 1.0;
486 Point* p = make_point ();
488 p->move_to (x_coordinate (x), y_coordinate (y), x, y);
490 fade[current].points.push_back (p);
491 fade[current].points.sort (cmp);
493 redraw ();
496 void
497 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
499 const double half_size = rint(size/2.0);
500 double x1 = nx - half_size;
501 double x2 = nx + half_size;
503 box->property_x1() = x1;
504 box->property_x2() = x2;
506 box->property_y1() = ny - half_size;
507 box->property_y2() = ny + half_size;
509 x = xfract;
510 y = yfract;
513 void
514 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
516 if (toplevel) {
517 toplevel->property_x1() = 0.0;
518 toplevel->property_y1() = 0.0;
519 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
520 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
523 canvas->set_scroll_region (0.0, 0.0,
524 canvas->get_allocation().get_width(),
525 canvas->get_allocation().get_height());
527 Point* end = make_point ();
528 PointSorter cmp;
530 if (fade[In].points.size() > 1) {
531 Point* old_end = fade[In].points.back();
532 fade[In].points.pop_back ();
533 end->move_to (x_coordinate (old_end->x),
534 y_coordinate (old_end->y),
535 old_end->x, old_end->y);
536 delete old_end;
537 } else {
538 double x = 1.0;
539 double y = 0.5;
540 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
544 fade[In].points.push_back (end);
545 fade[In].points.sort (cmp);
547 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
548 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
549 (*i)->x, (*i)->y);
552 end = make_point ();
554 if (fade[Out].points.size() > 1) {
555 Point* old_end = fade[Out].points.back();
556 fade[Out].points.pop_back ();
557 end->move_to (x_coordinate (old_end->x),
558 y_coordinate (old_end->y),
559 old_end->x, old_end->y);
560 delete old_end;
561 } else {
562 double x = 1.0;
563 double y = 0.5;
564 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
568 fade[Out].points.push_back (end);
569 fade[Out].points.sort (cmp);
571 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
572 (*i)->move_to (x_coordinate ((*i)->x),
573 y_coordinate ((*i)->y),
574 (*i)->x, (*i)->y);
577 WhichFade old_current = current;
578 current = In;
579 redraw ();
580 current = Out;
581 redraw ();
582 current = old_current;
584 double spu = xfade->length() / (double) effective_width();
586 if (fade[In].waves.empty()) {
587 make_waves (xfade->in(), In);
590 if (fade[Out].waves.empty()) {
591 make_waves (xfade->out(), Out);
594 double ht;
595 vector<ArdourCanvas::WaveView*>::iterator i;
596 uint32_t n;
598 ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
600 for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
601 double yoff;
603 yoff = n * ht;
605 (*i)->property_y() = yoff;
606 (*i)->property_height() = ht;
607 (*i)->property_samples_per_unit() = spu;
610 ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
612 for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
613 double yoff;
615 yoff = n * ht;
617 (*i)->property_y() = yoff;
618 (*i)->property_height() = ht;
619 (*i)->property_samples_per_unit() = spu;
625 void
626 CrossfadeEditor::xfade_changed (Change ignored)
628 set (xfade->fade_in(), In);
629 set (xfade->fade_out(), Out);
632 void
633 CrossfadeEditor::redraw ()
635 if (canvas->get_allocation().get_width() < 2) {
636 return;
639 nframes_t len = xfade->length ();
641 fade[current].normative_curve.clear ();
642 fade[current].gain_curve.clear ();
644 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
645 fade[current].normative_curve.add ((*i)->x, (*i)->y);
646 double offset;
647 if (current==In)
648 offset = xfade->in()->start();
649 else
650 offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
651 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
655 size_t npoints = (size_t) effective_width();
656 float vec[npoints];
658 fade[current].normative_curve.get_vector (0, 1.0, vec, npoints);
660 ArdourCanvas::Points pts;
661 ArdourCanvas::Points spts;
663 while (pts.size() < npoints) {
664 pts.push_back (Gnome::Art::Point (0,0));
667 while (spts.size() < npoints + 3) {
668 spts.push_back (Gnome::Art::Point (0,0));
671 /* the shade coordinates *MUST* be in anti-clockwise order.
674 if (current == In) {
676 /* lower left */
678 spts[0].set_x (canvas_border);
679 spts[0].set_y (effective_height() + canvas_border);
681 /* lower right */
683 spts[1].set_x (effective_width() + canvas_border);
684 spts[1].set_y (effective_height() + canvas_border);
686 /* upper right */
688 spts[2].set_x (effective_width() + canvas_border);
689 spts[2].set_y (canvas_border);
692 } else {
694 /* upper left */
696 spts[0].set_x (canvas_border);
697 spts[0].set_y (canvas_border);
699 /* lower left */
701 spts[1].set_x (canvas_border);
702 spts[1].set_y (effective_height() + canvas_border);
704 /* lower right */
706 spts[2].set_x (effective_width() + canvas_border);
707 spts[2].set_y (effective_height() + canvas_border);
711 size_t last_spt = (npoints + 3) - 1;
713 for (size_t i = 0; i < npoints; ++i) {
715 double y = vec[i];
717 pts[i].set_x (canvas_border + i);
718 pts[i].set_y (y_coordinate (y));
720 spts[last_spt - i].set_x (canvas_border + i);
721 spts[last_spt - i].set_y (pts[i].get_y());
724 fade[current].line->property_points() = pts;
725 fade[current].shading->property_points() = spts;
727 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
728 (*i)->property_gain_src() = &fade[current].gain_curve;
732 void
733 CrossfadeEditor::apply_preset (Preset *preset)
736 WhichFade wf = find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
738 if (current != wf) {
740 if (wf == In) {
741 select_in_button.clicked();
742 } else {
743 select_out_button.clicked();
746 curve_select_clicked (wf);
749 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
750 delete *i;
753 fade[current].points.clear ();
755 for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
756 Point* p = make_point ();
757 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
758 (*i).x, (*i).y);
759 fade[current].points.push_back (p);
762 redraw ();
765 void
766 CrossfadeEditor::apply ()
768 _apply_to (xfade);
771 void
772 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
774 ARDOUR::Curve& in (xf->fade_in());
775 ARDOUR::Curve& out (xf->fade_out());
777 /* IN */
780 ARDOUR::Curve::const_iterator the_end = in.const_end();
781 --the_end;
783 double firstx = (*in.begin())->when;
784 double endx = (*the_end)->when;
785 double miny = in.get_min_y ();
786 double maxy = in.get_max_y ();
788 in.freeze ();
789 in.clear ();
791 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
793 double when = firstx + ((*i)->x * (endx - firstx));
794 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
795 in.add (when, value);
798 /* OUT */
800 the_end = out.const_end();
801 --the_end;
803 firstx = (*out.begin())->when;
804 endx = (*the_end)->when;
805 miny = out.get_min_y ();
806 maxy = out.get_max_y ();
808 out.freeze ();
809 out.clear ();
811 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
813 double when = firstx + ((*i)->x * (endx - firstx));
814 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
815 out.add (when, value);
818 in.thaw ();
819 out.thaw ();
822 void
823 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
825 _apply_to (xfade);
826 xfade->set_active (true);
827 xfade->fade_in().solve ();
828 xfade->fade_out().solve ();
831 void
832 CrossfadeEditor::clear ()
834 for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
835 delete *i;
838 fade[current].points.clear ();
840 redraw ();
843 void
844 CrossfadeEditor::reset ()
846 set (xfade->fade_in(), In);
847 set (xfade->fade_out(), Out);
849 curve_select_clicked (current);
852 void
853 CrossfadeEditor::build_presets ()
855 Preset* p;
857 fade_in_presets = new Presets;
858 fade_out_presets = new Presets;
860 /* FADE OUT */
862 p = new Preset ("Linear (-6dB)", "crossfade_in_dipped");
863 p->push_back (PresetPoint (0, 0));
864 p->push_back (PresetPoint (0.000000, 0.000000));
865 p->push_back (PresetPoint (0.166667, 0.166366));
866 p->push_back (PresetPoint (0.333333, 0.332853));
867 p->push_back (PresetPoint (0.500000, 0.499459));
868 p->push_back (PresetPoint (0.666667, 0.666186));
869 p->push_back (PresetPoint (0.833333, 0.833033));
870 p->push_back (PresetPoint (1.000000, 1.000000));
871 fade_in_presets->push_back (p);
873 p = new Preset ("S(1)-curve", "crossfade_in_default");
874 p->push_back (PresetPoint (0, 0));
875 p->push_back (PresetPoint (0.1, 0.01));
876 p->push_back (PresetPoint (0.2, 0.03));
877 p->push_back (PresetPoint (0.8, 0.97));
878 p->push_back (PresetPoint (0.9, 0.99));
879 p->push_back (PresetPoint (1, 1));
880 fade_in_presets->push_back (p);
882 p = new Preset ("S(2)-curve", "crossfade_in_default");
883 p->push_back (PresetPoint (0.0, 0.0));
884 p->push_back (PresetPoint (0.055, 0.222));
885 p->push_back (PresetPoint (0.163, 0.35));
886 p->push_back (PresetPoint (0.837, 0.678));
887 p->push_back (PresetPoint (0.945, 0.783));
888 p->push_back (PresetPoint (1.0, 1.0));
889 fade_in_presets->push_back (p);
891 p = new Preset ("Constant Power (-3dB)", "crossfade_in_constant");
893 p->push_back (PresetPoint (0.000000, 0.000000));
894 p->push_back (PresetPoint (0.166667, 0.282192));
895 p->push_back (PresetPoint (0.333333, 0.518174));
896 p->push_back (PresetPoint (0.500000, 0.707946));
897 p->push_back (PresetPoint (0.666667, 0.851507));
898 p->push_back (PresetPoint (0.833333, 0.948859));
899 p->push_back (PresetPoint (1.000000, 1.000000));
901 fade_in_presets->push_back (p);
903 if (!Profile->get_sae()) {
904 // p = new Preset ("hiin.xpm");
905 p = new Preset ("Long cut", "crossfade_in_fast-cut");
906 p->push_back (PresetPoint (0, 0));
907 p->push_back (PresetPoint (0.0207373, 0.197222));
908 p->push_back (PresetPoint (0.0645161, 0.525));
909 p->push_back (PresetPoint (0.152074, 0.802778));
910 p->push_back (PresetPoint (0.276498, 0.919444));
911 p->push_back (PresetPoint (0.481567, 0.980556));
912 p->push_back (PresetPoint (0.767281, 1));
913 p->push_back (PresetPoint (1, 1));
914 fade_in_presets->push_back (p);
916 // p = new Preset ("loin.xpm");
917 p = new Preset ("Short cut", "crossfade_in_transition");
918 p->push_back (PresetPoint (0, 0));
919 p->push_back (PresetPoint (0.389401, 0.0333333));
920 p->push_back (PresetPoint (0.629032, 0.0861111));
921 p->push_back (PresetPoint (0.829493, 0.233333));
922 p->push_back (PresetPoint (0.9447, 0.483333));
923 p->push_back (PresetPoint (0.976959, 0.697222));
924 p->push_back (PresetPoint (1, 1));
925 fade_in_presets->push_back (p);
928 // p = new Preset ("regin2.xpm");
929 p = new Preset ("Slow cut", "crossfade_in_slow-cut");
930 p->push_back (PresetPoint (0, 0));
931 p->push_back (PresetPoint (0.304147, 0.0694444));
932 p->push_back (PresetPoint (0.529954, 0.152778));
933 p->push_back (PresetPoint (0.725806, 0.333333));
934 p->push_back (PresetPoint (0.847926, 0.558333));
935 p->push_back (PresetPoint (0.919355, 0.730556));
936 p->push_back (PresetPoint (1, 1));
937 fade_in_presets->push_back (p);
940 /* FADE OUT */
942 // p = new Preset ("regout.xpm");
943 p = new Preset ("Linear (-6dB cut)", "crossfade_out_dipped");
944 p->push_back (PresetPoint (0, 1));
945 p->push_back (PresetPoint (0.000000, 1.000000));
946 p->push_back (PresetPoint (0.166667, 0.833033));
947 p->push_back (PresetPoint (0.333333, 0.666186));
948 p->push_back (PresetPoint (0.500000, 0.499459));
949 p->push_back (PresetPoint (0.666667, 0.332853));
950 p->push_back (PresetPoint (0.833333, 0.166366));
951 p->push_back (PresetPoint (1.000000, 0.000000));
952 fade_out_presets->push_back (p);
954 p = new Preset ("S(1)-Curve", "crossfade_out_default");
955 p->push_back (PresetPoint (0, 1));
956 p->push_back (PresetPoint (0.1, 0.99));
957 p->push_back (PresetPoint (0.2, 0.97));
958 p->push_back (PresetPoint (0.8, 0.03));
959 p->push_back (PresetPoint (0.9, 0.01));
960 p->push_back (PresetPoint (1, 0));
961 fade_out_presets->push_back (p);
963 p = new Preset ("S(2)-Curve", "crossfade_out_default");
964 p->push_back (PresetPoint (0.0, 1.0));
965 p->push_back (PresetPoint (0.163, 0.678));
966 p->push_back (PresetPoint (0.055, 0.783));
967 p->push_back (PresetPoint (0.837, 0.35));
968 p->push_back (PresetPoint (0.945, 0.222));
969 p->push_back (PresetPoint (1.0, 0.0));
970 fade_out_presets->push_back (p);
972 // p = new Preset ("linout.xpm");
973 p = new Preset ("Constant Power (-3dB cut)", "crossfade_out_constant");
974 p->push_back (PresetPoint (0.000000, 1.000000));
975 p->push_back (PresetPoint (0.166667, 0.948859));
976 p->push_back (PresetPoint (0.333333, 0.851507));
977 p->push_back (PresetPoint (0.500000, 0.707946));
978 p->push_back (PresetPoint (0.666667, 0.518174));
979 p->push_back (PresetPoint (0.833333, 0.282192));
980 p->push_back (PresetPoint (1.000000, 0.000000));
981 fade_out_presets->push_back (p);
983 if (!Profile->get_sae()) {
984 // p = new Preset ("hiout.xpm");
985 p = new Preset ("Slow end/cut", "crossfade_out_fast-cut");
986 p->push_back (PresetPoint (0, 1));
987 p->push_back (PresetPoint (0.305556, 1));
988 p->push_back (PresetPoint (0.548611, 0.991736));
989 p->push_back (PresetPoint (0.759259, 0.931129));
990 p->push_back (PresetPoint (0.918981, 0.68595));
991 p->push_back (PresetPoint (0.976852, 0.22865));
992 p->push_back (PresetPoint (1, 0));
993 fade_out_presets->push_back (p);
995 // p = new Preset ("loout.xpm");
996 p = new Preset ("Fast start/cut", "crossfade_out_transition");
997 p->push_back (PresetPoint (0, 1));
998 p->push_back (PresetPoint (0.023041, 0.697222));
999 p->push_back (PresetPoint (0.0553, 0.483333));
1000 p->push_back (PresetPoint (0.170507, 0.233333));
1001 p->push_back (PresetPoint (0.370968, 0.0861111));
1002 p->push_back (PresetPoint (0.610599, 0.0333333));
1003 p->push_back (PresetPoint (1, 0));
1004 fade_out_presets->push_back (p);
1006 // p = new Preset ("regout2.xpm");
1007 p = new Preset ("Slow Fade", "crossfade_out_slow-fade");
1008 p->push_back (PresetPoint (0, 1));
1009 p->push_back (PresetPoint (0.080645, 0.730556));
1010 p->push_back (PresetPoint (0.277778, 0.289256));
1011 p->push_back (PresetPoint (0.470046, 0.152778));
1012 p->push_back (PresetPoint (0.695853, 0.0694444));
1013 p->push_back (PresetPoint (1, 0));
1014 fade_out_presets->push_back (p);
1018 void
1019 CrossfadeEditor::curve_select_clicked (WhichFade wf)
1021 current = wf;
1023 if (wf == In) {
1025 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1026 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1027 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1030 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1031 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1032 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1035 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1036 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1037 fade[Out].shading->hide();
1038 fade[In].shading->show();
1040 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1041 (*i)->box->hide();
1044 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1045 (*i)->box->show ();
1048 } else {
1050 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1051 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1052 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1055 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1056 (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1057 (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1060 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1061 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1062 fade[In].shading->hide();
1063 fade[Out].shading->show();
1065 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1066 (*i)->box->hide();
1069 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1070 (*i)->box->show();
1076 double
1077 CrossfadeEditor::x_coordinate (double& xfract) const
1079 xfract = min (1.0, xfract);
1080 xfract = max (0.0, xfract);
1082 return canvas_border + (xfract * effective_width());
1085 double
1086 CrossfadeEditor::y_coordinate (double& yfract) const
1088 yfract = min (1.0, yfract);
1089 yfract = max (0.0, yfract);
1091 return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1094 void
1095 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1097 gdouble ht;
1098 uint32_t nchans = region->n_channels();
1099 guint32 color;
1100 double spu;
1102 if (which == In) {
1103 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1104 } else {
1105 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1108 ht = canvas->get_allocation().get_height() / (double) nchans;
1109 spu = xfade->length() / (double) effective_width();
1111 for (uint32_t n = 0; n < nchans; ++n) {
1113 gdouble yoff = n * ht;
1115 if (region->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;
1136 if (which==In)
1137 waveview->property_region_start() = region->start();
1138 else
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();
1149 void
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);
1160 void
1161 CrossfadeEditor::audition (Audition which)
1163 AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1164 nframes_t preroll;
1165 nframes_t postroll;
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
1172 } else {
1173 preroll = 0;
1176 if (which != Left && postroll_button.get_active()) {
1177 postroll = session.frame_rate() * 2; //2 second hardcoded postroll for now
1178 } else {
1179 postroll = 0;
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;
1186 } else {
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;
1196 } else {
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 ();
1226 void
1227 CrossfadeEditor::audition_both ()
1229 audition (Both);
1232 void
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);
1241 void
1242 CrossfadeEditor::audition_left ()
1244 audition (Left);
1247 void
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);
1255 void
1256 CrossfadeEditor::audition_right ()
1258 audition (Right);
1261 void
1262 CrossfadeEditor::cancel_audition ()
1264 session.cancel_audition ();
1267 void
1268 CrossfadeEditor::audition_toggled ()
1270 bool x;
1272 if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1274 if (x) {
1275 audition_both ();
1276 } else {
1277 cancel_audition ();
1282 void
1283 CrossfadeEditor::audition_right_toggled ()
1285 bool x;
1287 if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1289 if (x) {
1290 audition_right ();
1291 } else {
1292 cancel_audition ();
1297 void
1298 CrossfadeEditor::audition_right_dry_toggled ()
1300 bool x;
1302 if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1304 if (x) {
1305 audition_right_dry ();
1306 } else {
1307 cancel_audition ();
1312 void
1313 CrossfadeEditor::audition_left_toggled ()
1315 bool x;
1317 if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1319 if (x) {
1320 audition_left ();
1321 } else {
1322 cancel_audition ();
1327 void
1328 CrossfadeEditor::audition_left_dry_toggled ()
1330 bool x;
1332 if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1334 if (x) {
1335 audition_left_dry ();
1336 } else {
1337 cancel_audition ();
1342 bool
1343 CrossfadeEditor::on_key_press_event (GdkEventKey *ev)
1345 return true;
1348 bool
1349 CrossfadeEditor::on_key_release_event (GdkEventKey* ev)
1351 switch (ev->keyval) {
1352 case GDK_Right:
1353 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1354 audition_right_dry_button.set_active (!audition_right_dry_button.get_active());
1355 } else {
1356 audition_right_button.set_active (!audition_right_button.get_active());
1358 break;
1360 case GDK_Left:
1361 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1362 audition_left_dry_button.set_active (!audition_left_dry_button.get_active());
1363 } else {
1364 audition_left_button.set_active (!audition_left_button.get_active());
1366 break;
1368 case GDK_space:
1369 if (session.is_auditioning()) {
1370 cancel_audition ();
1371 } else {
1372 audition_both_button.set_active (!audition_both_button.get_active());
1374 break;
1376 default:
1377 break;
1380 return true;