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