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