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