1d275d5e3bbfdce0cc48c9e75caa47b176311e1c
[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, 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 ("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         jack_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         // GTK2FIX some odd math to fix up here
702
703         size_t last_spt = (npoints + 3) - 1;
704
705         for (size_t i = 0; i < npoints; ++i) {
706
707                 double y = vec[i];
708                 
709                 pts[i].set_x (canvas_border + i);
710                 pts[i].set_y  (y_coordinate (y));
711
712                 spts[last_spt - i].set_x (canvas_border + i);
713                 spts[last_spt - i].set_y (pts[i].get_y());
714         }
715
716         fade[current].line->property_points() = pts;
717         fade[current].shading->property_points() = spts;
718
719         for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
720                 (*i)->property_gain_src() = &fade[current].gain_curve;
721         }
722 }
723
724 void
725 CrossfadeEditor::apply_preset (Preset *preset)
726 {
727         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
728                 delete *i;
729         }
730
731         fade[current].points.clear ();
732
733         for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
734                 Point* p = make_point ();
735                 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
736                             (*i).x, (*i).y);
737                 fade[current].points.push_back (p);
738         }
739
740         redraw ();
741 }
742
743 void
744 CrossfadeEditor::apply ()
745 {
746         _apply_to (&xfade);
747 }
748
749 void
750 CrossfadeEditor::_apply_to (Crossfade* xf)
751 {
752         ARDOUR::Curve& in (xf->fade_in());
753         ARDOUR::Curve& out (xf->fade_out());
754
755         /* IN */
756
757
758         ARDOUR::Curve::const_iterator the_end = in.const_end();
759         --the_end;
760
761         double firstx = (*in.begin())->when;
762         double endx = (*the_end)->when;
763         double miny = in.get_min_y ();
764         double maxy = in.get_max_y ();
765
766         in.freeze ();
767         in.clear ();
768
769         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
770
771                 double when = firstx + ((*i)->x * (endx - firstx));
772                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
773                 in.add (when, value);
774         }
775
776         /* OUT */
777
778         the_end = out.const_end();
779         --the_end;
780
781         firstx = (*out.begin())->when;
782         endx = (*the_end)->when;
783         miny = out.get_min_y ();
784         maxy = out.get_max_y ();
785
786         out.freeze ();
787         out.clear ();
788
789         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
790
791                 double when = firstx + ((*i)->x * (endx - firstx));
792                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
793                 out.add (when, value);
794         }
795
796         in.thaw ();
797         out.thaw ();
798 }
799
800 void
801 CrossfadeEditor::setup (Crossfade* xfade)
802 {
803         _apply_to (xfade);
804         xfade->set_active (true);
805         xfade->fade_in().solve ();
806         xfade->fade_out().solve ();
807 }
808
809 void
810 CrossfadeEditor::clear ()
811 {
812         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
813                 delete *i;
814         }
815
816         fade[current].points.clear ();
817
818         redraw ();
819 }
820
821 void
822 CrossfadeEditor::reset ()
823 {
824         set (xfade.fade_in(),  In);
825         set (xfade.fade_out(), Out);
826 }
827
828 void
829 CrossfadeEditor::build_presets ()
830 {
831         Preset* p;
832
833         fade_in_presets = new Presets;
834         fade_out_presets = new Presets;
835
836         /* FADE OUT */
837         p = new Preset ("hiin.xpm");
838         p->push_back (PresetPoint (0, 0));
839         p->push_back (PresetPoint (0.0207373, 0.197222));
840         p->push_back (PresetPoint (0.0645161, 0.525));
841         p->push_back (PresetPoint (0.152074, 0.802778));
842         p->push_back (PresetPoint (0.276498, 0.919444));
843         p->push_back (PresetPoint (0.481567, 0.980556));
844         p->push_back (PresetPoint (0.767281, 1));
845         p->push_back (PresetPoint (1, 1));
846         fade_in_presets->push_back (p);
847         
848         p = new Preset ("loin.xpm");
849         p->push_back (PresetPoint (0, 0));
850         p->push_back (PresetPoint (0.389401, 0.0333333));
851         p->push_back (PresetPoint (0.629032, 0.0861111));
852         p->push_back (PresetPoint (0.829493, 0.233333));
853         p->push_back (PresetPoint (0.9447, 0.483333));
854         p->push_back (PresetPoint (0.976959, 0.697222));
855         p->push_back (PresetPoint (1, 1));
856         fade_in_presets->push_back (p);
857
858         p = new Preset ("regin.xpm");
859         p->push_back (PresetPoint (0, 0));
860         p->push_back (PresetPoint (0.0737327, 0.308333));
861         p->push_back (PresetPoint (0.246544, 0.658333));
862         p->push_back (PresetPoint (0.470046, 0.886111));
863         p->push_back (PresetPoint (0.652074, 0.972222));
864         p->push_back (PresetPoint (0.771889, 0.988889));
865         p->push_back (PresetPoint (1, 1));
866         fade_in_presets->push_back (p);
867
868         p = new Preset ("regin2.xpm");
869         p->push_back (PresetPoint (0, 0));
870         p->push_back (PresetPoint (0.304147, 0.0694444));
871         p->push_back (PresetPoint (0.529954, 0.152778));
872         p->push_back (PresetPoint (0.725806, 0.333333));
873         p->push_back (PresetPoint (0.847926, 0.558333));
874         p->push_back (PresetPoint (0.919355, 0.730556));
875         p->push_back (PresetPoint (1, 1));
876         fade_in_presets->push_back (p);
877
878         p = new Preset ("linin.xpm");
879         p->push_back (PresetPoint (0, 0));
880         p->push_back (PresetPoint (1, 1));
881         fade_in_presets->push_back (p);
882
883         /* FADE OUT */
884
885         p = new Preset ("hiout.xpm");
886         p->push_back (PresetPoint (0, 1));
887         p->push_back (PresetPoint (0.305556, 1));
888         p->push_back (PresetPoint (0.548611, 0.991736));
889         p->push_back (PresetPoint (0.759259, 0.931129));
890         p->push_back (PresetPoint (0.918981, 0.68595));
891         p->push_back (PresetPoint (0.976852, 0.22865));
892         p->push_back (PresetPoint (1, 0));
893         fade_out_presets->push_back (p);
894         
895         p = new Preset ("regout.xpm");
896         p->push_back (PresetPoint (0, 1));
897         p->push_back (PresetPoint (0.228111, 0.988889));
898         p->push_back (PresetPoint (0.347926, 0.972222));
899         p->push_back (PresetPoint (0.529954, 0.886111));
900         p->push_back (PresetPoint (0.753456, 0.658333));
901         p->push_back (PresetPoint (0.9262673, 0.308333));
902         p->push_back (PresetPoint (1, 0));
903         fade_out_presets->push_back (p);
904
905         p = new Preset ("loout.xpm");
906         p->push_back (PresetPoint (0, 1));
907         p->push_back (PresetPoint (0.023041, 0.697222));
908         p->push_back (PresetPoint (0.0553,   0.483333));
909         p->push_back (PresetPoint (0.170507, 0.233333));
910         p->push_back (PresetPoint (0.370968, 0.0861111));
911         p->push_back (PresetPoint (0.610599, 0.0333333));
912         p->push_back (PresetPoint (1, 0));
913         fade_out_presets->push_back (p);
914
915         p = new Preset ("regout2.xpm");
916         p->push_back (PresetPoint (0, 1));
917         p->push_back (PresetPoint (0.080645, 0.730556));
918         p->push_back (PresetPoint (0.277778, 0.289256));
919         p->push_back (PresetPoint (0.470046, 0.152778));
920         p->push_back (PresetPoint (0.695853, 0.0694444));
921         p->push_back (PresetPoint (1, 0));
922         fade_out_presets->push_back (p);
923
924         p = new Preset ("linout.xpm");
925         p->push_back (PresetPoint (0, 1));
926         p->push_back (PresetPoint (1, 0));
927         fade_out_presets->push_back (p);
928 }
929
930 void
931 CrossfadeEditor::curve_select_clicked (WhichFade wf)
932 {
933         current = wf;
934         
935         if (wf == In) {
936                 
937                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
938                         (*i)->property_wave_color() = color_map[cSelectedCrossfadeEditorWave];
939                 }
940
941                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
942                         (*i)->property_wave_color() = color_map[cCrossfadeEditorWave];
943                 }
944
945                 fade[In].line->property_fill_color_rgba() = color_map[cSelectedCrossfadeEditorLine];
946                 fade[Out].line->property_fill_color_rgba() = color_map[cCrossfadeEditorLine];
947                 fade[Out].shading->hide();
948                 fade[In].shading->show();
949
950                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
951                         (*i)->box->hide();
952                 }
953
954                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
955                         (*i)->box->show ();
956                 }
957
958                 for (vector<Button*>::iterator i = fade_out_buttons.begin(); i != fade_out_buttons.end(); ++i) {
959                         (*i)->set_sensitive (false);
960                 }
961
962                 for (vector<Button*>::iterator i = fade_in_buttons.begin(); i != fade_in_buttons.end(); ++i) {
963                         (*i)->set_sensitive (true);
964                 }
965
966         } else {
967
968                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
969                         (*i)->property_wave_color() = color_map[cCrossfadeEditorWave];
970                 }
971
972                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
973                         (*i)->property_wave_color() = color_map[cSelectedCrossfadeEditorWave];
974                 }
975
976                 fade[Out].line->property_fill_color_rgba() = color_map[cSelectedCrossfadeEditorLine];
977                 fade[In].line->property_fill_color_rgba() = color_map[cCrossfadeEditorLine];
978                 fade[In].shading->hide();
979                 fade[Out].shading->show();
980
981                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
982                         (*i)->box->hide();
983                 }
984                 
985                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
986                         (*i)->box->show();
987                 }
988
989                 for (vector<Button*>::iterator i = fade_out_buttons.begin(); i != fade_out_buttons.end(); ++i) {
990                         (*i)->set_sensitive (true);
991                 }
992
993                 for (vector<Button*>::iterator i = fade_in_buttons.begin(); i != fade_in_buttons.end(); ++i) {
994                         (*i)->set_sensitive (false);
995                 }
996
997         }
998 }
999
1000 double 
1001 CrossfadeEditor::x_coordinate (double& xfract) const
1002 {
1003         xfract = min (1.0, xfract);
1004         xfract = max (0.0, xfract);
1005     
1006         return canvas_border + (xfract * effective_width());
1007 }
1008
1009 double
1010 CrossfadeEditor::y_coordinate (double& yfract) const
1011 {
1012         yfract = min (1.0, yfract);
1013         yfract = max (0.0, yfract);
1014
1015         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1016 }
1017
1018 void
1019 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1020 {
1021         gdouble ht;
1022         uint32_t nchans = region->n_channels();
1023         guint32 color;
1024         double spu;
1025
1026         if (which == In) {
1027                 color = color_map[cSelectedCrossfadeEditorWave];
1028         } else {
1029                 color = color_map[cCrossfadeEditorWave];
1030         }
1031
1032         ht = canvas->get_allocation().get_height() / (double) nchans;
1033         spu = xfade.length() / (double) effective_width();
1034
1035         for (uint32_t n = 0; n < nchans; ++n) {
1036                 
1037                 gdouble yoff = n * ht;
1038                 
1039                 if (region->source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1040                         
1041                         WaveView* waveview = new WaveView (*(canvas->root()));
1042
1043                         waveview->property_data_src() = region.get();
1044                         waveview->property_cache_updater() =  true;
1045                         waveview->property_cache() = WaveView::create_cache();
1046                         waveview->property_channel() = n;
1047                         waveview->property_length_function() = (void*) region_length_from_c;
1048                         waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1049                         waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1050                         waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1051                         waveview->property_gain_src() = &fade[which].gain_curve;
1052                         waveview->property_x() = canvas_border;
1053                         waveview->property_y() = yoff;
1054                         waveview->property_height() = ht;
1055                         waveview->property_samples_per_unit() = spu;
1056                         waveview->property_amplitude_above_axis() = 2.0;
1057                         waveview->property_wave_color() = color;
1058                         
1059                         waveview->lower_to_bottom();
1060                         fade[which].waves.push_back (waveview);
1061                 }
1062         }
1063
1064         toplevel->lower_to_bottom();
1065 }
1066
1067 void
1068 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1069 {
1070         /* this should never be called, because the peak files for an xfade
1071            will be ready by the time we want them. but our API forces us
1072            to provide this, so ..
1073         */
1074         peaks_ready_connection.disconnect ();
1075         make_waves (r, which);
1076 }
1077
1078 void
1079 CrossfadeEditor::audition_both ()
1080 {
1081         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1082         jack_nframes_t preroll;
1083         jack_nframes_t postroll;
1084         jack_nframes_t length;
1085         jack_nframes_t left_start_offset;
1086         jack_nframes_t right_length;
1087         jack_nframes_t left_length;
1088
1089         if (preroll_button.get_active()) {
1090                 preroll = ARDOUR_UI::instance()->preroll_clock.current_duration ();
1091         } else {
1092                 preroll = 0;
1093         }
1094
1095         if (postroll_button.get_active()) {
1096                 postroll = ARDOUR_UI::instance()->postroll_clock.current_duration ();
1097         } else {
1098                 postroll = 0;
1099         }
1100
1101         if ((left_start_offset = xfade.out()->length() - xfade.length()) >= preroll) {
1102                 left_start_offset -= preroll;
1103         } 
1104
1105         length = 0;
1106
1107         if ((left_length = xfade.length()) < xfade.out()->length() - left_start_offset) {
1108                 length += postroll;
1109         }
1110
1111         right_length = xfade.length();
1112
1113         if (xfade.in()->length() - right_length < postroll) {
1114                 right_length += postroll;
1115         }
1116
1117         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.out(), left_start_offset, left_length, "xfade out", 
1118                                                                                                               0, Region::DefaultFlags, false)));
1119         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.in(), 0, right_length, "xfade in", 
1120                                                                                                                0, Region::DefaultFlags, false)));
1121         
1122         pl.add_region (left, 0);
1123         pl.add_region (right, 1+preroll);
1124
1125         /* there is only one ... */
1126
1127         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1128
1129         session.audition_playlist ();
1130 }
1131
1132 void
1133 CrossfadeEditor::audition_left_dry ()
1134 {
1135         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.out(), xfade.out()->length() - xfade.length(), xfade.length(), "xfade left", 
1136                                                                                                               0, Region::DefaultFlags, false)));
1137         
1138         session.audition_region (left);
1139 }
1140
1141 void
1142 CrossfadeEditor::audition_left ()
1143 {
1144         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1145
1146         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.out(), xfade.out()->length() - xfade.length(), xfade.length(), "xfade left", 
1147                                                                                                               0, Region::DefaultFlags, false)));
1148         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.in(), 0, xfade.length(), "xfade in", 
1149                                                                                                                0, Region::DefaultFlags, false)));
1150
1151         pl.add_region (left, 0);
1152         pl.add_region (right, 1);
1153
1154         right->set_muted (true);
1155
1156         /* there is only one ... */
1157
1158         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1159
1160         session.audition_playlist ();
1161
1162         /* memory leak for regions */
1163 }
1164
1165 void
1166 CrossfadeEditor::audition_right_dry ()
1167 {
1168         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.in(), 0, xfade.length(), "xfade in", 
1169                                                                                                                0, Region::DefaultFlags, false)));
1170         session.audition_region (right);
1171 }
1172
1173 void
1174 CrossfadeEditor::audition_right ()
1175 {
1176         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1177
1178         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.out(), xfade.out()->length() - xfade.length(), xfade.length(), "xfade out", 
1179                                                                                                               0, Region::DefaultFlags, false)));
1180                                              boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade.out(), 0, xfade.length(), "xfade out", 
1181                                                                                                                0, Region::DefaultFlags, false)));
1182
1183         pl.add_region (left, 0);
1184         pl.add_region (right, 1);
1185         
1186         left->set_muted (true);
1187
1188         /* there is only one ... */
1189
1190         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1191
1192         session.audition_playlist ();
1193 }
1194         
1195 void
1196 CrossfadeEditor::cancel_audition ()
1197 {
1198         session.cancel_audition ();
1199 }
1200
1201 void
1202 CrossfadeEditor::audition_toggled ()
1203 {
1204         bool x;
1205
1206         if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1207
1208                 if (x) {
1209                         audition_both ();
1210                 } else {
1211                         cancel_audition ();
1212                 }
1213         }
1214 }
1215
1216 void
1217 CrossfadeEditor::audition_right_toggled ()
1218 {
1219         bool x;
1220         
1221         if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1222
1223                 if (x) {
1224                         audition_right ();
1225                 } else {
1226                         cancel_audition ();
1227                 }
1228         }
1229 }
1230
1231 void
1232 CrossfadeEditor::audition_right_dry_toggled ()
1233 {
1234         bool x;
1235
1236         if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1237
1238                 if (x) {
1239                         audition_right_dry ();
1240                 } else {
1241                         cancel_audition ();
1242                 }
1243         }
1244 }
1245
1246 void
1247 CrossfadeEditor::audition_left_toggled ()
1248 {
1249         bool x;
1250
1251         if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1252
1253                 if (x) {
1254                         audition_left ();
1255                 } else {
1256                         cancel_audition ();
1257                 }
1258         }
1259 }
1260
1261 void
1262 CrossfadeEditor::audition_left_dry_toggled ()
1263 {
1264         bool x;
1265
1266         if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1267                 
1268                 if (x) {
1269                         audition_left_dry ();
1270                 } else {
1271                         cancel_audition ();
1272                 }
1273         }
1274 }