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