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