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