remove debug output from last commit
[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 */
19
20 #include <cmath>
21
22 #include <sigc++/bind.h>
23
24 #include <gtkmm/frame.h>
25 #include <gtkmm/image.h>
26 #include <gtkmm/scrolledwindow.h>
27
28 #include <libgnomecanvasmm/line.h>
29
30 #include <ardour/automation_event.h>
31 #include <ardour/curve.h>
32 #include <ardour/crossfade.h>
33 #include <ardour/session.h>
34 #include <ardour/auditioner.h>
35 #include <ardour/audioplaylist.h>
36 #include <ardour/audiosource.h>
37 #include <ardour/playlist_templates.h>
38 #include <ardour/region_factory.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, boost::shared_ptr<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 (X_("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_icon ((*i)->image_name)));
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_icon ((*i)->image_name)));
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         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         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 (boost::shared_ptr<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 (boost::shared_ptr<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 = new Preset ("crossfade_in_fast-cut");
836         p->push_back (PresetPoint (0, 0));
837         p->push_back (PresetPoint (0.0207373, 0.197222));
838         p->push_back (PresetPoint (0.0645161, 0.525));
839         p->push_back (PresetPoint (0.152074, 0.802778));
840         p->push_back (PresetPoint (0.276498, 0.919444));
841         p->push_back (PresetPoint (0.481567, 0.980556));
842         p->push_back (PresetPoint (0.767281, 1));
843         p->push_back (PresetPoint (1, 1));
844         fade_in_presets->push_back (p);
845         
846         // p = new Preset ("loin.xpm");
847         p = new Preset ("crossfade_in_transition");
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 = new Preset ("crossfade_in_constant");
859         p->push_back (PresetPoint (0, 0));
860         p->push_back (PresetPoint (0.0737327, 0.308333));
861         p->push_back (PresetPoint (0.246544, 0.658333));
862         p->push_back (PresetPoint (0.470046, 0.886111));
863         p->push_back (PresetPoint (0.652074, 0.972222));
864         p->push_back (PresetPoint (0.771889, 0.988889));
865         p->push_back (PresetPoint (1, 1));
866         fade_in_presets->push_back (p);
867
868         // p = new Preset ("regin2.xpm");
869         p = new Preset ("crossfade_in_slow-cut");
870         p->push_back (PresetPoint (0, 0));
871         p->push_back (PresetPoint (0.304147, 0.0694444));
872         p->push_back (PresetPoint (0.529954, 0.152778));
873         p->push_back (PresetPoint (0.725806, 0.333333));
874         p->push_back (PresetPoint (0.847926, 0.558333));
875         p->push_back (PresetPoint (0.919355, 0.730556));
876         p->push_back (PresetPoint (1, 1));
877         fade_in_presets->push_back (p);
878
879         // p = new Preset ("linin.xpm");
880         p = new Preset ("crossfade_in_dipped");
881         p->push_back (PresetPoint (0, 0));
882         p->push_back (PresetPoint (1, 1));
883         fade_in_presets->push_back (p);
884
885         /* FADE OUT */
886
887         // p = new Preset ("hiout.xpm");
888         p = new Preset ("crossfade_out_fast-cut");
889         p->push_back (PresetPoint (0, 1));
890         p->push_back (PresetPoint (0.305556, 1));
891         p->push_back (PresetPoint (0.548611, 0.991736));
892         p->push_back (PresetPoint (0.759259, 0.931129));
893         p->push_back (PresetPoint (0.918981, 0.68595));
894         p->push_back (PresetPoint (0.976852, 0.22865));
895         p->push_back (PresetPoint (1, 0));
896         fade_out_presets->push_back (p);
897         
898         // p = new Preset ("regout.xpm");
899         p = new Preset ("crossfade_out_constant");
900         p->push_back (PresetPoint (0, 1));
901         p->push_back (PresetPoint (0.228111, 0.988889));
902         p->push_back (PresetPoint (0.347926, 0.972222));
903         p->push_back (PresetPoint (0.529954, 0.886111));
904         p->push_back (PresetPoint (0.753456, 0.658333));
905         p->push_back (PresetPoint (0.9262673, 0.308333));
906         p->push_back (PresetPoint (1, 0));
907         fade_out_presets->push_back (p);
908
909         // p = new Preset ("loout.xpm");
910         p = new Preset ("crossfade_out_transition");
911         p->push_back (PresetPoint (0, 1));
912         p->push_back (PresetPoint (0.023041, 0.697222));
913         p->push_back (PresetPoint (0.0553,   0.483333));
914         p->push_back (PresetPoint (0.170507, 0.233333));
915         p->push_back (PresetPoint (0.370968, 0.0861111));
916         p->push_back (PresetPoint (0.610599, 0.0333333));
917         p->push_back (PresetPoint (1, 0));
918         fade_out_presets->push_back (p);
919
920         // p = new Preset ("regout2.xpm");
921         p = new Preset ("crossfade_out_slow-fade");
922         p->push_back (PresetPoint (0, 1));
923         p->push_back (PresetPoint (0.080645, 0.730556));
924         p->push_back (PresetPoint (0.277778, 0.289256));
925         p->push_back (PresetPoint (0.470046, 0.152778));
926         p->push_back (PresetPoint (0.695853, 0.0694444));
927         p->push_back (PresetPoint (1, 0));
928         fade_out_presets->push_back (p);
929
930         // p = new Preset ("linout.xpm");
931         p = new Preset ("crossfade_out_dipped");
932         p->push_back (PresetPoint (0, 1));
933         p->push_back (PresetPoint (1, 0));
934         fade_out_presets->push_back (p);
935 }
936
937 void
938 CrossfadeEditor::curve_select_clicked (WhichFade wf)
939 {
940         current = wf;
941         
942         if (wf == In) {
943                 
944                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
945                         (*i)->property_wave_color() = color_map[cSelectedCrossfadeEditorWave];
946                 }
947
948                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
949                         (*i)->property_wave_color() = color_map[cCrossfadeEditorWave];
950                 }
951
952                 fade[In].line->property_fill_color_rgba() = color_map[cSelectedCrossfadeEditorLine];
953                 fade[Out].line->property_fill_color_rgba() = color_map[cCrossfadeEditorLine];
954                 fade[Out].shading->hide();
955                 fade[In].shading->show();
956
957                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
958                         (*i)->box->hide();
959                 }
960
961                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
962                         (*i)->box->show ();
963                 }
964
965                 for (vector<Button*>::iterator i = fade_out_buttons.begin(); i != fade_out_buttons.end(); ++i) {
966                         (*i)->set_sensitive (false);
967                 }
968
969                 for (vector<Button*>::iterator i = fade_in_buttons.begin(); i != fade_in_buttons.end(); ++i) {
970                         (*i)->set_sensitive (true);
971                 }
972
973         } else {
974
975                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[In].waves.begin(); i != fade[In].waves.end(); ++i) {
976                         (*i)->property_wave_color() = color_map[cCrossfadeEditorWave];
977                 }
978
979                 for (vector<ArdourCanvas::WaveView*>::iterator i = fade[Out].waves.begin(); i != fade[Out].waves.end(); ++i) {
980                         (*i)->property_wave_color() = color_map[cSelectedCrossfadeEditorWave];
981                 }
982
983                 fade[Out].line->property_fill_color_rgba() = color_map[cSelectedCrossfadeEditorLine];
984                 fade[In].line->property_fill_color_rgba() = color_map[cCrossfadeEditorLine];
985                 fade[In].shading->hide();
986                 fade[Out].shading->show();
987
988                 for (list<Point*>::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) {
989                         (*i)->box->hide();
990                 }
991                 
992                 for (list<Point*>::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) {
993                         (*i)->box->show();
994                 }
995
996                 for (vector<Button*>::iterator i = fade_out_buttons.begin(); i != fade_out_buttons.end(); ++i) {
997                         (*i)->set_sensitive (true);
998                 }
999
1000                 for (vector<Button*>::iterator i = fade_in_buttons.begin(); i != fade_in_buttons.end(); ++i) {
1001                         (*i)->set_sensitive (false);
1002                 }
1003
1004         }
1005 }
1006
1007 double 
1008 CrossfadeEditor::x_coordinate (double& xfract) const
1009 {
1010         xfract = min (1.0, xfract);
1011         xfract = max (0.0, xfract);
1012     
1013         return canvas_border + (xfract * effective_width());
1014 }
1015
1016 double
1017 CrossfadeEditor::y_coordinate (double& yfract) const
1018 {
1019         yfract = min (1.0, yfract);
1020         yfract = max (0.0, yfract);
1021
1022         return (canvas->get_allocation().get_height() - (canvas_border)) - (yfract * effective_height());
1023 }
1024
1025 void
1026 CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade which)
1027 {
1028         gdouble ht;
1029         uint32_t nchans = region->n_channels();
1030         guint32 color;
1031         double spu;
1032
1033         if (which == In) {
1034                 color = color_map[cSelectedCrossfadeEditorWave];
1035         } else {
1036                 color = color_map[cCrossfadeEditorWave];
1037         }
1038
1039         ht = canvas->get_allocation().get_height() / (double) nchans;
1040         spu = xfade->length() / (double) effective_width();
1041
1042         for (uint32_t n = 0; n < nchans; ++n) {
1043                 
1044                 gdouble yoff = n * ht;
1045                 
1046                 if (region->source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) {
1047                         
1048                         WaveView* waveview = new WaveView (*(canvas->root()));
1049
1050                         waveview->property_data_src() = region.get();
1051                         waveview->property_cache_updater() =  true;
1052                         waveview->property_cache() = WaveView::create_cache();
1053                         waveview->property_channel() = n;
1054                         waveview->property_length_function() = (void*) region_length_from_c;
1055                         waveview->property_sourcefile_length_function() = (void*) sourcefile_length_from_c;
1056                         waveview->property_peak_function() = (void*) region_read_peaks_from_c;
1057                         waveview->property_gain_function() = (void*) curve_get_vector_from_c;
1058                         waveview->property_gain_src() = &fade[which].gain_curve;
1059                         waveview->property_x() = canvas_border;
1060                         waveview->property_y() = yoff;
1061                         waveview->property_height() = ht;
1062                         waveview->property_samples_per_unit() = spu;
1063                         waveview->property_amplitude_above_axis() = 2.0;
1064                         waveview->property_wave_color() = color;
1065                         
1066                         waveview->lower_to_bottom();
1067                         fade[which].waves.push_back (waveview);
1068                 }
1069         }
1070
1071         toplevel->lower_to_bottom();
1072 }
1073
1074 void
1075 CrossfadeEditor::peaks_ready (boost::shared_ptr<AudioRegion> r, WhichFade which)
1076 {
1077         /* this should never be called, because the peak files for an xfade
1078            will be ready by the time we want them. but our API forces us
1079            to provide this, so ..
1080         */
1081         peaks_ready_connection.disconnect ();
1082         make_waves (r, which);
1083 }
1084
1085 void
1086 CrossfadeEditor::audition_both ()
1087 {
1088         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1089         nframes_t preroll;
1090         nframes_t postroll;
1091         nframes_t length;
1092         nframes_t left_start_offset;
1093         nframes_t right_length;
1094         nframes_t left_length;
1095
1096         if (preroll_button.get_active()) {
1097                 preroll = ARDOUR_UI::instance()->preroll_clock.current_duration ();
1098         } else {
1099                 preroll = 0;
1100         }
1101
1102         if (postroll_button.get_active()) {
1103                 postroll = ARDOUR_UI::instance()->postroll_clock.current_duration ();
1104         } else {
1105                 postroll = 0;
1106         }
1107
1108         if ((left_start_offset = xfade->out()->length() - xfade->length()) >= preroll) {
1109                 left_start_offset -= preroll;
1110         } 
1111
1112         length = 0;
1113
1114         if ((left_length = xfade->length()) < xfade->out()->length() - left_start_offset) {
1115                 length += postroll;
1116         }
1117
1118         right_length = xfade->length();
1119
1120         if (xfade->in()->length() - right_length < postroll) {
1121                 right_length += postroll;
1122         }
1123
1124         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out", 
1125                                                                                                               0, Region::DefaultFlags, false)));
1126         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, right_length, "xfade in", 
1127                                                                                                                0, Region::DefaultFlags, false)));
1128         
1129         pl.add_region (left, 0);
1130         pl.add_region (right, 1+preroll);
1131
1132         /* there is only one ... */
1133
1134         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1135
1136         session.audition_playlist ();
1137 }
1138
1139 void
1140 CrossfadeEditor::audition_left_dry ()
1141 {
1142         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left", 
1143                                                                                                               0, Region::DefaultFlags, false)));
1144         
1145         session.audition_region (left);
1146 }
1147
1148 void
1149 CrossfadeEditor::audition_left ()
1150 {
1151         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1152
1153         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left", 
1154                                                                                                               0, Region::DefaultFlags, false)));
1155         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in", 
1156                                                                                                                0, Region::DefaultFlags, false)));
1157
1158         pl.add_region (left, 0);
1159         pl.add_region (right, 1);
1160
1161         right->set_muted (true);
1162
1163         /* there is only one ... */
1164
1165         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1166
1167         session.audition_playlist ();
1168
1169         /* memory leak for regions */
1170 }
1171
1172 void
1173 CrossfadeEditor::audition_right_dry ()
1174 {
1175         boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in", 
1176                                                                                                                0, Region::DefaultFlags, false)));
1177         session.audition_region (right);
1178 }
1179
1180 void
1181 CrossfadeEditor::audition_right ()
1182 {
1183         AudioPlaylist& pl (session.the_auditioner()->prepare_playlist());
1184
1185         boost::shared_ptr<AudioRegion> left (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade out", 
1186                                                                                                               0, Region::DefaultFlags, false)));
1187                                              boost::shared_ptr<AudioRegion> right (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (xfade->out(), 0, xfade->length(), "xfade out", 
1188                                                                                                                0, Region::DefaultFlags, false)));
1189
1190         pl.add_region (left, 0);
1191         pl.add_region (right, 1);
1192         
1193         left->set_muted (true);
1194
1195         /* there is only one ... */
1196
1197         pl.foreach_crossfade (this, &CrossfadeEditor::setup);
1198
1199         session.audition_playlist ();
1200 }
1201         
1202 void
1203 CrossfadeEditor::cancel_audition ()
1204 {
1205         session.cancel_audition ();
1206 }
1207
1208 void
1209 CrossfadeEditor::audition_toggled ()
1210 {
1211         bool x;
1212
1213         if ((x = audition_both_button.get_active ()) != session.is_auditioning()) {
1214
1215                 if (x) {
1216                         audition_both ();
1217                 } else {
1218                         cancel_audition ();
1219                 }
1220         }
1221 }
1222
1223 void
1224 CrossfadeEditor::audition_right_toggled ()
1225 {
1226         bool x;
1227         
1228         if ((x = audition_right_button.get_active ()) != session.is_auditioning()) {
1229
1230                 if (x) {
1231                         audition_right ();
1232                 } else {
1233                         cancel_audition ();
1234                 }
1235         }
1236 }
1237
1238 void
1239 CrossfadeEditor::audition_right_dry_toggled ()
1240 {
1241         bool x;
1242
1243         if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) {
1244
1245                 if (x) {
1246                         audition_right_dry ();
1247                 } else {
1248                         cancel_audition ();
1249                 }
1250         }
1251 }
1252
1253 void
1254 CrossfadeEditor::audition_left_toggled ()
1255 {
1256         bool x;
1257
1258         if ((x = audition_left_button.get_active ()) != session.is_auditioning()) {
1259
1260                 if (x) {
1261                         audition_left ();
1262                 } else {
1263                         cancel_audition ();
1264                 }
1265         }
1266 }
1267
1268 void
1269 CrossfadeEditor::audition_left_dry_toggled ()
1270 {
1271         bool x;
1272
1273         if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) {
1274                 
1275                 if (x) {
1276                         audition_left_dry ();
1277                 } else {
1278                         cancel_audition ();
1279                 }
1280         }
1281 }