SaBers auditioning fixes, plus a declicking fade at start and end
[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
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 (0.0, 1.0, 1.0, true),
69           gain_curve (0.0, 2.0, 1.0, true)
70 {
71 }
72
73 CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr<Crossfade> xf, double my, double mxy)
74         : ArdourDialog (_("ardour: x-fade edit")),
75           xfade (xf),
76           session (s),
77           clear_button (_("Clear")),
78           revert_button (_("Reset")),
79           audition_both_button (_("Fade")),
80           audition_left_dry_button (_("Out (dry)")),
81           audition_left_button (_("Out")),
82           audition_right_dry_button (_("In (dry)")),
83           audition_right_button (_("In")),
84
85           preroll_button (_("With Pre-roll")),
86           postroll_button (_("With Post-roll")),
87           
88           miny (my),
89           maxy (mxy),
90
91           fade_in_table (3, 3),
92           fade_out_table (3, 3),
93
94           select_in_button (_("Fade In")),
95           select_out_button (_("Fade Out"))
96 {
97         set_wmclass (X_("ardour_automationedit"), "Ardour");
98         set_name ("CrossfadeEditWindow");
99         set_position (Gtk::WIN_POS_MOUSE);
100
101         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
102
103         RadioButtonGroup sel_but_group = select_in_button.get_group();
104         select_out_button.set_group (sel_but_group);
105         select_out_button.set_mode (false);
106         select_in_button.set_mode (false);
107
108         get_action_area()->set_layout(BUTTONBOX_SPREAD);
109         get_action_area()->pack_start(clear_button);
110         get_action_area()->pack_start(revert_button);
111         cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
112         ok_button = add_button ("OK", RESPONSE_ACCEPT);
113
114         if (fade_in_presets == 0) {
115                 build_presets ();
116         }
117
118         point_grabbed = false;
119         toplevel = 0;
120
121         canvas = new ArdourCanvas::CanvasAA ();
122         canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation));
123         canvas->set_size_request (425, 200);
124         
125         toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
126         toplevel->property_x1() =  0.0;
127         toplevel->property_y1() =  0.0;
128         toplevel->property_x2() =  10.0;
129         toplevel->property_y2() =  10.0;
130         toplevel->property_fill() =  true;
131         toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get();
132         toplevel->property_outline_pixels() =  0;
133         toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
134         
135         fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
136         fade[Out].line->property_width_pixels() = 1;
137         fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
138                 
139         fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
140         fade[Out].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
141
142         fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
143         fade[In].line->property_width_pixels() = 1;
144         fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
145                 
146         fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
147         fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get();
148         
149         fade[In].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
150         fade[In].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
151         fade[Out].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
152         fade[Out].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
153
154         select_in_button.set_name (X_("CrossfadeEditCurveButton"));
155         select_out_button.set_name (X_("CrossfadeEditCurveButton"));
156
157         select_in_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
158         select_out_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
159
160         HBox* acbox = manage (new HBox);
161         
162         audition_box.set_border_width (7);
163         audition_box.set_spacing (5);
164         audition_box.set_homogeneous (false);
165         audition_box.pack_start (audition_left_dry_button, false, false);
166         audition_box.pack_start (audition_left_button, false, false);
167         audition_box.pack_start (audition_both_button, false, false);
168         audition_box.pack_start (audition_right_button, false, false);
169         audition_box.pack_start (audition_right_dry_button, false, false);
170
171         Frame* audition_frame = manage (new Frame (_("Audition")));
172         
173         audition_frame->set_name (X_("CrossfadeEditFrame"));
174         audition_frame->add (audition_box);
175
176         acbox->pack_start (*audition_frame, true, false);
177
178         Frame* canvas_frame = manage (new Frame);
179         canvas_frame->add (*canvas);
180         canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
181
182         fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
183         fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
184
185         Image *pxmap;
186         Button* pbutton;
187         int row;
188         int col;
189
190         row = 1;
191         col = 0;
192
193         for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
194
195                 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
196                 pbutton = manage (new Button);
197                 pbutton->add (*pxmap);
198                 pbutton->set_name ("CrossfadeEditButton");
199                 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
200                 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
201                 fade_in_buttons.push_back (pbutton);
202
203                 col++;
204
205                 if (col == 2) {
206                         col = 0;
207                         row++;
208                 }
209         }
210
211         row = 1;
212         col = 0;
213
214         for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
215
216                 pxmap = manage (new Image (::get_icon ((*i)->image_name)));
217                 pbutton = manage (new Button);
218                 pbutton->add (*pxmap);
219                 pbutton->set_name ("CrossfadeEditButton");
220                 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
221                 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
222                 fade_out_buttons.push_back (pbutton);
223
224                 col++;
225
226                 if (col == 2) {
227                         col = 0;
228                         row++;
229                 }
230         }
231
232         clear_button.set_name ("CrossfadeEditButton");
233         revert_button.set_name ("CrossfadeEditButton");
234         ok_button->set_name ("CrossfadeEditButton");
235         cancel_button->set_name ("CrossfadeEditButton");
236         preroll_button.set_name ("CrossfadeEditButton");
237         postroll_button.set_name ("CrossfadeEditButton");
238         audition_both_button.set_name ("CrossfadeEditAuditionButton");
239         audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
240         audition_left_button.set_name ("CrossfadeEditAuditionButton");
241         audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
242         audition_right_button.set_name ("CrossfadeEditAuditionButton");
243
244         clear_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear));
245         revert_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset));
246         audition_both_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled));
247         audition_right_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
248         audition_right_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
249         audition_left_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
250         audition_left_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
251
252         roll_box.pack_start (preroll_button, false, false);
253         roll_box.pack_start (postroll_button, false, false);
254
255         Gtk::HBox* rcenter_box = manage (new HBox);
256         rcenter_box->pack_start (roll_box, true, false);
257
258         VBox* vpacker2 = manage (new (VBox));
259
260         vpacker2->set_border_width (12);
261         vpacker2->set_spacing (7);
262         vpacker2->pack_start (*acbox, false, false);
263         vpacker2->pack_start (*rcenter_box, false, false);
264
265         curve_button_box.set_spacing (7);
266         curve_button_box.pack_start (fade_out_table, false, false, 12);
267         curve_button_box.pack_start (*vpacker2, false, false, 12);
268         curve_button_box.pack_start (fade_in_table, false, false, 12);
269         
270         get_vbox()->pack_start (*canvas_frame, true, true);
271         get_vbox()->pack_start (curve_button_box, false, false);
272
273         /* button to allow hackers to check the actual curve values */
274
275 //      Button* foobut = manage (new Button ("dump"));
276 //      foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
277 //      vpacker.pack_start (*foobut, false, false);
278
279         current = In;
280         set (xfade->fade_in(), In);
281
282         current = Out;
283         set (xfade->fade_out(), Out);
284
285         curve_select_clicked (In);
286
287         xfade->StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed));
288
289         session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed));
290         show_all_children();
291 }
292
293 CrossfadeEditor::~CrossfadeEditor()
294 {
295         /* most objects will be destroyed when the toplevel window is. */
296
297         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
298                 delete *i;
299         }
300
301         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
302                 delete *i;
303         }
304 }
305
306 void
307 CrossfadeEditor::dump ()
308 {
309         for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
310                 cerr << (*i)->when << ' ' << (*i)->value << endl;
311         }
312 }
313
314 void
315 CrossfadeEditor::audition_state_changed (bool yn)
316 {
317         ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn));
318
319         if (!yn) {
320                 audition_both_button.set_active (false);
321                 audition_left_button.set_active (false);
322                 audition_right_button.set_active (false);
323                 audition_left_dry_button.set_active (false);
324                 audition_right_dry_button.set_active (false);
325         }
326 }
327
328 void
329 CrossfadeEditor::set (const ARDOUR::Curve& curve, WhichFade which)
330 {
331         double firstx, endx;
332         ARDOUR::Curve::const_iterator the_end;
333
334         for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
335                         delete *i;
336         }
337         
338         fade[which].points.clear ();
339         fade[which].gain_curve.clear ();
340         fade[which].normative_curve.clear ();
341
342         if (curve.empty()) {
343                 goto out;
344         }
345         
346         the_end = curve.const_end();
347         --the_end;
348         
349         firstx = (*curve.const_begin())->when;
350         endx = (*the_end)->when;
351
352         for (ARDOUR::Curve::const_iterator i = curve.const_begin(); i != curve.const_end(); ++i) {
353                 
354                 double xfract = ((*i)->when - firstx) / (endx - firstx);
355                 double yfract = ((*i)->value - miny) / (maxy - miny);
356                 
357                 Point* p = make_point ();
358
359                 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
360                             xfract, yfract);
361                 
362                 fade[which].points.push_back (p);
363         }
364
365         /* no need to sort because curve is already time-ordered */
366
367   out:
368         
369         swap (which, current);
370         redraw ();
371         swap (which, current);
372 }
373
374 bool
375 CrossfadeEditor::curve_event (GdkEvent* event)
376 {
377         /* treat it like a toplevel event */
378
379         return canvas_event (event);
380 }
381
382 bool
383 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
384 {
385
386         if (point->curve != fade[current].line) {
387                 return FALSE;
388         }
389
390         switch (event->type) {
391         case GDK_BUTTON_PRESS:
392                 point_grabbed = true;
393                 break;
394         case GDK_BUTTON_RELEASE:
395                 point_grabbed = false;
396
397                 if (Keyboard::is_delete_event (&event->button)) {
398                         fade[current].points.remove (point);
399                         delete point;
400                 }
401
402                 redraw ();
403                 break;
404
405         case GDK_MOTION_NOTIFY:
406                 if (point_grabbed) {
407                         double new_x, new_y;
408
409                         /* can't drag first or last points horizontally */
410
411                         if (point == fade[current].points.front() || point == fade[current].points.back()) {
412                                 new_x = point->x;
413                         } else {
414                                 new_x = (event->motion.x - canvas_border)/effective_width();
415                         }
416
417                         new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
418                         point->move_to (x_coordinate (new_x), y_coordinate (new_y), 
419                                         new_x, new_y);
420                         redraw ();
421                 }
422                 break;
423         default:
424                 break;
425         }
426         return TRUE;
427 }
428
429 bool
430 CrossfadeEditor::canvas_event (GdkEvent* event)
431 {
432         switch (event->type) {
433         case GDK_BUTTON_PRESS:
434                 add_control_point ((event->button.x - canvas_border)/effective_width(),
435                                    1.0 - ((event->button.y - canvas_border)/effective_height()));
436                 return TRUE;
437                 break;
438         default:
439                 break;
440         }
441         return FALSE;
442 }
443
444 CrossfadeEditor::Point::~Point()
445 {
446         delete box;
447 }
448
449 CrossfadeEditor::Point*
450 CrossfadeEditor::make_point ()
451 {
452         Point* p = new Point;
453
454         p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
455         p->box->property_fill() = true;
456         p->box->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointFill.get();
457         p->box->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorPointOutline.get();
458         p->box->property_outline_pixels() = 1;
459
460         p->curve = fade[current].line;
461
462         p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p));
463         
464         return p;
465 }
466
467 void
468 CrossfadeEditor::add_control_point (double x, double y)
469 {
470         PointSorter cmp;
471
472         /* enforce end point x location */
473         
474         if (fade[current].points.empty()) {
475                 x = 0.0;
476         } else if (fade[current].points.size() == 1) {
477                 x = 1.0;
478         } 
479
480         Point* p = make_point ();
481
482         p->move_to (x_coordinate (x), y_coordinate (y), x, y);
483
484         fade[current].points.push_back (p);
485         fade[current].points.sort (cmp);
486
487         redraw ();
488 }
489
490 void
491 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
492 {
493         const double half_size = rint(size/2.0);
494         double x1 = nx - half_size;
495         double x2 = nx + half_size;
496
497         box->property_x1() = x1;
498         box->property_x2() = x2;
499
500         box->property_y1() = ny - half_size;
501         box->property_y2() = ny + half_size;
502
503         x = xfract;
504         y = yfract;
505 }
506
507 void
508 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
509 {
510         if (toplevel) {
511                 toplevel->property_x1() = 0.0;
512                 toplevel->property_y1() = 0.0;
513                 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
514                 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
515         }
516         
517         canvas->set_scroll_region (0.0, 0.0, 
518                                    canvas->get_allocation().get_width(), 
519                                    canvas->get_allocation().get_height());
520
521         Point* end = make_point ();
522         PointSorter cmp;
523
524         if (fade[In].points.size() > 1) {
525                 Point* old_end = fade[In].points.back();
526                 fade[In].points.pop_back ();
527                 end->move_to (x_coordinate (old_end->x),
528                               y_coordinate (old_end->y),
529                               old_end->x, old_end->y);
530                 delete old_end;
531         } else {
532                 double x = 1.0;
533                 double y = 0.5;
534                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
535
536         }
537
538         fade[In].points.push_back (end);
539         fade[In].points.sort (cmp);
540
541         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
542                 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
543                                (*i)->x, (*i)->y);
544         }
545         
546         end = make_point ();
547         
548         if (fade[Out].points.size() > 1) {
549                 Point* old_end = fade[Out].points.back();
550                 fade[Out].points.pop_back ();
551                 end->move_to (x_coordinate (old_end->x),
552                               y_coordinate (old_end->y),
553                               old_end->x, old_end->y);
554                 delete old_end;
555         } else {
556                 double x = 1.0;
557                 double y = 0.5;
558                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
559
560         }
561
562         fade[Out].points.push_back (end);
563         fade[Out].points.sort (cmp);
564
565         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
566                 (*i)->move_to (x_coordinate ((*i)->x),
567                                y_coordinate ((*i)->y),
568                                (*i)->x, (*i)->y);
569         }
570         
571         WhichFade old_current = current;
572         current = In;
573         redraw ();
574         current = Out;
575         redraw ();
576         current = old_current;
577
578         double spu = xfade->length() / (double) effective_width();
579
580         if (fade[In].waves.empty()) {
581                 make_waves (xfade->in(), In);
582         }
583
584         if (fade[Out].waves.empty()) {
585                 make_waves (xfade->out(), Out);
586         }
587
588         double ht;
589         vector<ArdourCanvas::WaveView*>::iterator i;
590         uint32_t n;
591
592         ht = canvas->get_allocation().get_height() / xfade->in()->n_channels();
593
594         for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
595                 double yoff;
596
597                 yoff = n * ht;
598
599                 (*i)->property_y() = yoff;
600                 (*i)->property_height() = ht;
601                 (*i)->property_samples_per_unit() = spu;
602         }
603
604         ht = canvas->get_allocation().get_height() / xfade->out()->n_channels();
605
606         for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
607                 double yoff;
608
609                 yoff = n * ht;
610
611                 (*i)->property_y() = yoff;
612                 (*i)->property_height() = ht;
613                 (*i)->property_samples_per_unit() = spu;
614         }
615
616 }
617
618
619 void
620 CrossfadeEditor::xfade_changed (Change ignored)
621 {
622         set (xfade->fade_in(), In);
623         set (xfade->fade_out(), Out);
624 }
625
626 void
627 CrossfadeEditor::redraw ()
628 {
629         if (canvas->get_allocation().get_width() < 2) {
630                 return;
631         }
632
633         nframes_t len = xfade->length ();
634
635         fade[current].normative_curve.clear ();
636         fade[current].gain_curve.clear ();
637
638         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
639                 fade[current].normative_curve.add ((*i)->x, (*i)->y);
640                 double offset;
641                 if (current==In)
642                         offset = xfade->in()->start();
643                 else
644                         offset = xfade->out()->start()+xfade->out()->length()-xfade->length();
645                 fade[current].gain_curve.add (((*i)->x * len) + offset, (*i)->y);
646         }
647
648
649         size_t npoints = (size_t) effective_width();
650         float vec[npoints];
651
652         fade[current].normative_curve.get_vector (0, 1.0, vec, npoints);
653         
654         ArdourCanvas::Points pts;
655         ArdourCanvas::Points spts;
656
657         while (pts.size() < npoints) {
658                 pts.push_back (Gnome::Art::Point (0,0));
659         }
660
661         while (spts.size() < npoints + 3) {
662                 spts.push_back (Gnome::Art::Point (0,0));
663         }
664
665         /* the shade coordinates *MUST* be in anti-clockwise order.
666          */
667
668         if (current == In) {
669
670                 /* lower left */
671
672                 spts[0].set_x (canvas_border);
673                 spts[0].set_y (effective_height() + canvas_border);
674
675                 /* lower right */
676
677                 spts[1].set_x (effective_width() + canvas_border);
678                 spts[1].set_y (effective_height() + canvas_border);
679
680                 /* upper right */
681
682                 spts[2].set_x (effective_width() + canvas_border);
683                 spts[2].set_y (canvas_border);
684
685                 
686         } else {
687
688                 /*  upper left */
689                 
690                 spts[0].set_x (canvas_border);
691                 spts[0].set_y (canvas_border);
692
693                 /* lower left */
694
695                 spts[1].set_x (canvas_border);
696                 spts[1].set_y (effective_height() + canvas_border);
697
698                 /* lower right */
699
700                 spts[2].set_x (effective_width() + canvas_border);
701                 spts[2].set_y (effective_height() + canvas_border);
702
703         }
704
705         size_t last_spt = (npoints + 3) - 1;
706
707         for (size_t i = 0; i < npoints; ++i) {
708
709                 double y = vec[i];
710                 
711                 pts[i].set_x (canvas_border + i);
712                 pts[i].set_y  (y_coordinate (y));
713
714                 spts[last_spt - i].set_x (canvas_border + i);
715                 spts[last_spt - i].set_y (pts[i].get_y());
716         }
717
718         fade[current].line->property_points() = pts;
719         fade[current].shading->property_points() = spts;
720
721         for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
722                 (*i)->property_gain_src() = &fade[current].gain_curve;
723         }
724 }
725
726 void
727 CrossfadeEditor::apply_preset (Preset *preset)
728 {
729   
730         WhichFade wf =  find(fade_in_presets->begin(), fade_in_presets->end(), preset) != fade_in_presets->end() ? In : Out;
731         
732         if (current != wf) {
733           
734                 if (wf == In) {
735                         select_in_button.clicked();
736                 } else {
737                         select_out_button.clicked();
738                 }
739                 
740                 curve_select_clicked (wf);
741         }  
742         
743         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
744                 delete *i;
745         }
746
747         fade[current].points.clear ();
748
749         for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
750                 Point* p = make_point ();
751                 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
752                             (*i).x, (*i).y);
753                 fade[current].points.push_back (p);
754         }
755
756         redraw ();
757 }
758
759 void
760 CrossfadeEditor::apply ()
761 {
762         _apply_to (xfade);
763 }
764
765 void
766 CrossfadeEditor::_apply_to (boost::shared_ptr<Crossfade> xf)
767 {
768         ARDOUR::Curve& in (xf->fade_in());
769         ARDOUR::Curve& out (xf->fade_out());
770
771         /* IN */
772
773
774         ARDOUR::Curve::const_iterator the_end = in.const_end();
775         --the_end;
776
777         double firstx = (*in.begin())->when;
778         double endx = (*the_end)->when;
779         double miny = in.get_min_y ();
780         double maxy = in.get_max_y ();
781
782         in.freeze ();
783         in.clear ();
784
785         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
786
787                 double when = firstx + ((*i)->x * (endx - firstx));
788                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
789                 in.add (when, value);
790         }
791
792         /* OUT */
793
794         the_end = out.const_end();
795         --the_end;
796
797         firstx = (*out.begin())->when;
798         endx = (*the_end)->when;
799         miny = out.get_min_y ();
800         maxy = out.get_max_y ();
801
802         out.freeze ();
803         out.clear ();
804
805         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
806
807                 double when = firstx + ((*i)->x * (endx - firstx));
808                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
809                 out.add (when, value);
810         }
811
812         in.thaw ();
813         out.thaw ();
814 }
815
816 void
817 CrossfadeEditor::setup (boost::shared_ptr<Crossfade> xfade)
818 {
819         _apply_to (xfade);
820         xfade->set_active (true);
821         xfade->fade_in().solve ();
822         xfade->fade_out().solve ();
823 }
824
825 void
826 CrossfadeEditor::clear ()
827 {
828         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
829                 delete *i;
830         }
831
832         fade[current].points.clear ();
833
834         redraw ();
835 }
836
837 void
838 CrossfadeEditor::reset ()
839 {
840         set (xfade->fade_in(),  In);
841         set (xfade->fade_out(), Out);
842
843         curve_select_clicked (current);
844 }
845
846 void
847 CrossfadeEditor::build_presets ()
848 {
849         Preset* p;
850
851         fade_in_presets = new Presets;
852         fade_out_presets = new Presets;
853
854         /* FADE OUT */
855         // p = new Preset ("hiin.xpm");
856         p = new Preset ("crossfade_in_fast-cut");
857         p->push_back (PresetPoint (0, 0));
858         p->push_back (PresetPoint (0.0207373, 0.197222));
859         p->push_back (PresetPoint (0.0645161, 0.525));
860         p->push_back (PresetPoint (0.152074, 0.802778));
861         p->push_back (PresetPoint (0.276498, 0.919444));
862         p->push_back (PresetPoint (0.481567, 0.980556));
863         p->push_back (PresetPoint (0.767281, 1));
864         p->push_back (PresetPoint (1, 1));
865         fade_in_presets->push_back (p);
866         
867         // p = new Preset ("loin.xpm");
868         p = new Preset ("crossfade_in_transition");
869         p->push_back (PresetPoint (0, 0));
870         p->push_back (PresetPoint (0.389401, 0.0333333));
871         p->push_back (PresetPoint (0.629032, 0.0861111));
872         p->push_back (PresetPoint (0.829493, 0.233333));
873         p->push_back (PresetPoint (0.9447, 0.483333));
874         p->push_back (PresetPoint (0.976959, 0.697222));
875         p->push_back (PresetPoint (1, 1));
876         fade_in_presets->push_back (p);
877
878         // p = new Preset ("regin.xpm");
879         p = new Preset ("crossfade_in_constant");
880         p->push_back (PresetPoint (0, 0));
881         p->push_back (PresetPoint (0.0737327, 0.308333));
882         p->push_back (PresetPoint (0.246544, 0.658333));
883         p->push_back (PresetPoint (0.470046, 0.886111));
884         p->push_back (PresetPoint (0.652074, 0.972222));
885         p->push_back (PresetPoint (0.771889, 0.988889));
886         p->push_back (PresetPoint (1, 1));
887         fade_in_presets->push_back (p);
888
889         // p = new Preset ("regin2.xpm");
890         p = new Preset ("crossfade_in_slow-cut");
891         p->push_back (PresetPoint (0, 0));
892         p->push_back (PresetPoint (0.304147, 0.0694444));
893         p->push_back (PresetPoint (0.529954, 0.152778));
894         p->push_back (PresetPoint (0.725806, 0.333333));
895         p->push_back (PresetPoint (0.847926, 0.558333));
896         p->push_back (PresetPoint (0.919355, 0.730556));
897         p->push_back (PresetPoint (1, 1));
898         fade_in_presets->push_back (p);
899
900         // p = new Preset ("linin.xpm");
901         p = new Preset ("crossfade_in_dipped");
902         p->push_back (PresetPoint (0, 0));
903         p->push_back (PresetPoint (1, 1));
904         fade_in_presets->push_back (p);
905
906         p = new Preset ("crossfade_in_default");
907         p->push_back (PresetPoint (0, 0));
908         p->push_back (PresetPoint (0.1, 0.01));
909         p->push_back (PresetPoint (0.2, 0.03));
910         p->push_back (PresetPoint (0.8, 0.97));
911         p->push_back (PresetPoint (0.9, 0.99));
912         p->push_back (PresetPoint (1, 1));
913         fade_in_presets->push_back (p);
914         
915         /* FADE OUT */
916
917         // p = new Preset ("hiout.xpm");
918         p = new Preset ("crossfade_out_fast-cut");
919         p->push_back (PresetPoint (0, 1));
920         p->push_back (PresetPoint (0.305556, 1));
921         p->push_back (PresetPoint (0.548611, 0.991736));
922         p->push_back (PresetPoint (0.759259, 0.931129));
923         p->push_back (PresetPoint (0.918981, 0.68595));
924         p->push_back (PresetPoint (0.976852, 0.22865));
925         p->push_back (PresetPoint (1, 0));
926         fade_out_presets->push_back (p);
927         
928         // p = new Preset ("loout.xpm");
929         p = new Preset ("crossfade_out_transition");
930         p->push_back (PresetPoint (0, 1));
931         p->push_back (PresetPoint (0.023041, 0.697222));
932         p->push_back (PresetPoint (0.0553,   0.483333));
933         p->push_back (PresetPoint (0.170507, 0.233333));
934         p->push_back (PresetPoint (0.370968, 0.0861111));
935         p->push_back (PresetPoint (0.610599, 0.0333333));
936         p->push_back (PresetPoint (1, 0));
937         fade_out_presets->push_back (p);
938
939         // p = new Preset ("regout.xpm");
940         p = new Preset ("crossfade_out_constant");
941         p->push_back (PresetPoint (0, 1));
942         p->push_back (PresetPoint (0.228111, 0.988889));
943         p->push_back (PresetPoint (0.347926, 0.972222));
944         p->push_back (PresetPoint (0.529954, 0.886111));
945         p->push_back (PresetPoint (0.753456, 0.658333));
946         p->push_back (PresetPoint (0.9262673, 0.308333));
947         p->push_back (PresetPoint (1, 0));
948         fade_out_presets->push_back (p);
949
950         // p = new Preset ("regout2.xpm");
951         p = new Preset ("crossfade_out_slow-fade");
952         p->push_back (PresetPoint (0, 1));
953         p->push_back (PresetPoint (0.080645, 0.730556));
954         p->push_back (PresetPoint (0.277778, 0.289256));
955         p->push_back (PresetPoint (0.470046, 0.152778));
956         p->push_back (PresetPoint (0.695853, 0.0694444));
957         p->push_back (PresetPoint (1, 0));
958         fade_out_presets->push_back (p);
959
960         // p = new Preset ("linout.xpm");
961         p = new Preset ("crossfade_out_dipped");
962         p->push_back (PresetPoint (0, 1));
963         p->push_back (PresetPoint (1, 0));
964         fade_out_presets->push_back (p);
965         
966         p = new Preset ("crossfade_out_default");
967         p->push_back (PresetPoint (0, 1));
968         p->push_back (PresetPoint (0.1, 0.99));
969         p->push_back (PresetPoint (0.2, 0.97));
970         p->push_back (PresetPoint (0.8, 0.03));
971         p->push_back (PresetPoint (0.9, 0.01));
972         p->push_back (PresetPoint (1, 0));
973         fade_out_presets->push_back (p);
974 }
975
976 void
977 CrossfadeEditor::curve_select_clicked (WhichFade wf)
978 {
979         current = wf;
980         
981         if (wf == In) {
982                 
983                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
984                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
985                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
986                 }
987
988                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
989                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
990                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
991                 }
992
993                 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
994                 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
995                 fade[Out].shading->hide();
996                 fade[In].shading->show();
997
998                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
999                         (*i)->box->hide();
1000                 }
1001
1002                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1003                         (*i)->box->show ();
1004                 }
1005
1006         } else {
1007
1008                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
1009                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1010                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1011                 }
1012
1013                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
1014                         (*i)->property_wave_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1015                         (*i)->property_fill_color() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1016                 }
1017
1018                 fade[Out].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorLine.get();
1019                 fade[In].line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLine.get();
1020                 fade[In].shading->hide();
1021                 fade[Out].shading->show();
1022
1023                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
1024                         (*i)->box->hide();
1025                 }
1026                 
1027                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
1028                         (*i)->box->show();
1029                 }
1030
1031         }
1032 }
1033
1034 double 
1035 CrossfadeEditor::x_coordinate (double& xfract) const
1036 {
1037         xfract = min (1.0, xfract);
1038         xfract = max (0.0, xfract);
1039     
1040         return canvas_border + (xfract * effective_width());
1041 }
1042
1043 double
1044 CrossfadeEditor::y_coordinate (double& yfract) const
1045 {
1046         yfract = min (1.0, yfract);
1047         yfract = max (0.0, yfract);
1048
1049         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1050 }
1051
1052 void
1053 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1054 {
1055         gdouble ht;
1056         uint32_t nchans = region->n_channels();
1057         guint32 color;
1058         double spu;
1059
1060         if (which == In) {
1061                 color = ARDOUR_UI::config()->canvasvar_SelectedCrossfadeEditorWave.get();
1062         } else {
1063                 color = ARDOUR_UI::config()->canvasvar_CrossfadeEditorWave.get();
1064         }
1065
1066         ht = canvas->get_allocation().get_height() / (double) nchans;
1067         spu = xfade->length() / (double) effective_width();
1068
1069         for (uint32_t n = 0; n < nchans; ++n) {
1070                 
1071                 gdouble yoff = n * ht;
1072                 
1073                 if (region->source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1074                         
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 }