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