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