Can't call the wrong function when there's only one of them: remove ARDOUR::Parameter...
[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_list.h>
31 #include <evoral/Curve.hpp>
32 #include <ardour/crossfade.h>
33 #include <ardour/session.h>
34 #include <ardour/auditioner.h>
35 #include <ardour/audioplaylist.h>
36 #include <ardour/audiosource.h>
37 #include <ardour/playlist_templates.h>
38 #include <ardour/region_factory.h>
39
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
52 using namespace std;
53 using namespace ARDOUR;
54 using namespace PBD;
55 using namespace Gtk;
56 using namespace sigc;
57 using namespace Editing;
58
59 #include "i18n.h"
60
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;
65
66 CrossfadeEditor::Half::Half ()
67         : line (0), 
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))
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() = ARDOUR_UI::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() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
139                 
140         fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
141         fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::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() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
146                 
147         fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
148         fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::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::AutomationList& curve, WhichFade which)
331 {
332         double firstx, endx;
333         ARDOUR::AutomationList::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.end();
348         --the_end;
349         
350         firstx = (*curve.begin())->when;
351         endx = (*the_end)->when;
352
353         for (ARDOUR::AutomationList::const_iterator i = curve.begin(); i != curve.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() = 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;
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                 double offset;
642                 if (current==In)
643                         offset = xfade->in()->start();
644                 else
645                         offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
646                 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
647         }
648
649
650         size_t npoints = (size_t) effective_width();
651         float vec[npoints];
652
653         fade[current].normative_curve.curve().get_vector (0, 1.0, vec, npoints);
654         
655         ArdourCanvas::Points pts;
656         ArdourCanvas::Points spts;
657
658         while (pts.size() < npoints) {
659                 pts.push_back (Gnome::Art::Point (0,0));
660         }
661
662         while (spts.size() < npoints + 3) {
663                 spts.push_back (Gnome::Art::Point (0,0));
664         }
665
666         /* the shade coordinates *MUST* be in anti-clockwise order.
667          */
668
669         if (current == In) {
670
671                 /* lower left */
672
673                 spts[0].set_x (canvas_border);
674                 spts[0].set_y (effective_height() + canvas_border);
675
676                 /* lower right */
677
678                 spts[1].set_x (effective_width() + canvas_border);
679                 spts[1].set_y (effective_height() + canvas_border);
680
681                 /* upper right */
682
683                 spts[2].set_x (effective_width() + canvas_border);
684                 spts[2].set_y (canvas_border);
685
686                 
687         } else {
688
689                 /*  upper left */
690                 
691                 spts[0].set_x (canvas_border);
692                 spts[0].set_y (canvas_border);
693
694                 /* lower left */
695
696                 spts[1].set_x (canvas_border);
697                 spts[1].set_y (effective_height() + canvas_border);
698
699                 /* lower right */
700
701                 spts[2].set_x (effective_width() + canvas_border);
702                 spts[2].set_y (effective_height() + canvas_border);
703
704         }
705
706         size_t last_spt = (npoints + 3) - 1;
707
708         for (size_t i = 0; i < npoints; ++i) {
709
710                 double y = vec[i];
711                 
712                 pts[i].set_x (canvas_border + i);
713                 pts[i].set_y  (y_coordinate (y));
714
715                 spts[last_spt - i].set_x (canvas_border + i);
716                 spts[last_spt - i].set_y (pts[i].get_y());
717         }
718
719         fade[current].line->property_points() = pts;
720         fade[current].shading->property_points() = spts;
721
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;
724         }
725 }
726
727 void
728 CrossfadeEditor::apply_preset (Preset *preset)
729 {
730   
731         WhichFade wf =  find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
732         
733         if (current != wf) {
734           
735                 if (wf == In) {
736                         select_in_button.clicked();
737                 } else {
738                         select_out_button.clicked();
739                 }
740                 
741                 curve_select_clicked (wf);
742         }  
743         
744         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
745                 delete *i;
746         }
747
748         fade[current].points.clear ();
749
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),
753                             (*i).x, (*i).y);
754                 fade[current].points.push_back (p);
755         }
756
757         redraw ();
758 }
759
760 void
761 CrossfadeEditor::apply ()
762 {
763         _apply_to (xfade);
764 }
765
766 void
767 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
768 {
769         ARDOUR::AutomationList& in (xf->fade_in());
770         ARDOUR::AutomationList& out (xf->fade_out());
771
772         /* IN */
773
774
775         ARDOUR::AutomationList::const_iterator the_end = in.end();
776         --the_end;
777
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 ();
782
783         in.freeze ();
784         in.clear ();
785
786         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
787
788                 double when = firstx + ((*i)->x * (endx - firstx));
789                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
790                 in.add (when, value);
791         }
792
793         /* OUT */
794
795         the_end = out.end();
796         --the_end;
797
798         firstx = (*out.begin())->when;
799         endx = (*the_end)->when;
800         miny = out.get_min_y ();
801         maxy = out.get_max_y ();
802
803         out.freeze ();
804         out.clear ();
805
806         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
807
808                 double when = firstx + ((*i)->x * (endx - firstx));
809                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
810                 out.add (when, value);
811         }
812
813         in.thaw ();
814         out.thaw ();
815 }
816
817 void
818 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
819 {
820         _apply_to (xfade);
821         xfade->set_active (true);
822         xfade->fade_in().curve().solve ();
823         xfade->fade_out().curve().solve ();
824 }
825
826 void
827 CrossfadeEditor::clear ()
828 {
829         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
830                 delete *i;
831         }
832
833         fade[current].points.clear ();
834
835         redraw ();
836 }
837
838 void
839 CrossfadeEditor::reset ()
840 {
841         set (xfade->fade_in(),  In);
842         set (xfade->fade_out(), Out);
843
844         curve_select_clicked (current);
845 }
846
847 void
848 CrossfadeEditor::build_presets ()
849 {
850         Preset* p;
851
852         fade_in_presets = new Presets;
853         fade_out_presets = new Presets;
854
855         /* FADE OUT */
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);
867         
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);
878
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);
889
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);
900
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);
906
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);
915         
916         /* FADE OUT */
917
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);
928         
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);
939
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);
950
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);
960
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);
966         
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);
975 }
976
977 void
978 CrossfadeEditor::curve_select_clicked (WhichFade wf)
979 {
980         current = wf;
981         
982         if (wf == In) {
983                 
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();
987                 }
988
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();
992                 }
993
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();
998
999                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1000                         (*i)->box->hide();
1001                 }
1002
1003                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1004                         (*i)->box->show ();
1005                 }
1006
1007         } else {
1008
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();
1012                 }
1013
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();
1017                 }
1018
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();
1023
1024                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1025                         (*i)->box->hide();
1026                 }
1027                 
1028                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1029                         (*i)->box->show();
1030                 }
1031
1032         }
1033 }
1034
1035 double 
1036 CrossfadeEditor::x_coordinate (double& xfract) const
1037 {
1038         xfract = min (1.0, xfract);
1039         xfract = max (0.0, xfract);
1040     
1041         return canvas_border + (xfract * effective_width());
1042 }
1043
1044 double
1045 CrossfadeEditor::y_coordinate (double& yfract) const
1046 {
1047         yfract = min (1.0, yfract);
1048         yfract = max (0.0, yfract);
1049
1050         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1051 }
1052
1053 void
1054 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1055 {
1056         gdouble ht;
1057         uint32_t nchans = region->n_channels();
1058         guint32 color;
1059         double spu;
1060
1061         if (which == In) {
1062                 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1063         } else {
1064                 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1065         }
1066
1067         ht = canvas->get_allocation().get_height() / (double) nchans;
1068         spu = xfade->length() / (double) effective_width();
1069
1070         for (uint32_t n = 0; n < nchans; ++n) {
1071                 
1072                 gdouble yoff = n * ht;
1073                 
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()));
1076
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;
1093                         
1094                         if (which==In)
1095                                 waveview->property_region_start() = region->start();
1096                         else
1097                                 waveview->property_region_start() = region->start()+region->length()-xfade->length();
1098
1099                         waveview->lower_to_bottom();
1100                         fade[which].waves.push_back (waveview);
1101                 }
1102         }
1103
1104         toplevel->lower_to_bottom();
1105 }
1106
1107 void
1108 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1109 {
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 ..
1113         */
1114         peaks_ready_connection.disconnect ();
1115         make_waves (r, which);
1116 }
1117
1118 void
1119 CrossfadeEditor::audition (Audition which)
1120 {
1121         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1122         nframes_t preroll;
1123         nframes_t postroll;
1124         nframes_t left_start_offset;
1125         nframes_t right_length;
1126         nframes_t left_length;
1127
1128         if (which != Right && preroll_button.get_active()) {
1129                 preroll = session.frame_rate() * 2;  //2 second hardcoded preroll for now
1130         } else {
1131                 preroll = 0;
1132         }
1133
1134         if (which != Left && postroll_button.get_active()) {
1135                 postroll = session.frame_rate() * 2;  //2 second hardcoded postroll for now
1136         } else {
1137                 postroll = 0;
1138         }
1139
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;
1144         } else {
1145                 preroll = left_start_offset;
1146                 left_start_offset = 0;
1147         }
1148         left_length += preroll;
1149
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;
1154         } else {
1155                 right_length = xfade->in()->length();
1156         }
1157
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)));
1162         
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);
1168
1169         pl.add_region (left, 0);
1170         pl.add_region (right, 1 + preroll);
1171         
1172         if (which == Left) {
1173                 right->set_scale_amplitude (0.0);
1174         } else if (which == Right) {
1175                 left->set_scale_amplitude (0.0);
1176         }
1177
1178         /* there is only one ... */
1179         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1180
1181         session.audition_playlist ();
1182 }
1183
1184 void
1185 CrossfadeEditor::audition_both ()
1186 {
1187         audition (Both);
1188 }
1189
1190 void
1191 CrossfadeEditor::audition_left_dry ()
1192 {
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)));
1195         
1196         session.audition_region (left);
1197 }
1198
1199 void
1200 CrossfadeEditor::audition_left ()
1201 {
1202         audition (Left);
1203 }
1204
1205 void
1206 CrossfadeEditor::audition_right_dry ()
1207 {
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);
1211 }
1212
1213 void
1214 CrossfadeEditor::audition_right ()
1215 {
1216         audition (Right);
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 }