diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index f94269c564..01777f54a3 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -4430,10 +4430,10 @@ Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewLi if ((tr = rtv->track()) && ((pl = tr->playlist()))) { - boost::shared_ptr regions = pl->regions_at ( + boost::shared_ptr regions = pl->regions_at ( (framepos_t) floor ( (double) where * tr->speed())); - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { + for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { RegionView* rv = rtv->view()->find_view (*i); if (rv) { rs.add (rv); @@ -4463,10 +4463,10 @@ Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackVie if ((tr = rtv->track()) && ((pl = tr->playlist()))) { - boost::shared_ptr regions = pl->regions_touched ( + boost::shared_ptr regions = pl->regions_touched ( (framepos_t) floor ( (double)where * tr->speed()), max_framepos); - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { + for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { RegionView* rv = rtv->view()->find_view (*i); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index e12e20f610..2bf8fa8052 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1834,7 +1834,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD int time_stretch (RegionSelection&, float fraction); int pitch_shift (RegionSelection&, float cents); void pitch_shift_region (); - int time_fx (RegionSelection&, float val, bool pitching); void transpose_region (); @@ -2081,6 +2080,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD void follow_mixer_selection (); bool _following_mixer_selection; + int time_fx (ARDOUR::RegionList&, float val, bool pitching); + friend class Drag; friend class RegionDrag; friend class RegionMoveDrag; diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 1875907345..0f07875eac 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -568,7 +568,7 @@ Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, boost::shared_ptr pl; if ((pl = boost::dynamic_pointer_cast (atv->track()->playlist())) != 0) { - boost::shared_ptr rl = pl->regions_at (event_frame (event)); + boost::shared_ptr rl = pl->regions_at (event_frame (event)); if (!rl->empty()) { if (atv->layer_display() == Overlaid) { @@ -618,7 +618,7 @@ Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, layer_t const l = pl->top_layer () + 1 - (cy / c); /* hence region */ - Playlist::RegionList::iterator i = rl->begin(); + RegionList::iterator i = rl->begin(); while (i != rl->end() && (*i)->layer() != l) { ++i; } diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 269539dd72..582ddeb1fc 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3304,15 +3304,16 @@ TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } #endif - // XXX how do timeFX on multiple regions ? + if (!_editor->get_selection().regions.empty()) { + /* primary will already be included in the selection, and edit + group shared editing will propagate selection across + equivalent regions, so just use the current region + selection. + */ - RegionSelection rs; - rs.add (_primary); - - RegionSelection all = _editor->get_equivalent_regions (rs, ARDOUR::Properties::edit.property_id); - - if (_editor->time_stretch (all, percentage) == -1) { - error << _("An error occurred while executing time stretch operation") << endmsg; + if (_editor->time_stretch (_editor->get_selection().regions, percentage) == -1) { + error << _("An error occurred while executing time stretch operation") << endmsg; + } } } diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc index 830d8999a4..d4d02ea1c4 100644 --- a/gtk2_ardour/editor_timefx.cc +++ b/gtk2_ardour/editor_timefx.cc @@ -21,8 +21,8 @@ #include #include #include - #include +#include #include "pbd/error.h" #include "pbd/pthread_utils.h" @@ -63,45 +63,87 @@ using namespace Gtkmm2ext; int Editor::time_stretch (RegionSelection& regions, float fraction) { - // FIXME: kludge, implement stretching of selection of both types + RegionList audio; + RegionList midi; + int aret; - if (regions.front()->region()->data_type() == DataType::AUDIO) { - // Audio, pop up timefx dialog - return time_fx (regions, fraction, false); - } else { - // MIDI, just stretch - RouteTimeAxisView* rtv = dynamic_cast (®ions.front()->get_time_axis_view()); - if (!rtv) - return -1; + begin_reversible_command (_("stretch/shrink")); - boost::shared_ptr playlist = rtv->track()->playlist(); - - ARDOUR::TimeFXRequest request; - request.time_fraction = fraction; - MidiStretch stretch(*_session, request); - begin_reversible_command ("midi stretch"); - stretch.run(regions.front()->region()); - playlist->clear_changes (); - playlist->replace_region (regions.front()->region(), stretch.results[0], - regions.front()->region()->position()); - _session->add_command (new StatefulDiffCommand (playlist)); - commit_reversible_command (); + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + if ((*i)->region()->data_type() == DataType::AUDIO) { + audio.push_back ((*i)->region()); + } else if ((*i)->region()->data_type() == DataType::MIDI) { + midi.push_back ((*i)->region()); + } } + if ((aret = time_fx (audio, fraction, false)) != 0) { + return aret; + } + + set > midi_playlists_affected; + + for (RegionList::iterator i = midi.begin(); i != midi.end(); ++i) { + boost::shared_ptr playlist = (*i)->playlist(); + + if (playlist) { + playlist->clear_changes (); + } + + } + + ARDOUR::TimeFXRequest request; + request.time_fraction = fraction; + + for (RegionList::iterator i = midi.begin(); i != midi.end(); ++i) { + boost::shared_ptr playlist = (*i)->playlist(); + + if (!playlist) { + continue; + } + + MidiStretch stretch (*_session, request); + stretch.run (*i); + + playlist->replace_region (regions.front()->region(), stretch.results[0], + regions.front()->region()->position()); + midi_playlists_affected.insert (playlist); + } + + for (set >::iterator p = midi_playlists_affected.begin(); p != midi_playlists_affected.end(); ++p) { + _session->add_command (new StatefulDiffCommand (*p)); + } + + commit_reversible_command (); + return 0; } int Editor::pitch_shift (RegionSelection& regions, float fraction) { - return time_fx (regions, fraction, true); + RegionList rl; + + for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) { + rl.push_back ((*i)->region()); + } + + begin_reversible_command (_("pitch shift")); + + int ret = time_fx (rl, fraction, true); + + if (ret == 0) { + commit_reversible_command (); + } + + return ret; } /** @param val Percentage to time stretch by; ignored if pitch-shifting. * @param pitching true to pitch shift, false to time stretch. * @return -1 in case of error, 1 if operation was cancelled by the user, 0 if everything went ok */ int -Editor::time_fx (RegionSelection& regions, float val, bool pitching) +Editor::time_fx (RegionList& regions, float val, bool pitching) { delete current_timefx; @@ -264,45 +306,31 @@ Editor::time_fx (RegionSelection& regions, float val, bool pitching) void Editor::do_timefx (TimeFXDialog& dialog) { - Track* t; boost::shared_ptr playlist; boost::shared_ptr new_region; - bool in_command = false; + set > playlists_affected; uint32_t const N = dialog.regions.size (); - for (RegionSelection::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ) { - AudioRegionView* arv = dynamic_cast(*i); + for (RegionList::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ++i) { + boost::shared_ptr playlist = (*i)->playlist(); - if (!arv) { - continue; + if (playlist) { + playlist->clear_changes (); } + } - boost::shared_ptr region (arv->audio_region()); - TimeAxisView* tv = &(arv->get_time_axis_view()); - RouteTimeAxisView* rtv; - RegionSelection::iterator tmp; + for (RegionList::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ++i) { - tmp = i; - ++tmp; + boost::shared_ptr region = boost::dynamic_pointer_cast (*i); - if ((rtv = dynamic_cast (tv)) == 0) { - i = tmp; - continue; - } - - if ((t = dynamic_cast (rtv->route().get())) == 0) { - i = tmp; - continue; - } - - if ((playlist = t->playlist()) == 0) { - i = tmp; + if (!region || (playlist = region->playlist()) == 0) { continue; } if (dialog.request.cancel) { /* we were cancelled */ + /* XXX what to do about playlists already affected ? */ dialog.status = 1; return; } @@ -331,24 +359,16 @@ Editor::do_timefx (TimeFXDialog& dialog) if (!fx->results.empty()) { new_region = fx->results.front(); - if (!in_command) { - _session->begin_reversible_command (dialog.pitching ? _("pitch shift") : _("time stretch")); - in_command = true; - } - - playlist->clear_changes (); playlist->replace_region (region, new_region, region->position()); - _session->add_command (new StatefulDiffCommand (playlist)); + playlists_affected.insert (playlist); } current_timefx->ascend (); - - i = tmp; delete fx; } - if (in_command) { - _session->commit_reversible_command (); + for (set >::iterator p = playlists_affected.begin(); p != playlists_affected.end(); ++p) { + _session->add_command (new StatefulDiffCommand (*p)); } dialog.status = 0; diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 54b6ae5023..13f169b96e 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -2416,7 +2416,7 @@ RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, } static -void add_region_to_list (RegionView* rv, Playlist::RegionList* l) +void add_region_to_list (RegionView* rv, RegionList* l) { l->push_back (rv->region()); } @@ -2435,7 +2435,7 @@ RouteTimeAxisView::combine_regions () return 0; } - Playlist::RegionList selected_regions; + RegionList selected_regions; boost::shared_ptr playlist = track()->playlist(); _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions)); @@ -2466,7 +2466,7 @@ RouteTimeAxisView::uncombine_regions () return; } - Playlist::RegionList selected_regions; + RegionList selected_regions; boost::shared_ptr playlist = track()->playlist(); /* have to grab selected regions first because the uncombine is going @@ -2477,7 +2477,7 @@ RouteTimeAxisView::uncombine_regions () playlist->clear_changes (); - for (Playlist::RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) { + for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) { playlist->uncombine (*i); } diff --git a/gtk2_ardour/time_fx_dialog.h b/gtk2_ardour/time_fx_dialog.h index 20b0538a7f..be7c32c1e8 100644 --- a/gtk2_ardour/time_fx_dialog.h +++ b/gtk2_ardour/time_fx_dialog.h @@ -22,6 +22,8 @@ #include +#include "ardour/playlist.h" + #include "ardour_dialog.h" #include "region_selection.h" #include "progress_reporter.h" @@ -40,8 +42,8 @@ public: Gtk::SpinButton pitch_octave_spinner; Gtk::SpinButton pitch_semitone_spinner; Gtk::SpinButton pitch_cent_spinner; - RegionSelection regions; Gtk::ProgressBar progress_bar; + ARDOUR::RegionList regions; /* SoundTouch */ Gtk::CheckButton quick_button; diff --git a/libs/ardour/ardour/midi_stretch.h b/libs/ardour/ardour/midi_stretch.h index 90c75bbc18..9b4fba80ce 100644 --- a/libs/ardour/ardour/midi_stretch.h +++ b/libs/ardour/ardour/midi_stretch.h @@ -26,13 +26,13 @@ namespace ARDOUR { class MidiStretch : public Filter { public: - MidiStretch (ARDOUR::Session&, TimeFXRequest&); + MidiStretch (ARDOUR::Session&, const TimeFXRequest&); ~MidiStretch (); int run (boost::shared_ptr, Progress* progress = 0); private: - TimeFXRequest& _request; + const TimeFXRequest& _request; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h index 022fdb3ccb..1f66310877 100644 --- a/libs/ardour/ardour/playlist.h +++ b/libs/ardour/ardour/playlist.h @@ -81,7 +81,6 @@ class RegionListProperty : public PBD::SequenceProperty { public: - typedef std::list > RegionList; static void make_property_quarks (); Playlist (Session&, const XMLNode&, DataType type, bool hidden = false); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index c2c7289329..c34869bc2b 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -82,6 +82,8 @@ namespace ARDOUR { // associate a set of intervals with regions (e.g. for silence detection) typedef std::map,AudioIntervalResult> AudioIntervalMap; + typedef std::list > RegionList; + struct IOChange { enum Type { diff --git a/libs/ardour/midi_stretch.cc b/libs/ardour/midi_stretch.cc index 7a4164427a..83b845bbfc 100644 --- a/libs/ardour/midi_stretch.cc +++ b/libs/ardour/midi_stretch.cc @@ -33,7 +33,7 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -MidiStretch::MidiStretch (Session& s, TimeFXRequest& req) +MidiStretch::MidiStretch (Session& s, const TimeFXRequest& req) : Filter (s) , _request (req) { diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index bc11b863eb..a17d72c4eb 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -1634,7 +1634,7 @@ Playlist::flush_notifications (bool from_undo) FINDING THINGS **********************************************************************/ -boost::shared_ptr +boost::shared_ptr Playlist::regions_at (framepos_t frame) { RegionLock rlock (this); @@ -1703,7 +1703,7 @@ Playlist::regions_at (framepos_t frame) return region; } -boost::shared_ptr +boost::shared_ptr Playlist::regions_to_read (framepos_t start, framepos_t end) { /* Caller must hold lock */ @@ -1838,7 +1838,7 @@ Playlist::regions_to_read (framepos_t start, framepos_t end) return rlist; } -boost::shared_ptr +boost::shared_ptr Playlist::find_regions_at (framepos_t frame) { /* Caller must hold lock */ @@ -1854,7 +1854,7 @@ Playlist::find_regions_at (framepos_t frame) return rlist; } -boost::shared_ptr +boost::shared_ptr Playlist::regions_touched (framepos_t start, framepos_t end) { RegionLock rlock (this);