remove debugging for peaks ready signal, plus add new connection arg to Source::peaks...
[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 #include "color.h"
51
52 using namespace std;
53 using namespace ARDOUR;
54 using namespace Gtk;
55 using namespace sigc;
56 using namespace Editing;
57
58 #include "i18n.h"
59
60 const int32_t CrossfadeEditor::Point::size = 7;
61 const double CrossfadeEditor::canvas_border = 10;
62 CrossfadeEditor::Presets* CrossfadeEditor::fade_in_presets = 0;
63 CrossfadeEditor::Presets* CrossfadeEditor::fade_out_presets = 0;
64
65 #include "crossfade_xpms.h"
66
67 CrossfadeEditor::Half::Half ()
68         : line (0), 
69           normative_curve (0.0, 1.0, 1.0, true),
70           gain_curve (0.0, 2.0, 1.0, true)
71 {
72 }
73
74 CrossfadeEditor::CrossfadeEditor (Session& s, Crossfade& xf, double my, double mxy)
75         : ArdourDialog (_("ardour: x-fade edit")),
76           xfade (xf),
77           session (s),
78           clear_button (_("Clear")),
79           revert_button (_("Reset")),
80           audition_both_button (_("Fade")),
81           audition_left_dry_button (_("Out (dry)")),
82           audition_left_button (_("Out")),
83           audition_right_dry_button (_("In (dry)")),
84           audition_right_button (_("In")),
85
86           preroll_button (_("With Pre-roll")),
87           postroll_button (_("With Post-roll")),
88           
89           miny (my),
90           maxy (mxy),
91
92           fade_in_table (3, 3),
93           fade_out_table (3, 3),
94
95           select_in_button (_("Fade In")),
96           select_out_button (_("Fade Out"))
97 {
98         set_wmclass ("ardour_automationedit", "Ardour");
99         set_name ("CrossfadeEditWindow");
100         set_position (Gtk::WIN_POS_MOUSE);
101
102         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
103
104         RadioButtonGroup sel_but_group = select_in_button.get_group();
105         select_out_button.set_group (sel_but_group);
106         select_out_button.set_mode (false);
107         select_in_button.set_mode (false);
108
109         get_action_area()->set_layout(BUTTONBOX_SPREAD);
110         get_action_area()->pack_start(clear_button);
111         get_action_area()->pack_start(revert_button);
112         cancel_button = add_button ("Cancel", RESPONSE_CANCEL);
113         ok_button = add_button ("OK", RESPONSE_ACCEPT);
114
115         if (fade_in_presets == 0) {
116                 build_presets ();
117         }
118
119         point_grabbed = false;
120         toplevel = 0;
121
122         canvas = new ArdourCanvas::CanvasAA ();
123         canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation));
124         canvas->set_size_request (425, 200);
125         
126         toplevel = new ArdourCanvas::SimpleRect (*(canvas->root()));
127         toplevel->property_x1() =  0.0;
128         toplevel->property_y1() =  0.0;
129         toplevel->property_x2() =  10.0;
130         toplevel->property_y2() =  10.0;
131         toplevel->property_fill() =  true;
132         toplevel->property_fill_color_rgba() = color_map[cCrossfadeEditorBase];
133         toplevel->property_outline_pixels() =  0;
134         toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
135         
136         fade[Out].line = new ArdourCanvas::Line (*(canvas->root()));
137         fade[Out].line->property_width_pixels() = 1;
138         fade[Out].line->property_fill_color_rgba() = color_map[cCrossfadeEditorLine];
139                 
140         fade[Out].shading = new ArdourCanvas::Polygon (*(canvas->root()));
141         fade[Out].shading->property_fill_color_rgba() = color_map[cCrossfadeEditorLineShading];
142
143         fade[In].line = new ArdourCanvas::Line (*(canvas->root()));
144         fade[In].line->property_width_pixels() = 1;
145         fade[In].line->property_fill_color_rgba() = color_map[cCrossfadeEditorLine];
146                 
147         fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root()));
148         fade[In].shading->property_fill_color_rgba() = color_map[cCrossfadeEditorLineShading];
149         
150         fade[In].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
151         fade[In].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
152         fade[Out].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event));
153         fade[Out].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event));
154
155         select_in_button.set_name (X_("CrossfadeEditCurveButton"));
156         select_out_button.set_name (X_("CrossfadeEditCurveButton"));
157
158         select_in_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In));
159         select_out_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out));
160
161         HBox* acbox = manage (new HBox);
162         
163         audition_box.set_border_width (7);
164         audition_box.set_spacing (5);
165         audition_box.set_homogeneous (false);
166         audition_box.pack_start (audition_left_dry_button, false, false);
167         audition_box.pack_start (audition_left_button, false, false);
168         audition_box.pack_start (audition_both_button, false, false);
169         audition_box.pack_start (audition_right_button, false, false);
170         audition_box.pack_start (audition_right_dry_button, false, false);
171
172         Frame* audition_frame = manage (new Frame (_("Audition")));
173         
174         audition_frame->set_name (X_("CrossfadeEditFrame"));
175         audition_frame->add (audition_box);
176
177         acbox->pack_start (*audition_frame, true, false);
178
179         Frame* canvas_frame = manage (new Frame);
180         canvas_frame->add (*canvas);
181         canvas_frame->set_shadow_type (Gtk::SHADOW_IN);
182
183         fade_in_table.attach (select_in_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
184         fade_out_table.attach (select_out_button, 0, 2, 0, 1, Gtk::FILL|Gtk::EXPAND);
185
186         Image *pxmap;
187         Button* pbutton;
188         int row;
189         int col;
190
191         row = 1;
192         col = 0;
193
194         for (list<Preset*>::iterator i = fade_in_presets->begin(); i != fade_in_presets->end(); ++i) {
195
196                 pxmap = manage (new Image (Gdk::Pixbuf::create_from_xpm_data((*i)->xpm)));
197                 pbutton = manage (new Button);
198                 pbutton->add (*pxmap);
199                 pbutton->set_name ("CrossfadeEditButton");
200                 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
201                 fade_in_table.attach (*pbutton, col, col+1, row, row+1);
202                 fade_in_buttons.push_back (pbutton);
203
204                 col++;
205
206                 if (col == 2) {
207                         col = 0;
208                         row++;
209                 }
210         }
211
212         row = 1;
213         col = 0;
214
215         for (list<Preset*>::iterator i = fade_out_presets->begin(); i != fade_out_presets->end(); ++i) {
216
217                 pxmap = manage (new Image (Gdk::Pixbuf::create_from_xpm_data((*i)->xpm)));
218                 pbutton = manage (new Button);
219                 pbutton->add (*pxmap);
220                 pbutton->set_name ("CrossfadeEditButton");
221                 pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i));
222                 fade_out_table.attach (*pbutton, col, col+1, row, row+1);
223                 fade_out_buttons.push_back (pbutton);
224
225                 col++;
226
227                 if (col == 2) {
228                         col = 0;
229                         row++;
230                 }
231         }
232
233         clear_button.set_name ("CrossfadeEditButton");
234         revert_button.set_name ("CrossfadeEditButton");
235         ok_button->set_name ("CrossfadeEditButton");
236         cancel_button->set_name ("CrossfadeEditButton");
237         preroll_button.set_name ("CrossfadeEditButton");
238         postroll_button.set_name ("CrossfadeEditButton");
239         audition_both_button.set_name ("CrossfadeEditAuditionButton");
240         audition_left_dry_button.set_name ("CrossfadeEditAuditionButton");
241         audition_left_button.set_name ("CrossfadeEditAuditionButton");
242         audition_right_dry_button.set_name ("CrossfadeEditAuditionButton");
243         audition_right_button.set_name ("CrossfadeEditAuditionButton");
244
245         clear_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear));
246         revert_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset));
247         audition_both_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled));
248         audition_right_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled));
249         audition_right_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled));
250         audition_left_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled));
251         audition_left_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled));
252
253         roll_box.pack_start (preroll_button, false, false);
254         roll_box.pack_start (postroll_button, false, false);
255
256         Gtk::HBox* rcenter_box = manage (new HBox);
257         rcenter_box->pack_start (roll_box, true, false);
258
259         VBox* vpacker2 = manage (new (VBox));
260
261         vpacker2->set_border_width (12);
262         vpacker2->set_spacing (7);
263         vpacker2->pack_start (*acbox, false, false);
264         vpacker2->pack_start (*rcenter_box, false, false);
265
266         curve_button_box.set_spacing (7);
267         curve_button_box.pack_start (fade_out_table, false, false, 12);
268         curve_button_box.pack_start (*vpacker2, false, false, 12);
269         curve_button_box.pack_start (fade_in_table, false, false, 12);
270         
271         get_vbox()->pack_start (*canvas_frame, true, true);
272         get_vbox()->pack_start (curve_button_box, false, false);
273
274         /* button to allow hackers to check the actual curve values */
275
276 //      Button* foobut = manage (new Button ("dump"));
277 //      foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump));
278 //      vpacker.pack_start (*foobut, false, false);
279
280         current = In;
281         set (xfade.fade_in(), In);
282
283         current = Out;
284         set (xfade.fade_out(), Out);
285
286         curve_select_clicked (In);
287
288         xfade.StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed));
289
290         session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed));
291         show_all_children();
292 }
293
294 CrossfadeEditor::~CrossfadeEditor()
295 {
296         /* most objects will be destroyed when the toplevel window is. */
297
298         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
299                 delete *i;
300         }
301
302         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
303                 delete *i;
304         }
305 }
306
307 void
308 CrossfadeEditor::dump ()
309 {
310         for (AutomationList::iterator i = fade[Out].normative_curve.begin(); i != fade[Out].normative_curve.end(); ++i) {
311                 cerr << (*i)->when << ' ' << (*i)->value << endl;
312         }
313 }
314
315 void
316 CrossfadeEditor::audition_state_changed (bool yn)
317 {
318         ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn));
319
320         if (!yn) {
321                 audition_both_button.set_active (false);
322                 audition_left_button.set_active (false);
323                 audition_right_button.set_active (false);
324                 audition_left_dry_button.set_active (false);
325                 audition_right_dry_button.set_active (false);
326         }
327 }
328
329 void
330 CrossfadeEditor::set (const ARDOUR::Curve& curve, WhichFade which)
331 {
332         double firstx, endx;
333         ARDOUR::Curve::const_iterator the_end;
334
335         for (list<Point*>::iterator i = fade[which].points.begin(); i != fade[which].points.end(); ++i) {
336                         delete *i;
337         }
338         
339         fade[which].points.clear ();
340         fade[which].gain_curve.clear ();
341         fade[which].normative_curve.clear ();
342
343         if (curve.empty()) {
344                 goto out;
345         }
346         
347         the_end = curve.const_end();
348         --the_end;
349         
350         firstx = (*curve.const_begin())->when;
351         endx = (*the_end)->when;
352
353         for (ARDOUR::Curve::const_iterator i = curve.const_begin(); i != curve.const_end(); ++i) {
354                 
355                 double xfract = ((*i)->when - firstx) / (endx - firstx);
356                 double yfract = ((*i)->value - miny) / (maxy - miny);
357                 
358                 Point* p = make_point ();
359
360                 p->move_to (x_coordinate (xfract), y_coordinate (yfract),
361                             xfract, yfract);
362                 
363                 fade[which].points.push_back (p);
364         }
365
366         /* no need to sort because curve is already time-ordered */
367
368   out:
369         
370         swap (which, current);
371         redraw ();
372         swap (which, current);
373 }
374
375 bool
376 CrossfadeEditor::curve_event (GdkEvent* event)
377 {
378         /* treat it like a toplevel event */
379
380         return canvas_event (event);
381 }
382
383 bool
384 CrossfadeEditor::point_event (GdkEvent* event, Point* point)
385 {
386
387         if (point->curve != fade[current].line) {
388                 return FALSE;
389         }
390
391         switch (event->type) {
392         case GDK_BUTTON_PRESS:
393                 point_grabbed = true;
394                 break;
395         case GDK_BUTTON_RELEASE:
396                 point_grabbed = false;
397
398                 if (Keyboard::is_delete_event (&event->button)) {
399                         fade[current].points.remove (point);
400                         delete point;
401                 }
402
403                 redraw ();
404                 break;
405
406         case GDK_MOTION_NOTIFY:
407                 if (point_grabbed) {
408                         double new_x, new_y;
409
410                         /* can't drag first or last points horizontally */
411
412                         if (point == fade[current].points.front() || point == fade[current].points.back()) {
413                                 new_x = point->x;
414                         } else {
415                                 new_x = (event->motion.x - canvas_border)/effective_width();
416                         }
417
418                         new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height());
419                         point->move_to (x_coordinate (new_x), y_coordinate (new_y), 
420                                         new_x, new_y);
421                         redraw ();
422                 }
423                 break;
424         default:
425                 break;
426         }
427         return TRUE;
428 }
429
430 bool
431 CrossfadeEditor::canvas_event (GdkEvent* event)
432 {
433         switch (event->type) {
434         case GDK_BUTTON_PRESS:
435                 add_control_point ((event->button.x - canvas_border)/effective_width(),
436                                    1.0 - ((event->button.y - canvas_border)/effective_height()));
437                 return TRUE;
438                 break;
439         default:
440                 break;
441         }
442         return FALSE;
443 }
444
445 CrossfadeEditor::Point::~Point()
446 {
447         delete box;
448 }
449
450 CrossfadeEditor::Point*
451 CrossfadeEditor::make_point ()
452 {
453         Point* p = new Point;
454
455         p->box = new ArdourCanvas::SimpleRect (*(canvas->root()));
456         p->box->property_fill() = true;
457         p->box->property_fill_color_rgba() = color_map[cCrossfadeEditorPointFill];
458         p->box->property_outline_color_rgba() = color_map[cCrossfadeEditorPointOutline];
459         p->box->property_outline_pixels() = 1;
460
461         p->curve = fade[current].line;
462
463         p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p));
464         
465         return p;
466 }
467
468 void
469 CrossfadeEditor::add_control_point (double x, double y)
470 {
471         PointSorter cmp;
472
473         /* enforce end point x location */
474         
475         if (fade[current].points.empty()) {
476                 x = 0.0;
477         } else if (fade[current].points.size() == 1) {
478                 x = 1.0;
479         } 
480
481         Point* p = make_point ();
482
483         p->move_to (x_coordinate (x), y_coordinate (y), x, y);
484
485         fade[current].points.push_back (p);
486         fade[current].points.sort (cmp);
487
488         redraw ();
489 }
490
491 void
492 CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract)
493 {
494         const double half_size = rint(size/2.0);
495         double x1 = nx - half_size;
496         double x2 = nx + half_size;
497
498         box->property_x1() = x1;
499         box->property_x2() = x2;
500
501         box->property_y1() = ny - half_size;
502         box->property_y2() = ny + half_size;
503
504         x = xfract;
505         y = yfract;
506 }
507
508 void
509 CrossfadeEditor::canvas_allocation (Gtk::Allocation& alloc)
510 {
511         if (toplevel) {
512                 toplevel->property_x1() = 0.0;
513                 toplevel->property_y1() = 0.0;
514                 toplevel->property_x2() = (double) canvas->get_allocation().get_width() + canvas_border;
515                 toplevel->property_y2() = (double) canvas->get_allocation().get_height() + canvas_border;
516         }
517         
518         canvas->set_scroll_region (0.0, 0.0, 
519                                    canvas->get_allocation().get_width(), 
520                                    canvas->get_allocation().get_height());
521
522         Point* end = make_point ();
523         PointSorter cmp;
524
525         if (fade[In].points.size() > 1) {
526                 Point* old_end = fade[In].points.back();
527                 fade[In].points.pop_back ();
528                 end->move_to (x_coordinate (old_end->x),
529                               y_coordinate (old_end->y),
530                               old_end->x, old_end->y);
531                 delete old_end;
532         } else {
533                 double x = 1.0;
534                 double y = 0.5;
535                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
536
537         }
538
539         fade[In].points.push_back (end);
540         fade[In].points.sort (cmp);
541
542         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
543                 (*i)->move_to (x_coordinate((*i)->x), y_coordinate((*i)->y),
544                                (*i)->x, (*i)->y);
545         }
546         
547         end = make_point ();
548         
549         if (fade[Out].points.size() > 1) {
550                 Point* old_end = fade[Out].points.back();
551                 fade[Out].points.pop_back ();
552                 end->move_to (x_coordinate (old_end->x),
553                               y_coordinate (old_end->y),
554                               old_end->x, old_end->y);
555                 delete old_end;
556         } else {
557                 double x = 1.0;
558                 double y = 0.5;
559                 end->move_to (x_coordinate (x), y_coordinate (y), x, y);
560
561         }
562
563         fade[Out].points.push_back (end);
564         fade[Out].points.sort (cmp);
565
566         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
567                 (*i)->move_to (x_coordinate ((*i)->x),
568                                y_coordinate ((*i)->y),
569                                (*i)->x, (*i)->y);
570         }
571         
572         WhichFade old_current = current;
573         current = In;
574         redraw ();
575         current = Out;
576         redraw ();
577         current = old_current;
578
579         double spu = xfade.length() / (double) effective_width();
580
581         if (fade[In].waves.empty()) {
582                 make_waves (xfade.in(), In);
583         }
584
585         if (fade[Out].waves.empty()) {
586                 make_waves (xfade.out(), Out);
587         }
588
589         double ht;
590         vector<ArdourCanvas::WaveView*>::iterator i;
591         uint32_t n;
592
593         ht = canvas->get_allocation().get_height() / xfade.in().n_channels();
594
595         for (n = 0, i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i, ++n) {
596                 double yoff;
597
598                 yoff = n * ht;
599
600                 (*i)->property_y() = yoff;
601                 (*i)->property_height() = ht;
602                 (*i)->property_samples_per_unit() = spu;
603         }
604
605         ht = canvas->get_allocation().get_height() / xfade.out().n_channels();
606
607         for (n = 0, i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i, ++n) {
608                 double yoff;
609
610                 yoff = n * ht;
611
612                 (*i)->property_y() = yoff;
613                 (*i)->property_height() = ht;
614                 (*i)->property_samples_per_unit() = spu;
615         }
616
617 }
618
619
620 void
621 CrossfadeEditor::xfade_changed (Change ignored)
622 {
623         set (xfade.fade_in(), In);
624         set (xfade.fade_out(), Out);
625 }
626
627 void
628 CrossfadeEditor::redraw ()
629 {
630         if (canvas->get_allocation().get_width() < 2) {
631                 return;
632         }
633
634         jack_nframes_t len = xfade.length ();
635
636         fade[current].normative_curve.clear ();
637         fade[current].gain_curve.clear ();
638
639         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
640                 fade[current].normative_curve.add ((*i)->x, (*i)->y);
641                 fade[current].gain_curve.add (((*i)->x * len), (*i)->y);
642         }
643
644         size_t npoints = (size_t) effective_width();
645         float vec[npoints];
646
647         fade[current].normative_curve.get_vector (0, 1.0, vec, npoints);
648         
649         ArdourCanvas::Points pts;
650         ArdourCanvas::Points spts;
651
652         while (pts.size() < npoints) {
653                 pts.push_back (Gnome::Art::Point (0,0));
654         }
655
656         while (spts.size() < npoints + 3) {
657                 spts.push_back (Gnome::Art::Point (0,0));
658         }
659
660         /* the shade coordinates *MUST* be in anti-clockwise order.
661          */
662
663         if (current == In) {
664
665                 /* lower left */
666
667                 spts[0].set_x (canvas_border);
668                 spts[0].set_y (effective_height() + canvas_border);
669
670                 /* lower right */
671
672                 spts[1].set_x (effective_width() + canvas_border);
673                 spts[1].set_y (effective_height() + canvas_border);
674
675                 /* upper right */
676
677                 spts[2].set_x (effective_width() + canvas_border);
678                 spts[2].set_y (canvas_border);
679
680                 
681         } else {
682
683                 /*  upper left */
684                 
685                 spts[0].set_x (canvas_border);
686                 spts[0].set_y (canvas_border);
687
688                 /* lower left */
689
690                 spts[1].set_x (canvas_border);
691                 spts[1].set_y (effective_height() + canvas_border);
692
693                 /* lower right */
694
695                 spts[2].set_x (effective_width() + canvas_border);
696                 spts[2].set_y (effective_height() + canvas_border);
697
698         }
699
700         // GTK2FIX some odd math to fix up here
701
702         size_t last_spt = (npoints + 3) - 1;
703
704         for (size_t i = 0; i < npoints; ++i) {
705
706                 double y = vec[i];
707                 
708                 pts[i].set_x (canvas_border + i);
709                 pts[i].set_y  (y_coordinate (y));
710
711                 spts[last_spt - i].set_x (canvas_border + i);
712                 spts[last_spt - i].set_y (pts[i].get_y());
713         }
714
715         fade[current].line->property_points() = pts;
716         fade[current].shading->property_points() = spts;
717
718         for (vector<ArdourCanvas::WaveView*>::iterator i = fade[current].waves.begin(); i != fade[current].waves.end(); ++i) {
719                 (*i)->property_gain_src() = &fade[current].gain_curve;
720         }
721 }
722
723 void
724 CrossfadeEditor::apply_preset (Preset *preset)
725 {
726         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
727                 delete *i;
728         }
729
730         fade[current].points.clear ();
731
732         for (Preset::iterator i = preset->begin(); i != preset->end(); ++i) {
733                 Point* p = make_point ();
734                 p->move_to (x_coordinate ((*i).x), y_coordinate ((*i).y),
735                             (*i).x, (*i).y);
736                 fade[current].points.push_back (p);
737         }
738
739         redraw ();
740 }
741
742 void
743 CrossfadeEditor::apply ()
744 {
745         _apply_to (&xfade);
746 }
747
748 void
749 CrossfadeEditor::_apply_to (Crossfade* xf)
750 {
751         ARDOUR::Curve& in (xf->fade_in());
752         ARDOUR::Curve& out (xf->fade_out());
753
754         /* IN */
755
756
757         ARDOUR::Curve::const_iterator the_end = in.const_end();
758         --the_end;
759
760         double firstx = (*in.begin())->when;
761         double endx = (*the_end)->when;
762         double miny = in.get_min_y ();
763         double maxy = in.get_max_y ();
764
765         in.freeze ();
766         in.clear ();
767
768         for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
769
770                 double when = firstx + ((*i)->x * (endx - firstx));
771                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
772                 in.add (when, value);
773         }
774
775         /* OUT */
776
777         the_end = out.const_end();
778         --the_end;
779
780         firstx = (*out.begin())->when;
781         endx = (*the_end)->when;
782         miny = out.get_min_y ();
783         maxy = out.get_max_y ();
784
785         out.freeze ();
786         out.clear ();
787
788         for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
789
790                 double when = firstx + ((*i)->x * (endx - firstx));
791                 double value = (*i)->y; // miny + ((*i)->y * (maxy - miny));
792                 out.add (when, value);
793         }
794
795         in.thaw ();
796         out.thaw ();
797 }
798
799 void
800 CrossfadeEditor::setup (Crossfade* xfade)
801 {
802         _apply_to (xfade);
803         xfade->set_active (true);
804         xfade->fade_in().solve ();
805         xfade->fade_out().solve ();
806 }
807
808 void
809 CrossfadeEditor::clear ()
810 {
811         for (list<Point*>::iterator i = fade[current].points.begin(); i != fade[current].points.end(); ++i) {
812                 delete *i;
813         }
814
815         fade[current].points.clear ();
816
817         redraw ();
818 }
819
820 void
821 CrossfadeEditor::reset ()
822 {
823         set (xfade.fade_in(),  In);
824         set (xfade.fade_out(), Out);
825 }
826
827 void
828 CrossfadeEditor::build_presets ()
829 {
830         Preset* p;
831
832         fade_in_presets = new Presets;
833         fade_out_presets = new Presets;
834
835         /* FADE OUT */
836
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->hide();
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 (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;
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 (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         AudioRegion* left = new AudioRegion (xfade.out(), left_start_offset, left_length, "xfade out", 
1118                                              0, Region::DefaultFlags, false);
1119         AudioRegion* right = new AudioRegion (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         AudioRegion* left = new AudioRegion (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         AudioRegion* left = new AudioRegion (xfade.out(), xfade.out().length() - xfade.length(), xfade.length(), "xfade left", 
1147                                              0, Region::DefaultFlags, false);
1148         AudioRegion* right = new AudioRegion (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         AudioRegion* right = new AudioRegion (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         AudioRegion* left = new AudioRegion (xfade.out(), xfade.out().length() - xfade.length(), xfade.length(), "xfade out", 
1179                                              0, Region::DefaultFlags, false);
1180         AudioRegion* right = new AudioRegion (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 }