Major Theme Manager changes, see ardour-dev
[ardour.git] / gtk2_ardour / crossfade_edit.cc
1 /*
2     Copyright (C) 2004 Paul Davis 
3
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.
8
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.
13
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.
17
18 */
19
20 #include <cmath>
21
22 #include <sigc++/bind.h>
23
24 #include <gtkmm/frame.h>
25 #include <gtkmm/image.h>
26 #include <gtkmm/scrolledwindow.h>
27
28 #include <libgnomecanvasmm/line.h>
29
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
40 #include <gtkmm2ext/gtk_ui.h>
41
42 #include "ardour_ui.h"
43 #include "crossfade_edit.h"
44 #include "rgb_macros.h"
45 #include "keyboard.h"
46 #include "utils.h"
47 #include "gui_thread.h"
48 #include "canvas_impl.h"
49 #include "simplerect.h"
50 #include "waveview.h"
51 #include "color.h"
52
53 using namespace std;
54 using namespace ARDOUR;
55 using namespace PBD;
56 using namespace Gtk;
57 using namespace sigc;
58 using namespace Editing;
59
60 #include "i18n.h"
61
62 const int32_t CrossfadeEditor::Point::size = 7;
63 const double CrossfadeEditor::canvas_border = 10;
64 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
65 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
66
67 CrossfadeEditor::Half::Half ()
68         : line (0), 
69           normative_curve (0.0, 1.0, 1.0, true),
70           gain_curve (0.0, 2.0, 1.0, true)
71 {
72 }
73
74 CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
75         : ArdourDialog (_("ardour: x-fade edit")),
76           xfade (xf),
77           session (s),
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")),
85
86           preroll_button (_("With Pre-roll")),
87           postroll_button (_("With Post-roll")),
88           
89           miny (my),
90           maxy (mxy),
91
92           fade_in_table (3, 3),
93           fade_out_table (3, 3),
94
95           select_in_button (_("Fade In")),
96           select_out_button (_("Fade Out"))
97 {
98         set_wmclass (X_("ardour_automationedit"), "Ardour");
99         set_name ("CrossfadeEditWindow");
100         set_position (Gtk::WIN_POS_MOUSE);
101
102         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
103
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);
108
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);
114
115         if (fade_in_presets == 0) {
116                 build_presets ();
117         }
118
119         point_grabbed = false;
120         toplevel = 0;
121
122         canvas = new ArdourCanvas::CanvasAA ();
123         canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation));
124         canvas->set_size_request (425, 200);
125         
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() = Config->canvasvar_CrossfadeEditorBase.get();
133         toplevel->property_outline_pixels() =  0;
134         toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
135         
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() = Config->canvasvar_CrossfadeEditorLine.get();
139                 
140         fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
141         fade[Out].shading->property_fill_color_rgba() = Config->canvasvar_CrossfadeEditorLineShading.get();
142
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() = Config->canvasvar_CrossfadeEditorLine.get();
146                 
147         fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
148         fade[In].shading->property_fill_color_rgba() = Config->canvasvar_CrossfadeEditorLineShading.get();
149         
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));
154
155         select_in_button.set_name (X_("CrossfadeEditCurveButton"));
156         select_out_button.set_name (X_("CrossfadeEditCurveButton"));
157
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));
160
161         HBox* acbox = manage (new HBox);
162         
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);
171
172         Frame* audition_frame = manage (new Frame (_("Audition")));
173         
174         audition_frame->set_name (X_("CrossfadeEditFrame"));
175         audition_frame->add (audition_box);
176
177         acbox->pack_start (*audition_frame, true, false);
178
179         Frame* canvas_frame = manage (new Frame);
180         canvas_frame->add (*canvas);
181         canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
182
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);
185
186         Image *pxmap;
187         Button* pbutton;
188         int row;
189         int col;
190
191         row = 1;
192         col = 0;
193
194         for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
195
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);
203
204                 col++;
205
206                 if (col == 2) {
207                         col = 0;
208                         row++;
209                 }
210         }
211
212         row = 1;
213         col = 0;
214
215         for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
216
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);
224
225                 col++;
226
227                 if (col == 2) {
228                         col = 0;
229                         row++;
230                 }
231         }
232
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");
244
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));
252
253         roll_box.pack_start (preroll_button, false, false);
254         roll_box.pack_start (postroll_button, false, false);
255
256         Gtk::HBox* rcenter_box = manage (new HBox);
257         rcenter_box->pack_start (roll_box, true, false);
258
259         VBox* vpacker2 = manage (new (VBox));
260
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);
265
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);
270         
271         get_vbox()->pack_start (*canvas_frame, true, true);
272         get_vbox()->pack_start (curve_button_box, false, false);
273
274         /* button to allow hackers to check the actual curve values */
275
276 //      Button* foobut = manage (new Button ("dump"));
277 //      foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
278 //      vpacker.pack_start (*foobut, false, false);
279
280         current = In;
281         set (xfade->fade_in(), In);
282
283         current = Out;
284         set (xfade->fade_out(), Out);
285
286         curve_select_clicked (In);
287
288         xfade->StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed));
289
290         session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed));
291         show_all_children();
292 }
293
294 CrossfadeEditor::~CrossfadeEditor()
295 {
296         /* most objects will be destroyed when the toplevel window is. */
297
298         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
299                 delete *i;
300         }
301
302         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
303                 delete *i;
304         }
305 }
306
307 void
308 CrossfadeEditor::dump ()
309 {
310         for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
311                 cerr << (*i)->when << ' ' << (*i)->value << endl;
312         }
313 }
314
315 void
316 CrossfadeEditor::audition_state_changed (bool yn)
317 {
318         ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn));
319
320         if (!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);
326         }
327 }
328
329 void
330 CrossfadeEditor::set (const ARDOUR::Curve& curve, WhichFade which)
331 {
332         double firstx, endx;
333         ARDOUR::Curve::const_iterator the_end;
334
335         for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
336                         delete *i;
337         }
338         
339         fade[which].points.clear ();
340         fade[which].gain_curve.clear ();
341         fade[which].normative_curve.clear ();
342
343         if (curve.empty()) {
344                 goto out;
345         }
346         
347         the_end = curve.const_end();
348         --the_end;
349         
350         firstx = (*curve.const_begin())->when;
351         endx = (*the_end)->when;
352
353         for (ARDOUR::Curve::const_iterator i = curve.const_begin(); i != curve.const_end(); ++i) {
354                 
355                 double xfract = ((*i)->when - firstx) / (endx - firstx);
356                 double yfract = ((*i)->value - miny) / (maxy - miny);
357                 
358                 Point* p = make_point ();
359
360                 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
361                             xfract, yfract);
362                 
363                 fade[which].points.push_back (p);
364         }
365
366         /* no need to sort because curve is already time-ordered */
367
368   out:
369         
370         swap (which, current);
371         redraw ();
372         swap (which, current);
373 }
374
375 bool
376 CrossfadeEditor::curve_event (GdkEvent* event)
377 {
378         /* treat it like a toplevel event */
379
380         return canvas_event (event);
381 }
382
383 bool
384 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
385 {
386
387         if (point->curve != fade[current].line) {
388                 return FALSE;
389         }
390
391         switch (event->type) {
392         case GDK_BUTTON_PRESS:
393                 point_grabbed = true;
394                 break;
395         case GDK_BUTTON_RELEASE:
396                 point_grabbed = false;
397
398                 if (Keyboard::is_delete_event (&event->button)) {
399                         fade[current].points.remove (point);
400                         delete point;
401                 }
402
403                 redraw ();
404                 break;
405
406         case GDK_MOTION_NOTIFY:
407                 if (point_grabbed) {
408                         double new_x, new_y;
409
410                         /* can't drag first or last points horizontally */
411
412                         if (point == fade[current].points.front() || point == fade[current].points.back()) {
413                                 new_x = point->x;
414                         } else {
415                                 new_x = (event->motion.x - canvas_border)/effective_width();
416                         }
417
418                         new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
419                         point->move_to (x_coordinate (new_x), y_coordinate (new_y), 
420                                         new_x, new_y);
421                         redraw ();
422                 }
423                 break;
424         default:
425                 break;
426         }
427         return TRUE;
428 }
429
430 bool
431 CrossfadeEditor::canvas_event (GdkEvent* event)
432 {
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()));
437                 return TRUE;
438                 break;
439         default:
440                 break;
441         }
442         return FALSE;
443 }
444
445 CrossfadeEditor::Point::~Point()
446 {
447         delete box;
448 }
449
450 CrossfadeEditor::Point*
451 CrossfadeEditor::make_point ()
452 {
453         Point* p = new Point;
454
455         p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
456         p->box->property_fill() = true;
457         p->box->property_fill_color_rgba() = Config->canvasvar_CrossfadeEditorPointFill.get();
458         p->box->property_outline_color_rgba() = Config->canvasvar_CrossfadeEditorPointOutline.get();
459         p->box->property_outline_pixels() = 1;
460
461         p->curve = fade[current].line;
462
463         p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p));
464         
465         return p;
466 }
467
468 void
469 CrossfadeEditor::add_control_point (double x, double y)
470 {
471         PointSorter cmp;
472
473         /* enforce end point x location */
474         
475         if (fade[current].points.empty()) {
476                 x = 0.0;
477         } else if (fade[current].points.size() == 1) {
478                 x = 1.0;
479         } 
480
481         Point* p = make_point ();
482
483         p->move_to (x_coordinate (x), y_coordinate (y), x, y);
484
485         fade[current].points.push_back (p);
486         fade[current].points.sort (cmp);
487
488         redraw ();
489 }
490
491 void
492 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
493 {
494         const double half_size = rint(size/2.0);
495         double x1 = nx - half_size;
496         double x2 = nx + half_size;
497
498         box->property_x1() = x1;
499         box->property_x2() = x2;
500
501         box->property_y1() = ny - half_size;
502         box->property_y2() = ny + half_size;
503
504         x = xfract;
505         y = yfract;
506 }
507
508 void
509 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
510 {
511         if (toplevel) {
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;
516         }
517         
518         canvas->set_scroll_region (0.0, 0.0, 
519                                    canvas->get_allocation().get_width(), 
520                                    canvas->get_allocation().get_height());
521
522         Point* end = make_point ();
523         PointSorter cmp;
524
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);
531                 delete old_end;
532         } else {
533                 double x = 1.0;
534                 double y = 0.5;
535                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
536
537         }
538
539         fade[In].points.push_back (end);
540         fade[In].points.sort (cmp);
541
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),
544                                (*i)->x, (*i)->y);
545         }
546         
547         end = make_point ();
548         
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);
555                 delete old_end;
556         } else {
557                 double x = 1.0;
558                 double y = 0.5;
559                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
560
561         }
562
563         fade[Out].points.push_back (end);
564         fade[Out].points.sort (cmp);
565
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),
569                                (*i)->x, (*i)->y);
570         }
571         
572         WhichFade old_current = current;
573         current = In;
574         redraw ();
575         current = Out;
576         redraw ();
577         current = old_current;
578
579         double spu = xfade->length() / (double) effective_width();
580
581         if (fade[In].waves.empty()) {
582                 make_waves (xfade->in(), In);
583         }
584
585         if (fade[Out].waves.empty()) {
586                 make_waves (xfade->out(), Out);
587         }
588
589         double ht;
590         vector<ArdourCanvas::WaveView*>::iterator i;
591         uint32_t n;
592
593         ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
594
595         for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
596                 double yoff;
597
598                 yoff = n * ht;
599
600                 (*i)->property_y() = yoff;
601                 (*i)->property_height() = ht;
602                 (*i)->property_samples_per_unit() = spu;
603         }
604
605         ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
606
607         for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
608                 double yoff;
609
610                 yoff = n * ht;
611
612                 (*i)->property_y() = yoff;
613                 (*i)->property_height() = ht;
614                 (*i)->property_samples_per_unit() = spu;
615         }
616
617 }
618
619
620 void
621 CrossfadeEditor::xfade_changed (Change ignored)
622 {
623         set (xfade->fade_in(), In);
624         set (xfade->fade_out(), Out);
625 }
626
627 void
628 CrossfadeEditor::redraw ()
629 {
630         if (canvas->get_allocation().get_width() < 2) {
631                 return;
632         }
633
634         nframes_t len = xfade->length ();
635
636         fade[current].normative_curve.clear ();
637         fade[current].gain_curve.clear ();
638
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);
641                 fade[current].gain_curve.add (((*i)->x * len), (*i)->y);
642         }
643
644         size_t npoints = (size_t) effective_width();
645         float vec[npoints];
646
647         fade[current].normative_curve.get_vector (0, 1.0, vec, npoints);
648         
649         ArdourCanvas::Points pts;
650         ArdourCanvas::Points spts;
651
652         while (pts.size() < npoints) {
653                 pts.push_back (Gnome::Art::Point (0,0));
654         }
655
656         while (spts.size() < npoints + 3) {
657                 spts.push_back (Gnome::Art::Point (0,0));
658         }
659
660         /* the shade coordinates *MUST* be in anti-clockwise order.
661          */
662
663         if (current == In) {
664
665                 /* lower left */
666
667                 spts[0].set_x (canvas_border);
668                 spts[0].set_y (effective_height() + canvas_border);
669
670                 /* lower right */
671
672                 spts[1].set_x (effective_width() + canvas_border);
673                 spts[1].set_y (effective_height() + canvas_border);
674
675                 /* upper right */
676
677                 spts[2].set_x (effective_width() + canvas_border);
678                 spts[2].set_y (canvas_border);
679
680                 
681         } else {
682
683                 /*  upper left */
684                 
685                 spts[0].set_x (canvas_border);
686                 spts[0].set_y (canvas_border);
687
688                 /* lower left */
689
690                 spts[1].set_x (canvas_border);
691                 spts[1].set_y (effective_height() + canvas_border);
692
693                 /* lower right */
694
695                 spts[2].set_x (effective_width() + canvas_border);
696                 spts[2].set_y (effective_height() + canvas_border);
697
698         }
699
700         size_t last_spt = (npoints + 3) - 1;
701
702         for (size_t i = 0; i < npoints; ++i) {
703
704                 double y = vec[i];
705                 
706                 pts[i].set_x (canvas_border + i);
707                 pts[i].set_y  (y_coordinate (y));
708
709                 spts[last_spt - i].set_x (canvas_border + i);
710                 spts[last_spt - i].set_y (pts[i].get_y());
711         }
712
713         fade[current].line->property_points() = pts;
714         fade[current].shading->property_points() = spts;
715
716         for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
717                 (*i)->property_gain_src() = &fade[current].gain_curve;
718         }
719 }
720
721 void
722 CrossfadeEditor::apply_preset (Preset *preset)
723 {
724   
725         WhichFade wf =  find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
726         
727         if (current != wf) {
728           
729                 if (wf == In) {
730                         select_in_button.clicked();
731                 } else {
732                         select_out_button.clicked();
733                 }
734                 
735                 curve_select_clicked (wf);
736         }  
737         
738         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
739                 delete *i;
740         }
741
742         fade[current].points.clear ();
743
744         for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
745                 Point* p = make_point ();
746                 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
747                             (*i).x, (*i).y);
748                 fade[current].points.push_back (p);
749         }
750
751         redraw ();
752 }
753
754 void
755 CrossfadeEditor::apply ()
756 {
757         _apply_to (xfade);
758 }
759
760 void
761 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
762 {
763         ARDOUR::Curve& in (xf->fade_in());
764         ARDOUR::Curve& out (xf->fade_out());
765
766         /* IN */
767
768
769         ARDOUR::Curve::const_iterator the_end = in.const_end();
770         --the_end;
771
772         double firstx = (*in.begin())->when;
773         double endx = (*the_end)->when;
774         double miny = in.get_min_y ();
775         double maxy = in.get_max_y ();
776
777         in.freeze ();
778         in.clear ();
779
780         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
781
782                 double when = firstx + ((*i)->x * (endx - firstx));
783                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
784                 in.add (when, value);
785         }
786
787         /* OUT */
788
789         the_end = out.const_end();
790         --the_end;
791
792         firstx = (*out.begin())->when;
793         endx = (*the_end)->when;
794         miny = out.get_min_y ();
795         maxy = out.get_max_y ();
796
797         out.freeze ();
798         out.clear ();
799
800         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
801
802                 double when = firstx + ((*i)->x * (endx - firstx));
803                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
804                 out.add (when, value);
805         }
806
807         in.thaw ();
808         out.thaw ();
809 }
810
811 void
812 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
813 {
814         _apply_to (xfade);
815         xfade->set_active (true);
816         xfade->fade_in().solve ();
817         xfade->fade_out().solve ();
818 }
819
820 void
821 CrossfadeEditor::clear ()
822 {
823         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
824                 delete *i;
825         }
826
827         fade[current].points.clear ();
828
829         redraw ();
830 }
831
832 void
833 CrossfadeEditor::reset ()
834 {
835         set (xfade->fade_in(),  In);
836         set (xfade->fade_out(), Out);
837
838         curve_select_clicked (current);
839 }
840
841 void
842 CrossfadeEditor::build_presets ()
843 {
844         Preset* p;
845
846         fade_in_presets = new Presets;
847         fade_out_presets = new Presets;
848
849         /* FADE OUT */
850         // p = new Preset ("hiin.xpm");
851         p = new Preset ("crossfade_in_fast-cut");
852         p->push_back (PresetPoint (0, 0));
853         p->push_back (PresetPoint (0.0207373, 0.197222));
854         p->push_back (PresetPoint (0.0645161, 0.525));
855         p->push_back (PresetPoint (0.152074, 0.802778));
856         p->push_back (PresetPoint (0.276498, 0.919444));
857         p->push_back (PresetPoint (0.481567, 0.980556));
858         p->push_back (PresetPoint (0.767281, 1));
859         p->push_back (PresetPoint (1, 1));
860         fade_in_presets->push_back (p);
861         
862         // p = new Preset ("loin.xpm");
863         p = new Preset ("crossfade_in_transition");
864         p->push_back (PresetPoint (0, 0));
865         p->push_back (PresetPoint (0.389401, 0.0333333));
866         p->push_back (PresetPoint (0.629032, 0.0861111));
867         p->push_back (PresetPoint (0.829493, 0.233333));
868         p->push_back (PresetPoint (0.9447, 0.483333));
869         p->push_back (PresetPoint (0.976959, 0.697222));
870         p->push_back (PresetPoint (1, 1));
871         fade_in_presets->push_back (p);
872
873         // p = new Preset ("regin.xpm");
874         p = new Preset ("crossfade_in_constant");
875         p->push_back (PresetPoint (0, 0));
876         p->push_back (PresetPoint (0.0737327, 0.308333));
877         p->push_back (PresetPoint (0.246544, 0.658333));
878         p->push_back (PresetPoint (0.470046, 0.886111));
879         p->push_back (PresetPoint (0.652074, 0.972222));
880         p->push_back (PresetPoint (0.771889, 0.988889));
881         p->push_back (PresetPoint (1, 1));
882         fade_in_presets->push_back (p);
883
884         // p = new Preset ("regin2.xpm");
885         p = new Preset ("crossfade_in_slow-cut");
886         p->push_back (PresetPoint (0, 0));
887         p->push_back (PresetPoint (0.304147, 0.0694444));
888         p->push_back (PresetPoint (0.529954, 0.152778));
889         p->push_back (PresetPoint (0.725806, 0.333333));
890         p->push_back (PresetPoint (0.847926, 0.558333));
891         p->push_back (PresetPoint (0.919355, 0.730556));
892         p->push_back (PresetPoint (1, 1));
893         fade_in_presets->push_back (p);
894
895         // p = new Preset ("linin.xpm");
896         p = new Preset ("crossfade_in_dipped");
897         p->push_back (PresetPoint (0, 0));
898         p->push_back (PresetPoint (1, 1));
899         fade_in_presets->push_back (p);
900
901         p = new Preset ("crossfade_in_default");
902         p->push_back (PresetPoint (0, 0));
903         p->push_back (PresetPoint (0.1, 0.01));
904         p->push_back (PresetPoint (0.2, 0.03));
905         p->push_back (PresetPoint (0.8, 0.97));
906         p->push_back (PresetPoint (0.9, 0.99));
907         p->push_back (PresetPoint (1, 1));
908         fade_in_presets->push_back (p);
909         
910         /* FADE OUT */
911
912         // p = new Preset ("hiout.xpm");
913         p = new Preset ("crossfade_out_fast-cut");
914         p->push_back (PresetPoint (0, 1));
915         p->push_back (PresetPoint (0.305556, 1));
916         p->push_back (PresetPoint (0.548611, 0.991736));
917         p->push_back (PresetPoint (0.759259, 0.931129));
918         p->push_back (PresetPoint (0.918981, 0.68595));
919         p->push_back (PresetPoint (0.976852, 0.22865));
920         p->push_back (PresetPoint (1, 0));
921         fade_out_presets->push_back (p);
922         
923         // p = new Preset ("regout.xpm");
924         p = new Preset ("crossfade_out_constant");
925         p->push_back (PresetPoint (0, 1));
926         p->push_back (PresetPoint (0.228111, 0.988889));
927         p->push_back (PresetPoint (0.347926, 0.972222));
928         p->push_back (PresetPoint (0.529954, 0.886111));
929         p->push_back (PresetPoint (0.753456, 0.658333));
930         p->push_back (PresetPoint (0.9262673, 0.308333));
931         p->push_back (PresetPoint (1, 0));
932         fade_out_presets->push_back (p);
933
934         // p = new Preset ("loout.xpm");
935         p = new Preset ("crossfade_out_transition");
936         p->push_back (PresetPoint (0, 1));
937         p->push_back (PresetPoint (0.023041, 0.697222));
938         p->push_back (PresetPoint (0.0553,   0.483333));
939         p->push_back (PresetPoint (0.170507, 0.233333));
940         p->push_back (PresetPoint (0.370968, 0.0861111));
941         p->push_back (PresetPoint (0.610599, 0.0333333));
942         p->push_back (PresetPoint (1, 0));
943         fade_out_presets->push_back (p);
944
945         // p = new Preset ("regout2.xpm");
946         p = new Preset ("crossfade_out_slow-fade");
947         p->push_back (PresetPoint (0, 1));
948         p->push_back (PresetPoint (0.080645, 0.730556));
949         p->push_back (PresetPoint (0.277778, 0.289256));
950         p->push_back (PresetPoint (0.470046, 0.152778));
951         p->push_back (PresetPoint (0.695853, 0.0694444));
952         p->push_back (PresetPoint (1, 0));
953         fade_out_presets->push_back (p);
954
955         // p = new Preset ("linout.xpm");
956         p = new Preset ("crossfade_out_dipped");
957         p->push_back (PresetPoint (0, 1));
958         p->push_back (PresetPoint (1, 0));
959         fade_out_presets->push_back (p);
960         
961         p = new Preset ("crossfade_out_default");
962         p->push_back (PresetPoint (0, 1));
963         p->push_back (PresetPoint (0.1, 0.99));
964         p->push_back (PresetPoint (0.2, 0.97));
965         p->push_back (PresetPoint (0.8, 0.03));
966         p->push_back (PresetPoint (0.9, 0.01));
967         p->push_back (PresetPoint (1, 0));
968         fade_out_presets->push_back (p);
969 }
970
971 void
972 CrossfadeEditor::curve_select_clicked (WhichFade wf)
973 {
974         current = wf;
975         
976         if (wf == In) {
977                 
978                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
979                         (*i)->property_wave_color() = Config->canvasvar_SelectedCrossfadeEditorWave.get();
980                 }
981
982                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
983                         (*i)->property_wave_color() = Config->canvasvar_CrossfadeEditorWave.get();
984                 }
985
986                 fade[In].line->property_fill_color_rgba() = Config->canvasvar_SelectedCrossfadeEditorLine.get();
987                 fade[Out].line->property_fill_color_rgba() = Config->canvasvar_CrossfadeEditorLine.get();
988                 fade[Out].shading->hide();
989                 fade[In].shading->show();
990
991                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
992                         (*i)->box->hide();
993                 }
994
995                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
996                         (*i)->box->show ();
997                 }
998
999         } else {
1000
1001                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1002                         (*i)->property_wave_color() = Config->canvasvar_CrossfadeEditorWave.get();
1003                 }
1004
1005                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1006                         (*i)->property_wave_color() = Config->canvasvar_SelectedCrossfadeEditorWave.get();
1007                 }
1008
1009                 fade[Out].line->property_fill_color_rgba() = Config->canvasvar_SelectedCrossfadeEditorLine.get();
1010                 fade[In].line->property_fill_color_rgba() = Config->canvasvar_CrossfadeEditorLine.get();
1011                 fade[In].shading->hide();
1012                 fade[Out].shading->show();
1013
1014                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1015                         (*i)->box->hide();
1016                 }
1017                 
1018                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1019                         (*i)->box->show();
1020                 }
1021
1022         }
1023 }
1024
1025 double 
1026 CrossfadeEditor::x_coordinate (double& xfract) const
1027 {
1028         xfract = min (1.0, xfract);
1029         xfract = max (0.0, xfract);
1030     
1031         return canvas_border + (xfract * effective_width());
1032 }
1033
1034 double
1035 CrossfadeEditor::y_coordinate (double& yfract) const
1036 {
1037         yfract = min (1.0, yfract);
1038         yfract = max (0.0, yfract);
1039
1040         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1041 }
1042
1043 void
1044 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1045 {
1046         gdouble ht;
1047         uint32_t nchans = region->n_channels();
1048         guint32 color;
1049         double spu;
1050
1051         if (which == In) {
1052                 color = Config->canvasvar_SelectedCrossfadeEditorWave.get();
1053         } else {
1054                 color = Config->canvasvar_CrossfadeEditorWave.get();
1055         }
1056
1057         ht = canvas->get_allocation().get_height() / (double) nchans;
1058         spu = xfade->length() / (double) effective_width();
1059
1060         for (uint32_t n = 0; n < nchans; ++n) {
1061                 
1062                 gdouble yoff = n * ht;
1063                 
1064                 if (region->audio_source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1065                         WaveView* waveview = new WaveView (*(canvas->root()));
1066
1067                         waveview->property_data_src() = region.get();
1068                         waveview->property_cache_updater() =  true;
1069                         waveview->property_cache() = WaveView::create_cache();
1070                         waveview->property_channel() = n;
1071                         waveview->property_length_function() = (void*) region_length_from_c;
1072                         waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1073                         waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1074                         waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1075                         waveview->property_gain_src() = &fade[which].gain_curve;
1076                         waveview->property_x() = canvas_border;
1077                         waveview->property_y() = yoff;
1078                         waveview->property_height() = ht;
1079                         waveview->property_samples_per_unit() = spu;
1080                         waveview->property_amplitude_above_axis() = 2.0;
1081                         waveview->property_wave_color() = color;
1082                         
1083                         waveview->lower_to_bottom();
1084                         fade[which].waves.push_back (waveview);
1085                 }
1086         }
1087
1088         toplevel->lower_to_bottom();
1089 }
1090
1091 void
1092 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1093 {
1094         /* this should never be called, because the peak files for an xfade
1095            will be ready by the time we want them. but our API forces us
1096            to provide this, so ..
1097         */
1098         peaks_ready_connection.disconnect ();
1099         make_waves (r, which);
1100 }
1101
1102 void
1103 CrossfadeEditor::audition_both ()
1104 {
1105         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1106         nframes_t preroll;
1107         nframes_t postroll;
1108         nframes_t length;
1109         nframes_t left_start_offset;
1110         nframes_t right_length;
1111         nframes_t left_length;
1112
1113         if (preroll_button.get_active()) {
1114                 preroll = ARDOUR_UI::instance()->preroll_clock.current_duration ();
1115         } else {
1116                 preroll = 0;
1117         }
1118
1119         if (postroll_button.get_active()) {
1120                 postroll = ARDOUR_UI::instance()->postroll_clock.current_duration ();
1121         } else {
1122                 postroll = 0;
1123         }
1124
1125         if ((left_start_offset = xfade->out()->length() - xfade->length()) >= preroll) {
1126                 left_start_offset -= preroll;
1127         } 
1128
1129         length = 0;
1130
1131         if ((left_length = xfade->length()) < xfade->out()->length() - left_start_offset) {
1132                 length += postroll;
1133         }
1134
1135         right_length = xfade->length();
1136
1137         if (xfade->in()->length() - right_length < postroll) {
1138                 right_length += postroll;
1139         }
1140
1141         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out", 
1142                                                                                                               0, Region::DefaultFlags, false)));
1143         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, right_length, "xfade in", 
1144                                                                                                                0, Region::DefaultFlags, false)));
1145         
1146         pl.add_region (left, 0);
1147         pl.add_region (right, 1+preroll);
1148
1149         /* there is only one ... */
1150
1151         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1152
1153         session.audition_playlist ();
1154 }
1155
1156 void
1157 CrossfadeEditor::audition_left_dry ()
1158 {
1159         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left", 
1160                                                                                                               0, Region::DefaultFlags, false)));
1161         
1162         session.audition_region (left);
1163 }
1164
1165 void
1166 CrossfadeEditor::audition_left ()
1167 {
1168         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1169
1170         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left", 
1171                                                                                                               0, Region::DefaultFlags, false)));
1172         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in", 
1173                                                                                                                0, Region::DefaultFlags, false)));
1174
1175         pl.add_region (left, 0);
1176         pl.add_region (right, 1);
1177
1178         right->set_muted (true);
1179
1180         /* there is only one ... */
1181
1182         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1183
1184         session.audition_playlist ();
1185
1186         /* memory leak for regions */
1187 }
1188
1189 void
1190 CrossfadeEditor::audition_right_dry ()
1191 {
1192         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in", 
1193                                                                                                                0, Region::DefaultFlags, false)));
1194         session.audition_region (right);
1195 }
1196
1197 void
1198 CrossfadeEditor::audition_right ()
1199 {
1200         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1201
1202         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade out", 
1203                                                                                                               0, Region::DefaultFlags, false)));
1204                                              boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), 0, xfade->length(), "xfade out", 
1205                                                                                                                0, Region::DefaultFlags, false)));
1206
1207         pl.add_region (left, 0);
1208         pl.add_region (right, 1);
1209         
1210         left->set_muted (true);
1211
1212         /* there is only one ... */
1213
1214         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1215
1216         session.audition_playlist ();
1217 }
1218         
1219 void
1220 CrossfadeEditor::cancel_audition ()
1221 {
1222         session.cancel_audition ();
1223 }
1224
1225 void
1226 CrossfadeEditor::audition_toggled ()
1227 {
1228         bool x;
1229
1230         if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1231
1232                 if (x) {
1233                         audition_both ();
1234                 } else {
1235                         cancel_audition ();
1236                 }
1237         }
1238 }
1239
1240 void
1241 CrossfadeEditor::audition_right_toggled ()
1242 {
1243         bool x;
1244         
1245         if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1246
1247                 if (x) {
1248                         audition_right ();
1249                 } else {
1250                         cancel_audition ();
1251                 }
1252         }
1253 }
1254
1255 void
1256 CrossfadeEditor::audition_right_dry_toggled ()
1257 {
1258         bool x;
1259
1260         if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1261
1262                 if (x) {
1263                         audition_right_dry ();
1264                 } else {
1265                         cancel_audition ();
1266                 }
1267         }
1268 }
1269
1270 void
1271 CrossfadeEditor::audition_left_toggled ()
1272 {
1273         bool x;
1274
1275         if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1276
1277                 if (x) {
1278                         audition_left ();
1279                 } else {
1280                         cancel_audition ();
1281                 }
1282         }
1283 }
1284
1285 void
1286 CrossfadeEditor::audition_left_dry_toggled ()
1287 {
1288         bool x;
1289
1290         if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1291                 
1292                 if (x) {
1293                         audition_left_dry ();
1294                 } else {
1295                         cancel_audition ();
1296                 }
1297         }
1298 }