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