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