X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fcrossfade_edit.cc;h=da833b8ea452f6eb40d87705c91f4a03f7b8fb3e;hb=eb1d3e48c822b4235e8dbf58e645ea733e4523b0;hp=c20b7c492ad93e53125a35f54c293f56bee0d032;hpb=7703f0a76a82ec3fe21609c396ebf2f950803bf9;p=ardour.git diff --git a/gtk2_ardour/crossfade_edit.cc b/gtk2_ardour/crossfade_edit.cc index c20b7c492a..da833b8ea4 100644 --- a/gtk2_ardour/crossfade_edit.cc +++ b/gtk2_ardour/crossfade_edit.cc @@ -27,6 +27,7 @@ #include +#include "pbd/memento_command.h" #include "ardour/automation_list.h" #include "evoral/Curve.hpp" #include "ardour/crossfade.h" @@ -36,6 +37,7 @@ #include "ardour/audiosource.h" #include "ardour/region_factory.h" #include "ardour/profile.h" +#include "ardour/crossfade_binder.h" #include @@ -54,7 +56,6 @@ using namespace std; using namespace ARDOUR; using namespace PBD; using namespace Gtk; -using namespace sigc; using namespace Editing; using Gtkmm2ext::Keyboard; @@ -73,10 +74,9 @@ CrossfadeEditor::Half::Half () { } -CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, double my, double mxy) - : ArdourDialog (_("ardour: x-fade edit")), +CrossfadeEditor::CrossfadeEditor (Session* s, boost::shared_ptr xf, double my, double mxy) + : ArdourDialog (_("Edit Crossfade")), xfade (xf), - session (s), clear_button (_("Clear")), revert_button (_("Reset")), audition_both_button (_("Fade")), @@ -95,9 +95,14 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d fade_out_table (3, 3), select_in_button (_("Fade In")), - select_out_button (_("Fade Out")) + select_out_button (_("Fade Out")), + + _peaks_ready_connection (0) + { - set_wmclass (X_("ardour_automationedit"), "Ardour"); + set_session (s); + + set_wmclass (X_("ardour_automationedit"), PROGRAM_NAME); set_name ("CrossfadeEditWindow"); set_position (Gtk::WIN_POS_MOUSE); @@ -124,7 +129,7 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d toplevel = 0; canvas = new ArdourCanvas::CanvasAA (); - canvas->signal_size_allocate().connect (mem_fun(*this, &CrossfadeEditor::canvas_allocation)); + canvas->signal_size_allocate().connect (sigc::mem_fun(*this, &CrossfadeEditor::canvas_allocation)); canvas->set_size_request (425, 200); toplevel = new ArdourCanvas::SimpleRect (*(canvas->root())); @@ -135,7 +140,7 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d toplevel->property_fill() = true; toplevel->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorBase.get(); toplevel->property_outline_pixels() = 0; - toplevel->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event)); + toplevel->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event)); fade[Out].line = new ArdourCanvas::Line (*(canvas->root())); fade[Out].line->property_width_pixels() = 1; @@ -151,16 +156,16 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d fade[In].shading = new ArdourCanvas::Polygon (*(canvas->root())); fade[In].shading->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeEditorLineShading.get(); - fade[In].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event)); - fade[In].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event)); - fade[Out].shading->signal_event().connect (mem_fun (*this, &CrossfadeEditor::canvas_event)); - fade[Out].line->signal_event().connect (mem_fun (*this, &CrossfadeEditor::curve_event)); + fade[In].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event)); + fade[In].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event)); + fade[Out].shading->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::canvas_event)); + fade[Out].line->signal_event().connect (sigc::mem_fun (*this, &CrossfadeEditor::curve_event)); select_in_button.set_name (X_("CrossfadeEditCurveButton")); select_out_button.set_name (X_("CrossfadeEditCurveButton")); - select_in_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In)); - select_out_button.signal_clicked().connect (bind (mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out)); + select_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), In)); + select_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::curve_select_clicked), Out)); HBox* acbox = manage (new HBox); @@ -201,7 +206,7 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d pbutton = manage (new Button); pbutton->add (*pxmap); pbutton->set_name ("CrossfadeEditButton"); - pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i)); + pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i)); ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, ""); fade_in_table.attach (*pbutton, col, col+1, row, row+1); fade_in_buttons.push_back (pbutton); @@ -223,7 +228,7 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d pbutton = manage (new Button); pbutton->add (*pxmap); pbutton->set_name ("CrossfadeEditButton"); - pbutton->signal_clicked().connect (bind (mem_fun(*this, &CrossfadeEditor::apply_preset), *i)); + pbutton->signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &CrossfadeEditor::apply_preset), *i)); ARDOUR_UI::instance()->set_tip (pbutton, (*i)->name, ""); fade_out_table.attach (*pbutton, col, col+1, row, row+1); fade_out_buttons.push_back (pbutton); @@ -248,13 +253,13 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d audition_right_dry_button.set_name ("CrossfadeEditAuditionButton"); audition_right_button.set_name ("CrossfadeEditAuditionButton"); - clear_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::clear)); - revert_button.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::reset)); - audition_both_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_toggled)); - audition_right_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_toggled)); - audition_right_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled)); - audition_left_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_toggled)); - audition_left_dry_button.signal_toggled().connect (mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled)); + clear_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::clear)); + revert_button.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::reset)); + audition_both_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_toggled)); + audition_right_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_toggled)); + audition_right_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_right_dry_toggled)); + audition_left_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_toggled)); + audition_left_dry_button.signal_toggled().connect (sigc::mem_fun(*this, &CrossfadeEditor::audition_left_dry_toggled)); roll_box.pack_start (preroll_button, false, false); roll_box.pack_start (postroll_button, false, false); @@ -280,7 +285,7 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d /* button to allow hackers to check the actual curve values */ // Button* foobut = manage (new Button ("dump")); -// foobut-.signal_clicked().connect (mem_fun(*this, &CrossfadeEditor::dump)); +// foobut-.signal_clicked().connect (sigc::mem_fun(*this, &CrossfadeEditor::dump)); // vpacker.pack_start (*foobut, false, false); current = In; @@ -291,9 +296,9 @@ CrossfadeEditor::CrossfadeEditor (Session& s, boost::shared_ptr xf, d curve_select_clicked (In); - xfade->StateChanged.connect (mem_fun(*this, &CrossfadeEditor::xfade_changed)); + xfade->PropertyChanged.connect (state_connection, invalidator (*this), ui_bind (&CrossfadeEditor::xfade_changed, this, _1), gui_context()); - session.AuditionActive.connect (mem_fun(*this, &CrossfadeEditor::audition_state_changed)); + _session->AuditionActive.connect (_session_connections, invalidator (*this), ui_bind (&CrossfadeEditor::audition_state_changed, this, _1), gui_context()); show_all_children(); } @@ -308,6 +313,8 @@ CrossfadeEditor::~CrossfadeEditor() for (list::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) { delete *i; } + + delete _peaks_ready_connection; } void @@ -321,7 +328,7 @@ CrossfadeEditor::dump () void CrossfadeEditor::audition_state_changed (bool yn) { - ENSURE_GUI_THREAD (bind (mem_fun(*this, &CrossfadeEditor::audition_state_changed), yn)); + ENSURE_GUI_THREAD (*this, &CrossfadeEditor::audition_state_changed, yn) if (!yn) { audition_both_button.set_active (false); @@ -413,15 +420,16 @@ CrossfadeEditor::point_event (GdkEvent* event, Point* point) if (point_grabbed) { double new_x, new_y; - /* can't drag first or last points horizontally */ + /* can't drag first or last points horizontally or vertically */ if (point == fade[current].points.front() || point == fade[current].points.back()) { new_x = point->x; + new_y = point->y; } else { new_x = (event->motion.x - canvas_border)/effective_width(); + new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height()); } - new_y = 1.0 - ((event->motion.y - canvas_border)/effective_height()); point->move_to (x_coordinate (new_x), y_coordinate (new_y), new_x, new_y); redraw (); @@ -466,7 +474,7 @@ CrossfadeEditor::make_point () p->curve = fade[current].line; - p->box->signal_event().connect (bind (mem_fun (*this, &CrossfadeEditor::point_event), p)); + p->box->signal_event().connect (sigc::bind (sigc::mem_fun (*this, &CrossfadeEditor::point_event), p)); return p; } @@ -497,6 +505,18 @@ CrossfadeEditor::add_control_point (double x, double y) void CrossfadeEditor::Point::move_to (double nx, double ny, double xfract, double yfract) { + if ( xfract < 0.0 ) { + xfract = 0.0; + } else if ( xfract > 1.0 ) { + xfract = 1.0; + } + + if ( yfract < 0.0 ) { + yfract = 0.0; + } else if ( yfract > 1.0 ) { + yfract = 1.0; + } + const double half_size = rint(size/2.0); double x1 = nx - half_size; double x2 = nx + half_size; @@ -624,7 +644,7 @@ CrossfadeEditor::canvas_allocation (Gtk::Allocation& /*alloc*/) void -CrossfadeEditor::xfade_changed (Change) +CrossfadeEditor::xfade_changed (const PropertyChange&) { set (xfade->fade_in(), In); set (xfade->fade_out(), Out); @@ -637,7 +657,7 @@ CrossfadeEditor::redraw () return; } - nframes_t len = xfade->length (); + framecnt_t len = xfade->length (); fade[current].normative_curve.clear (); fade[current].gain_curve.clear (); @@ -766,7 +786,20 @@ CrossfadeEditor::apply_preset (Preset *preset) void CrossfadeEditor::apply () { + _session->begin_reversible_command (_("Edit crossfade")); + + XMLNode& before = xfade->get_state (); + _apply_to (xfade); + + _session->add_command ( + new MementoCommand ( + new ARDOUR::CrossfadeBinder (_session->playlists, xfade->id ()), + &before, &xfade->get_state () + ) + ); + + _session->commit_reversible_command (); } void @@ -783,8 +816,6 @@ CrossfadeEditor::_apply_to (boost::shared_ptr xf) double firstx = (*in.begin())->when; double endx = (*the_end)->when; - double miny = in.get_min_y (); - double maxy = in.get_max_y (); in.freeze (); in.clear (); @@ -792,7 +823,7 @@ CrossfadeEditor::_apply_to (boost::shared_ptr xf) for (list::iterator i = fade[In].points.begin(); i != fade[In].points.end(); ++i) { double when = firstx + ((*i)->x * (endx - firstx)); - double value = (*i)->y; // miny + ((*i)->y * (maxy - miny)); + double value = (*i)->y; in.add (when, value); } @@ -803,8 +834,6 @@ CrossfadeEditor::_apply_to (boost::shared_ptr xf) firstx = (*out.begin())->when; endx = (*the_end)->when; - miny = out.get_min_y (); - maxy = out.get_max_y (); out.freeze (); out.clear (); @@ -812,7 +841,7 @@ CrossfadeEditor::_apply_to (boost::shared_ptr xf) for (list::iterator i = fade[Out].points.begin(); i != fade[Out].points.end(); ++i) { double when = firstx + ((*i)->x * (endx - firstx)); - double value = (*i)->y; // miny + ((*i)->y * (maxy - miny)); + double value = (*i)->y; out.add (when, value); } @@ -847,7 +876,7 @@ CrossfadeEditor::reset () set (xfade->fade_in(), In); set (xfade->fade_out(), Out); - curve_select_clicked (current); + curve_select_clicked (current); } void @@ -1126,11 +1155,14 @@ CrossfadeEditor::make_waves (boost::shared_ptr region, WhichFade wh ht = canvas->get_allocation().get_height() / (double) nchans; spu = xfade->length() / (double) effective_width(); + delete _peaks_ready_connection; + _peaks_ready_connection = 0; + for (uint32_t n = 0; n < nchans; ++n) { gdouble yoff = n * ht; - if (region->audio_source(n)->peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), region, which), peaks_ready_connection)) { + if (region->audio_source(n)->peaks_ready (boost::bind (&CrossfadeEditor::peaks_ready, this, boost::weak_ptr(region), which), &_peaks_ready_connection, gui_context())) { WaveView* waveview = new WaveView (*(canvas->root())); waveview->property_data_src() = region.get(); @@ -1164,34 +1196,42 @@ CrossfadeEditor::make_waves (boost::shared_ptr region, WhichFade wh } void -CrossfadeEditor::peaks_ready (boost::shared_ptr r, WhichFade which) +CrossfadeEditor::peaks_ready (boost::weak_ptr wr, WhichFade which) { + boost::shared_ptr r (wr.lock()); + + if (!r) { + return; + } + /* this should never be called, because the peak files for an xfade will be ready by the time we want them. but our API forces us to provide this, so .. */ - peaks_ready_connection.disconnect (); + delete _peaks_ready_connection; + _peaks_ready_connection = 0; + make_waves (r, which); } void CrossfadeEditor::audition (Audition which) { - AudioPlaylist& pl (session.the_auditioner()->prepare_playlist()); - nframes_t preroll; - nframes_t postroll; - nframes_t left_start_offset; - nframes_t right_length; - nframes_t left_length; + AudioPlaylist& pl (_session->the_auditioner()->prepare_playlist()); + framecnt_t preroll; + framecnt_t postroll; + framecnt_t left_start_offset; + framecnt_t right_length; + framecnt_t left_length; if (which != Right && preroll_button.get_active()) { - preroll = session.frame_rate() * 2; //2 second hardcoded preroll for now + preroll = _session->frame_rate() * 2; //2 second hardcoded preroll for now } else { preroll = 0; } if (which != Left && postroll_button.get_active()) { - postroll = session.frame_rate() * 2; //2 second hardcoded postroll for now + postroll = _session->frame_rate() * 2; //2 second hardcoded postroll for now } else { postroll = 0; } @@ -1214,30 +1254,46 @@ CrossfadeEditor::audition (Audition which) right_length = xfade->in()->length(); } - boost::shared_ptr left (boost::dynamic_pointer_cast (RegionFactory::create (xfade->out(), left_start_offset, left_length, "xfade out", - 0, Region::DefaultFlags, false))); - boost::shared_ptr right (boost::dynamic_pointer_cast (RegionFactory::create (xfade->in(), 0, right_length, "xfade in", - 0, Region::DefaultFlags, false))); + PropertyList left_plist; + PropertyList right_plist; - //apply a 20ms declicking fade at the start and end of auditioning - left->set_fade_in_active(true); - left->set_fade_in_length(session.frame_rate() / 50); - right->set_fade_out_active(true); - right->set_fade_out_length(session.frame_rate() / 50); - pl.add_region (left, 0); - pl.add_region (right, 1 + preroll); + left_plist.add (ARDOUR::Properties::start, left_start_offset); + left_plist.add (ARDOUR::Properties::length, left_length); + left_plist.add (ARDOUR::Properties::name, string ("xfade out")); + left_plist.add (ARDOUR::Properties::layer, 0); + left_plist.add (ARDOUR::Properties::fade_in_active, true); + + right_plist.add (ARDOUR::Properties::start, 0); + right_plist.add (ARDOUR::Properties::length, right_length); + right_plist.add (ARDOUR::Properties::name, string("xfade in")); + right_plist.add (ARDOUR::Properties::layer, 0); + right_plist.add (ARDOUR::Properties::fade_out_active, true); if (which == Left) { - right->set_scale_amplitude (0.0); + right_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f); } else if (which == Right) { - left->set_scale_amplitude (0.0); + left_plist.add (ARDOUR::Properties::scale_amplitude, 0.0f); } + boost::shared_ptr left (boost::dynamic_pointer_cast + (RegionFactory::create (xfade->out(), left_plist, false))); + boost::shared_ptr right (boost::dynamic_pointer_cast + (RegionFactory::create (xfade->in(), right_plist, false))); + + // apply a 20ms declicking fade at the start and end of auditioning + // XXX this should really be a property + + left->set_fade_in_length (_session->frame_rate() / 50); + right->set_fade_out_length (_session->frame_rate() / 50); + + pl.add_region (left, 0); + pl.add_region (right, 1 + preroll); + /* there is only one ... */ pl.foreach_crossfade (sigc::mem_fun (*this, &CrossfadeEditor::setup)); - session.audition_playlist (); + _session->audition_playlist (); } void @@ -1249,10 +1305,17 @@ CrossfadeEditor::audition_both () void CrossfadeEditor::audition_left_dry () { - boost::shared_ptr left (boost::dynamic_pointer_cast (RegionFactory::create (xfade->out(), xfade->out()->length() - xfade->length(), xfade->length(), "xfade left", - 0, Region::DefaultFlags, false))); + PropertyList plist; + + plist.add (ARDOUR::Properties::start, xfade->out()->length() - xfade->length()); + plist.add (ARDOUR::Properties::length, xfade->length()); + plist.add (ARDOUR::Properties::name, string("xfade left")); + plist.add (ARDOUR::Properties::layer, 0); - session.audition_region (left); + boost::shared_ptr left (boost::dynamic_pointer_cast + (RegionFactory::create (xfade->out(), plist, false))); + + _session->audition_region (left); } void @@ -1264,9 +1327,17 @@ CrossfadeEditor::audition_left () void CrossfadeEditor::audition_right_dry () { - boost::shared_ptr right (boost::dynamic_pointer_cast (RegionFactory::create (xfade->in(), 0, xfade->length(), "xfade in", - 0, Region::DefaultFlags, false))); - session.audition_region (right); + PropertyList plist; + + plist.add (ARDOUR::Properties::start, 0); + plist.add (ARDOUR::Properties::length, xfade->length()); + plist.add (ARDOUR::Properties::name, string ("xfade right")); + plist.add (ARDOUR::Properties::layer, 0); + + boost::shared_ptr right (boost::dynamic_pointer_cast + (RegionFactory::create (xfade->in(), plist, false))); + + _session->audition_region (right); } void @@ -1278,7 +1349,7 @@ CrossfadeEditor::audition_right () void CrossfadeEditor::cancel_audition () { - session.cancel_audition (); + _session->cancel_audition (); } void @@ -1286,7 +1357,7 @@ CrossfadeEditor::audition_toggled () { bool x; - if ((x = audition_both_button.get_active ()) != session.is_auditioning()) { + if ((x = audition_both_button.get_active ()) != _session->is_auditioning()) { if (x) { audition_both (); @@ -1301,7 +1372,7 @@ CrossfadeEditor::audition_right_toggled () { bool x; - if ((x = audition_right_button.get_active ()) != session.is_auditioning()) { + if ((x = audition_right_button.get_active ()) != _session->is_auditioning()) { if (x) { audition_right (); @@ -1316,7 +1387,7 @@ CrossfadeEditor::audition_right_dry_toggled () { bool x; - if ((x = audition_right_dry_button.get_active ()) != session.is_auditioning()) { + if ((x = audition_right_dry_button.get_active ()) != _session->is_auditioning()) { if (x) { audition_right_dry (); @@ -1331,7 +1402,7 @@ CrossfadeEditor::audition_left_toggled () { bool x; - if ((x = audition_left_button.get_active ()) != session.is_auditioning()) { + if ((x = audition_left_button.get_active ()) != _session->is_auditioning()) { if (x) { audition_left (); @@ -1346,7 +1417,7 @@ CrossfadeEditor::audition_left_dry_toggled () { bool x; - if ((x = audition_left_dry_button.get_active ()) != session.is_auditioning()) { + if ((x = audition_left_dry_button.get_active ()) != _session->is_auditioning()) { if (x) { audition_left_dry (); @@ -1383,7 +1454,7 @@ CrossfadeEditor::on_key_release_event (GdkEventKey* ev) break; case GDK_space: - if (session.is_auditioning()) { + if (_session->is_auditioning()) { cancel_audition (); } else { audition_both_button.set_active (!audition_both_button.get_active());