Towards arranging sections
This allows to move or copy whole sections of the timline (everything you hear) to a differnt position on the timeline. NB. Markers and tempo-map are not yet moved, and interpolated MIDI events are lost.
This commit is contained in:
parent
c24c210cce
commit
38c613cd9a
|
@ -167,6 +167,7 @@ public:
|
|||
/* end of vfunc-based API */
|
||||
|
||||
void shift (timepos_t const &, timecnt_t const &);
|
||||
void cut_copy_section (timepos_t const& start, timepos_t const& end, timepos_t const& to, bool const copy);
|
||||
|
||||
/* controls use set_solo() to modify this route's solo state */
|
||||
|
||||
|
|
|
@ -1169,6 +1169,8 @@ public:
|
|||
void clear_range_selection ();
|
||||
void clear_object_selection ();
|
||||
|
||||
void cut_copy_section (Temporal::timepos_t const& start, Temporal::timepos_t const& end, Temporal::timepos_t const& to, bool const copy = false);
|
||||
|
||||
/* buffers for gain and pan */
|
||||
|
||||
gain_t* gain_automation_buffer () const;
|
||||
|
|
|
@ -2902,6 +2902,7 @@ LuaBindings::common (lua_State* L)
|
|||
.addFunction ("session_range_is_free", &Session::session_range_is_free)
|
||||
.addFunction ("set_session_range_is_free", &Session::set_session_range_is_free)
|
||||
.addFunction ("remove_route_group", (void (Session::*)(RouteGroup*))&Session::remove_route_group)
|
||||
.addFunction ("cut_copy_section", &Session::cut_copy_section)
|
||||
.addFunction ("vca_manager", &Session::vca_manager_ptr)
|
||||
.addExtCFunction ("timecode_to_sample_lua", ARDOUR::LuaAPI::timecode_to_sample_lua)
|
||||
.addExtCFunction ("sample_to_timecode_lua", ARDOUR::LuaAPI::sample_to_timecode_lua)
|
||||
|
|
|
@ -4540,6 +4540,36 @@ Route::shift (timepos_t const & pos, timecnt_t const & distance)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Route::cut_copy_section (timepos_t const& start, timepos_t const& end, timepos_t const& to, bool const copy)
|
||||
{
|
||||
ControllableSet acs;
|
||||
automatables (acs);
|
||||
for (auto& ec : acs) {
|
||||
boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (ec);
|
||||
if (!ac) {
|
||||
continue;
|
||||
}
|
||||
boost::shared_ptr<AutomationList> al = ac->alist();
|
||||
if (!al || al->empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
XMLNode &before = al->get_state ();
|
||||
boost::shared_ptr<Evoral::ControlList> cl = copy ? al->copy (start, end) : al->cut (start, end);
|
||||
if (!copy) {
|
||||
/* remove time (negative distance), ripple */
|
||||
al->shift (start, end.distance (start));
|
||||
}
|
||||
/* make space at the inserion point */
|
||||
al->shift (to, start.distance (end));
|
||||
al->paste (*cl, to);
|
||||
|
||||
XMLNode &after = al->get_state ();
|
||||
_session.add_command (new MementoCommand<AutomationList> (*al.get(), &before, &after));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Route::set_plugin_state_dir (boost::weak_ptr<Processor> p, const std::string& d)
|
||||
{
|
||||
|
|
|
@ -7186,6 +7186,64 @@ Session::clear_object_selection ()
|
|||
_object_selection = Temporal::Range (timepos_t::max (Temporal::AudioTime), timepos_t::max (Temporal::AudioTime));
|
||||
}
|
||||
|
||||
void
|
||||
Session::cut_copy_section (timepos_t const& start, timepos_t const& end, timepos_t const& to, bool const copy)
|
||||
{
|
||||
std::list<TimelineRange> ltr;
|
||||
TimelineRange tlr (start, end, 0);
|
||||
ltr.push_back (tlr);
|
||||
|
||||
if (copy) {
|
||||
begin_reversible_command (_("Copy Section"));
|
||||
} else {
|
||||
begin_reversible_command (_("Move Section"));
|
||||
}
|
||||
|
||||
{
|
||||
/* disable DiskReader::playlist_ranges_moved moving automation */
|
||||
bool automation_follows = Config->get_automation_follows_regions ();
|
||||
Config->set_automation_follows_regions (false);
|
||||
|
||||
for (auto& pl : _playlists->playlists) {
|
||||
pl->freeze ();
|
||||
pl->clear_changes ();
|
||||
pl->clear_owned_changes ();
|
||||
|
||||
boost::shared_ptr<Playlist> p = copy ? pl->copy (ltr) : pl->cut (ltr);
|
||||
// TODO copy interpolated MIDI events
|
||||
if (!copy) {
|
||||
pl->ripple (start, end.distance(start), NULL);
|
||||
}
|
||||
|
||||
/* now make space at the insertion-point */
|
||||
pl->ripple (to, start.distance(end), NULL);
|
||||
|
||||
pl->paste (p, to, 1);
|
||||
|
||||
vector<Command*> cmds;
|
||||
pl->rdiff (cmds);
|
||||
add_commands (cmds);
|
||||
add_command (new StatefulDiffCommand (pl));
|
||||
}
|
||||
|
||||
for (auto& pl : _playlists->playlists) {
|
||||
pl->thaw ();
|
||||
}
|
||||
|
||||
Config->set_automation_follows_regions (automation_follows);
|
||||
}
|
||||
|
||||
for (auto& r : *(routes.reader())) {
|
||||
r->cut_copy_section (start, end, to, copy);
|
||||
}
|
||||
|
||||
// TODO: update ranges and Tempo-Map
|
||||
|
||||
if (!abort_empty_reversible_command ()) {
|
||||
commit_reversible_command ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Session::auto_connect_route (boost::shared_ptr<Route> route,
|
||||
bool connect_inputs,
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
ardour { ["type"] = "Snippet", name = "Move Section" }
|
||||
|
||||
function factory (params) return function ()
|
||||
local start = Temporal.timepos_t(96000)
|
||||
local _end = Temporal.timepos_t(144000)
|
||||
local to = Temporal.timepos_t(480000)
|
||||
Session:cut_copy_section (start, _end, to , true)
|
||||
end end
|
Loading…
Reference in New Issue