Implement #2425: option for automation to follow region moves.
git-svn-id: svn://localhost/ardour2/branches/3.0@4326 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
43b14aa609
commit
2ebb1af299
|
@ -567,6 +567,7 @@
|
|||
<menuitem action='RubberbandingSnapsToGrid'/>
|
||||
<menuitem action='AutoAnalyseAudio'/>
|
||||
<menuitem action='toggle-region-fades'/>
|
||||
<menuitem action='automation-follows-regions'/>
|
||||
</menu>
|
||||
</menu>
|
||||
<menu name='Help' action='Help'>
|
||||
|
|
|
@ -1101,12 +1101,6 @@ AutomationLine::change_model (AutomationList::iterator i, double x, double y)
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::change_model_range (AutomationList::iterator start, AutomationList::iterator end, double xdelta, float ydelta)
|
||||
{
|
||||
alist->move_range (start, end, xdelta, ydelta);
|
||||
}
|
||||
|
||||
void
|
||||
AutomationLine::set_list(boost::shared_ptr<ARDOUR::AutomationList> list)
|
||||
{
|
||||
|
|
|
@ -162,7 +162,6 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
|
|||
void sync_model_with_view_line (uint32_t, uint32_t);
|
||||
|
||||
virtual void change_model (ARDOUR::AutomationList::iterator, double x, double y);
|
||||
virtual void change_model_range (ARDOUR::AutomationList::iterator,ARDOUR::AutomationList::iterator, double delta, float ydelta);
|
||||
|
||||
void reset_callback (const Evoral::ControlList&);
|
||||
void list_changed ();
|
||||
|
|
|
@ -356,6 +356,7 @@ class Editor : public PublicEditor
|
|||
void update_layering_model ();
|
||||
|
||||
void toggle_link_region_and_track_selection ();
|
||||
void toggle_automation_follows_regions ();
|
||||
|
||||
/* redirect shared ops menu. caller must free returned menu */
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ Editor::register_actions ()
|
|||
/* add named actions for the editor */
|
||||
|
||||
ActionManager::register_toggle_action (editor_actions, "link-region-and-track-selection", _("Link Region/Track Selection"), mem_fun (*this, &Editor::toggle_link_region_and_track_selection));
|
||||
ActionManager::register_toggle_action (editor_actions, "automation-follows-regions", _("Automation follows regions"), mem_fun (*this, &Editor::toggle_automation_follows_regions));
|
||||
ActionManager::register_action (editor_actions, "break-drag", _("Break drag"), mem_fun (*this, &Editor::break_drag));
|
||||
|
||||
act = ActionManager::register_toggle_action (editor_actions, "show-editor-mixer", _("Show Editor Mixer"), mem_fun (*this, &Editor::editor_mixer_button_toggled));
|
||||
|
@ -1731,6 +1732,12 @@ Editor::toggle_link_region_and_track_selection ()
|
|||
ActionManager::toggle_config_state ("Editor", "link-region-and-track-selection", &Configuration::set_link_region_and_track_selection, &Configuration::get_link_region_and_track_selection);
|
||||
}
|
||||
|
||||
void
|
||||
Editor::toggle_automation_follows_regions ()
|
||||
{
|
||||
ActionManager::toggle_config_state ("Editor", "automation-follows-regions", &Configuration::set_automation_follows_regions, &Configuration::get_automation_follows_regions);
|
||||
}
|
||||
|
||||
/** A Configuration parameter has changed.
|
||||
* @param parameter_name Name of the changed parameter.
|
||||
*/
|
||||
|
@ -1777,6 +1784,8 @@ Editor::parameter_changed (const char* parameter_name)
|
|||
toggle_meter_updating();
|
||||
} else if (PARAM_IS ("link-region-and-track-selection")) {
|
||||
ActionManager::map_some_state ("Editor", "link-region-and-track-selection", &Configuration::get_link_region_and_track_selection);
|
||||
} else if (PARAM_IS ("automation-follows-regions")) {
|
||||
ActionManager::map_some_state ("Editor", "automation-follows-regions", &Configuration::get_automation_follows_regions);
|
||||
}
|
||||
|
||||
#undef PARAM_IS
|
||||
|
|
|
@ -1297,12 +1297,17 @@ MixerStrip::map_frozen ()
|
|||
void
|
||||
MixerStrip::hide_redirect_editors ()
|
||||
{
|
||||
_route->foreach_processor (this, &MixerStrip::hide_processor_editor);
|
||||
_route->foreach_processor (mem_fun (*this, &MixerStrip::hide_processor_editor));
|
||||
}
|
||||
|
||||
void
|
||||
MixerStrip::hide_processor_editor (boost::shared_ptr<Processor> processor)
|
||||
MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
|
||||
{
|
||||
boost::shared_ptr<Processor> processor (p.lock ());
|
||||
if (!processor) {
|
||||
return;
|
||||
}
|
||||
|
||||
void* gui = processor->get_gui ();
|
||||
|
||||
if (gui) {
|
||||
|
|
|
@ -250,7 +250,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
|
|||
void name_changed ();
|
||||
void update_speed_display ();
|
||||
void map_frozen ();
|
||||
void hide_processor_editor (boost::shared_ptr<ARDOUR::Processor> processor);
|
||||
void hide_processor_editor (boost::weak_ptr<ARDOUR::Processor> processor);
|
||||
void hide_redirect_editors ();
|
||||
|
||||
bool ignore_speed_adjustment;
|
||||
|
|
|
@ -562,8 +562,7 @@ ProcessorBox::redisplay_processors ()
|
|||
processor_active_connections.clear ();
|
||||
processor_name_connections.clear ();
|
||||
|
||||
void (ProcessorBox::*method)(boost::shared_ptr<Processor>) = &ProcessorBox::add_processor_to_display;
|
||||
_route->foreach_processor (this, method);
|
||||
_route->foreach_processor (mem_fun (*this, &ProcessorBox::add_processor_to_display));
|
||||
|
||||
switch (_placement) {
|
||||
case PreFader:
|
||||
|
@ -576,8 +575,13 @@ ProcessorBox::redisplay_processors ()
|
|||
}
|
||||
|
||||
void
|
||||
ProcessorBox::add_processor_to_display (boost::shared_ptr<Processor> processor)
|
||||
ProcessorBox::add_processor_to_display (boost::weak_ptr<Processor> p)
|
||||
{
|
||||
boost::shared_ptr<Processor> processor (p.lock ());
|
||||
if (!processor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (processor->placement() != _placement) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
|
|||
bool processor_button_press_event (GdkEventButton *);
|
||||
bool processor_button_release_event (GdkEventButton *);
|
||||
void redisplay_processors ();
|
||||
void add_processor_to_display (boost::shared_ptr<ARDOUR::Processor>);
|
||||
void add_processor_to_display (boost::weak_ptr<ARDOUR::Processor>);
|
||||
void row_deleted (const Gtk::TreeModel::Path& path);
|
||||
void show_processor_active (boost::weak_ptr<ARDOUR::Processor>);
|
||||
void show_processor_name (boost::weak_ptr<ARDOUR::Processor>);
|
||||
|
|
|
@ -286,8 +286,8 @@ RouteTimeAxisView::post_construct ()
|
|||
update_diskstream_display ();
|
||||
|
||||
subplugin_menu.items().clear ();
|
||||
_route->foreach_processor (this, &RouteTimeAxisView::add_processor_to_subplugin_menu);
|
||||
_route->foreach_processor (this, &RouteTimeAxisView::add_existing_processor_automation_curves);
|
||||
_route->foreach_processor (mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
|
||||
_route->foreach_processor (mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
|
||||
reset_processor_automation_curves ();
|
||||
}
|
||||
|
||||
|
@ -1920,8 +1920,13 @@ RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::Process
|
|||
}
|
||||
|
||||
void
|
||||
RouteTimeAxisView::add_existing_processor_automation_curves (boost::shared_ptr<Processor> processor)
|
||||
RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
|
||||
{
|
||||
boost::shared_ptr<Processor> processor (p.lock ());
|
||||
if (!processor) {
|
||||
return;
|
||||
}
|
||||
|
||||
set<Evoral::Parameter> s;
|
||||
boost::shared_ptr<AutomationLine> al;
|
||||
|
||||
|
@ -1977,8 +1982,13 @@ RouteTimeAxisView::add_automation_child(Evoral::Parameter param, boost::shared_p
|
|||
|
||||
|
||||
void
|
||||
RouteTimeAxisView::add_processor_to_subplugin_menu (boost::shared_ptr<Processor> processor)
|
||||
RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
|
||||
{
|
||||
boost::shared_ptr<Processor> processor (p.lock ());
|
||||
if (!processor) {
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace Menu_Helpers;
|
||||
ProcessorAutomationInfo *rai;
|
||||
list<ProcessorAutomationInfo*>::iterator x;
|
||||
|
@ -2108,8 +2118,8 @@ RouteTimeAxisView::processors_changed ()
|
|||
|
||||
subplugin_menu.items().clear ();
|
||||
|
||||
_route->foreach_processor (this, &RouteTimeAxisView::add_processor_to_subplugin_menu);
|
||||
_route->foreach_processor (this, &RouteTimeAxisView::add_existing_processor_automation_curves);
|
||||
_route->foreach_processor (mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
|
||||
_route->foreach_processor (mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
|
||||
|
||||
for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ protected:
|
|||
|
||||
void processors_changed ();
|
||||
|
||||
void add_processor_to_subplugin_menu (boost::shared_ptr<ARDOUR::Processor>);
|
||||
void add_processor_to_subplugin_menu (boost::weak_ptr<ARDOUR::Processor>);
|
||||
void remove_processor_automation_node (ProcessorAutomationNode* pan);
|
||||
|
||||
void processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo*,
|
||||
|
@ -205,7 +205,7 @@ protected:
|
|||
find_processor_automation_curve (boost::shared_ptr<ARDOUR::Processor> i, Evoral::Parameter);
|
||||
|
||||
void add_processor_automation_curve (boost::shared_ptr<ARDOUR::Processor> r, Evoral::Parameter);
|
||||
void add_existing_processor_automation_curves (boost::shared_ptr<ARDOUR::Processor>);
|
||||
void add_existing_processor_automation_curves (boost::weak_ptr<ARDOUR::Processor>);
|
||||
|
||||
void add_automation_child(Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show=true);
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ CONFIG_VARIABLE (EditMode, edit_mode, "edit-mode", Slide)
|
|||
CONFIG_VARIABLE (LayerModel, layer_model, "layer-model", MoveAddHigher)
|
||||
CONFIG_VARIABLE (bool, link_region_and_track_selection, "link-region-and-track-selection", false)
|
||||
CONFIG_VARIABLE (std::string, keyboard_layout_name, "keyboard-layout-name", "ansi")
|
||||
CONFIG_VARIABLE (bool, automation_follows_regions, "automation-follows-regions", false)
|
||||
|
||||
/* monitoring, mute, solo etc */
|
||||
|
||||
|
|
|
@ -140,6 +140,8 @@ class Diskstream : public SessionObject
|
|||
|
||||
void remove_region_from_last_capture (boost::weak_ptr<Region> wregion);
|
||||
|
||||
void move_processor_automation (boost::weak_ptr<Processor>, Evoral::RangeMoveList const &);
|
||||
|
||||
sigc::signal<void> RecordEnableChanged;
|
||||
sigc::signal<void> SpeedChanged;
|
||||
sigc::signal<void> ReverseChanged;
|
||||
|
@ -204,6 +206,7 @@ class Diskstream : public SessionObject
|
|||
|
||||
virtual void playlist_changed (Change);
|
||||
virtual void playlist_deleted (boost::weak_ptr<Playlist>);
|
||||
virtual void playlist_ranges_moved (Evoral::RangeMoveList const &);
|
||||
|
||||
virtual void transport_stopped (struct tm&, time_t, bool abort) = 0;
|
||||
virtual void transport_looped (nframes_t transport_frame) = 0;
|
||||
|
@ -299,6 +302,7 @@ class Diskstream : public SessionObject
|
|||
sigc::connection ports_created_c;
|
||||
sigc::connection plmod_connection;
|
||||
sigc::connection plgone_connection;
|
||||
sigc::connection plregion_connection;
|
||||
|
||||
Flag _flags;
|
||||
};
|
||||
|
|
|
@ -35,7 +35,9 @@
|
|||
|
||||
#include <pbd/undo.h>
|
||||
#include <pbd/stateful.h>
|
||||
#include <pbd/statefuldestructible.h>
|
||||
#include <pbd/statefuldestructible.h>
|
||||
|
||||
#include <evoral/types.hpp>
|
||||
|
||||
#include <ardour/ardour.h>
|
||||
#include <ardour/session_object.h>
|
||||
|
@ -126,6 +128,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
sigc::signal<void> Modified;
|
||||
sigc::signal<void> NameChanged;
|
||||
sigc::signal<void> LengthChanged;
|
||||
sigc::signal<void, Evoral::RangeMoveList const &> RangesMoved;
|
||||
|
||||
static string bump_name (string old_name, Session&);
|
||||
|
||||
|
@ -177,6 +180,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
|
||||
RegionList regions; /* the current list of regions in the playlist */
|
||||
std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
|
||||
std::list<sigc::connection> region_state_changed_connections;
|
||||
DataType _type;
|
||||
mutable gint block_notifications;
|
||||
mutable gint ignore_state_changes;
|
||||
|
@ -186,6 +190,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
RegionList pending_bounds;
|
||||
bool pending_modified;
|
||||
bool pending_length;
|
||||
Evoral::RangeMoveList pending_range_moves;
|
||||
bool save_on_thaw;
|
||||
string last_save_reason;
|
||||
uint32_t in_set_state;
|
||||
|
@ -227,6 +232,7 @@ class Playlist : public SessionObject, public boost::enable_shared_from_this<Pla
|
|||
void notify_layering_changed ();
|
||||
void notify_modified ();
|
||||
void notify_state_changed (Change);
|
||||
void notify_region_moved (boost::shared_ptr<Region>);
|
||||
|
||||
void mark_session_dirty();
|
||||
|
||||
|
|
|
@ -142,10 +142,10 @@ class Route : public IO
|
|||
|
||||
void flush_processors ();
|
||||
|
||||
template<class T> void foreach_processor (T *obj, void (T::*func)(boost::shared_ptr<Processor>)) {
|
||||
void foreach_processor (sigc::slot<void, boost::weak_ptr<Processor> > method) {
|
||||
Glib::RWLock::ReaderLock lm (_processor_lock);
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
(obj->*func) (*i);
|
||||
method (boost::weak_ptr<Processor> (*i));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <pbd/basename.h>
|
||||
#include <glibmm/thread.h>
|
||||
#include <pbd/xml++.h>
|
||||
#include <pbd/memento_command.h>
|
||||
|
||||
#include <ardour/ardour.h>
|
||||
#include <ardour/audioengine.h>
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include <ardour/playlist.h>
|
||||
#include <ardour/cycle_timer.h>
|
||||
#include <ardour/region.h>
|
||||
#include <ardour/panner.h>
|
||||
|
||||
#include "i18n.h"
|
||||
#include <locale.h>
|
||||
|
@ -312,6 +314,7 @@ Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
|
|||
|
||||
plmod_connection.disconnect ();
|
||||
plgone_connection.disconnect ();
|
||||
plregion_connection.disconnect ();
|
||||
|
||||
if (_playlist) {
|
||||
_playlist->release();
|
||||
|
@ -326,6 +329,7 @@ Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
|
|||
|
||||
plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
|
||||
plgone_connection = _playlist->GoingAway.connect (bind (mem_fun (*this, &Diskstream::playlist_deleted), boost::weak_ptr<Playlist>(_playlist)));
|
||||
plregion_connection = _playlist->RangesMoved.connect (mem_fun (*this, &Diskstream::playlist_ranges_moved));
|
||||
}
|
||||
|
||||
/* don't do this if we've already asked for it *or* if we are setting up
|
||||
|
@ -409,3 +413,64 @@ Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
|
|||
_last_capture_regions.remove (region);
|
||||
}
|
||||
|
||||
void
|
||||
Diskstream::playlist_ranges_moved (Evoral::RangeMoveList const & movements)
|
||||
{
|
||||
if (Config->get_automation_follows_regions () == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* move gain automation */
|
||||
boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->alist();
|
||||
XMLNode & before = gain_alist->get_state ();
|
||||
gain_alist->move_ranges (movements);
|
||||
_session.add_command (
|
||||
new MementoCommand<AutomationList> (
|
||||
*gain_alist.get(), &before, &gain_alist->get_state ()
|
||||
)
|
||||
);
|
||||
|
||||
/* move panner automation */
|
||||
Panner & p = _io->panner ();
|
||||
for (uint32_t i = 0; i < p.npanners (); ++i) {
|
||||
|
||||
boost::shared_ptr<AutomationList> pan_alist = p.streampanner(i).pan_control()->alist();
|
||||
XMLNode & before = pan_alist->get_state ();
|
||||
pan_alist->move_ranges (movements);
|
||||
_session.add_command (
|
||||
new MementoCommand<AutomationList> (
|
||||
*pan_alist.get(), &before, &pan_alist->get_state ()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/* move processor automation */
|
||||
/* XXX: ewww */
|
||||
Route * route = dynamic_cast<Route*> (_io);
|
||||
if (route) {
|
||||
route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, Evoral::RangeMoveList const & movements)
|
||||
{
|
||||
boost::shared_ptr<Processor> processor (p.lock ());
|
||||
if (!processor) {
|
||||
return;
|
||||
}
|
||||
|
||||
set<Evoral::Parameter> const a = processor->what_can_be_automated ();
|
||||
|
||||
for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
|
||||
boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
|
||||
XMLNode & before = al->get_state ();
|
||||
al->move_ranges (movements);
|
||||
_session.add_command (
|
||||
new MementoCommand<AutomationList> (
|
||||
*al.get(), &before, &al->get_state ()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -360,6 +360,25 @@ Playlist::notify_region_removed (boost::shared_ptr<Region> r)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::notify_region_moved (boost::shared_ptr<Region> r)
|
||||
{
|
||||
Evoral::RangeMove const move (r->last_position (), r->length (), r->position ());
|
||||
|
||||
if (holding_state ()) {
|
||||
|
||||
pending_range_moves.push_back (move);
|
||||
|
||||
} else {
|
||||
|
||||
Evoral::RangeMoveList m;
|
||||
m.push_back (move);
|
||||
RangesMoved (m);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Playlist::notify_region_added (boost::shared_ptr<Region> r)
|
||||
{
|
||||
|
@ -452,9 +471,14 @@ Playlist::flush_notifications ()
|
|||
check_dependents (*s, false);
|
||||
}
|
||||
|
||||
if (!pending_range_moves.empty ()) {
|
||||
RangesMoved (pending_range_moves);
|
||||
}
|
||||
|
||||
pending_adds.clear ();
|
||||
pending_removes.clear ();
|
||||
pending_bounds.clear ();
|
||||
pending_range_moves.clear ();
|
||||
|
||||
in_flush = false;
|
||||
}
|
||||
|
@ -559,8 +583,10 @@ Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t posit
|
|||
}
|
||||
}
|
||||
|
||||
region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
|
||||
boost::weak_ptr<Region> (region)));
|
||||
region_state_changed_connections.push_back (
|
||||
region->StateChanged.connect (sigc::bind (mem_fun (this, &Playlist::region_changed_proxy),
|
||||
boost::weak_ptr<Region> (region)))
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1288,20 +1314,22 @@ Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
|
|||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
if (what_changed & BoundsChanged) {
|
||||
region_bounds_changed (what_changed, region);
|
||||
save = !(_splicing || _nudging);
|
||||
}
|
||||
if (what_changed & BoundsChanged) {
|
||||
region_bounds_changed (what_changed, region);
|
||||
save = !(_splicing || _nudging);
|
||||
}
|
||||
|
||||
if ((what_changed & our_interests) &&
|
||||
!(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
|
||||
check_dependents (region, false);
|
||||
}
|
||||
if ((what_changed & our_interests) &&
|
||||
!(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
|
||||
check_dependents (region, false);
|
||||
}
|
||||
|
||||
if (what_changed & Change (ARDOUR::PositionChanged)) {
|
||||
notify_region_moved (region);
|
||||
}
|
||||
|
||||
if (what_changed & our_interests) {
|
||||
save = true;
|
||||
}
|
||||
if (what_changed & our_interests) {
|
||||
save = true;
|
||||
}
|
||||
|
||||
return save;
|
||||
|
@ -1320,6 +1348,17 @@ Playlist::clear (bool with_signals)
|
|||
{
|
||||
{
|
||||
RegionLock rl (this);
|
||||
|
||||
for (
|
||||
std::list<sigc::connection>::iterator i = region_state_changed_connections.begin ();
|
||||
i != region_state_changed_connections.end ();
|
||||
++i
|
||||
) {
|
||||
|
||||
i->disconnect ();
|
||||
|
||||
}
|
||||
|
||||
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
|
||||
pending_removes.insert (*i);
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
void erase_range (double start, double end);
|
||||
void erase (iterator);
|
||||
void erase (iterator, iterator);
|
||||
void move_range (iterator start, iterator end, double, double);
|
||||
void move_ranges (RangeMoveList const &);
|
||||
void modify (iterator, double, double);
|
||||
|
||||
boost::shared_ptr<ControlList> cut (double, double);
|
||||
|
@ -241,6 +241,7 @@ protected:
|
|||
bool rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
|
||||
|
||||
boost::shared_ptr<ControlList> cut_copy_clear (double, double, int op);
|
||||
bool erase_range_internal (double start, double end, EventList &);
|
||||
|
||||
virtual void maybe_signal_changed ();
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define EVORAL_TYPES_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
#include <list>
|
||||
|
||||
namespace Evoral {
|
||||
|
||||
|
@ -41,6 +42,16 @@ typedef double EventLength;
|
|||
/** Type of an event (opaque, mapped by application) */
|
||||
typedef uint32_t EventType;
|
||||
|
||||
/** Type to describe the movement of a time range */
|
||||
struct RangeMove {
|
||||
RangeMove (EventTime f, FrameTime l, EventTime t) : from (f), length (l), to (t) {}
|
||||
EventTime from; ///< start of the range
|
||||
FrameTime length; ///< length of the range
|
||||
EventTime to; ///< new start of the range
|
||||
};
|
||||
|
||||
typedef std::list<RangeMove> RangeMoveList;
|
||||
|
||||
} // namespace Evoral
|
||||
|
||||
#endif // EVORAL_TYPES_HPP
|
||||
|
|
|
@ -390,16 +390,10 @@ ControlList::erase_range (double start, double endt)
|
|||
|
||||
{
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
ControlEvent cp (start, 0.0f);
|
||||
iterator s;
|
||||
iterator e;
|
||||
erased = erase_range_internal (start, endt, _events);
|
||||
|
||||
if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) != _events.end()) {
|
||||
cp.when = endt;
|
||||
e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
|
||||
_events.erase (s, e);
|
||||
if (erased) {
|
||||
reposition_for_rt_add (0);
|
||||
erased = true;
|
||||
mark_dirty ();
|
||||
}
|
||||
|
||||
|
@ -410,36 +404,22 @@ ControlList::erase_range (double start, double endt)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ControlList::move_range (iterator start, iterator end, double xdelta, double ydelta)
|
||||
bool
|
||||
ControlList::erase_range_internal (double start, double endt, EventList & events)
|
||||
{
|
||||
/* note: we assume higher level logic is in place to avoid this
|
||||
reordering the time-order of control events in the list. ie. all
|
||||
points after end are later than (end)->when.
|
||||
*/
|
||||
bool erased = false;
|
||||
ControlEvent cp (start, 0.0f);
|
||||
iterator s;
|
||||
iterator e;
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
|
||||
while (start != end) {
|
||||
(*start)->when += xdelta;
|
||||
(*start)->value += ydelta;
|
||||
if (isnan ((*start)->value)) {
|
||||
abort ();
|
||||
}
|
||||
++start;
|
||||
}
|
||||
|
||||
if (!_frozen) {
|
||||
_events.sort (event_time_less_than);
|
||||
} else {
|
||||
_sort_pending = true;
|
||||
}
|
||||
|
||||
mark_dirty ();
|
||||
if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
|
||||
cp.when = endt;
|
||||
e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
|
||||
events.erase (s, e);
|
||||
erased = true;
|
||||
}
|
||||
|
||||
maybe_signal_changed ();
|
||||
return erased;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1315,5 +1295,51 @@ ControlList::paste (ControlList& alist, double pos, float times)
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Move automation around according to a list of region movements */
|
||||
void
|
||||
ControlList::move_ranges (RangeMoveList const & movements)
|
||||
{
|
||||
{
|
||||
Glib::Mutex::Lock lm (_lock);
|
||||
|
||||
/* a copy of the events list before we started moving stuff around */
|
||||
EventList old_events = _events;
|
||||
|
||||
/* clear the source and destination ranges in the new list */
|
||||
for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
|
||||
|
||||
erase_range_internal (i->from, i->from + i->length, _events);
|
||||
erase_range_internal (i->to, i->to + i->length, _events);
|
||||
|
||||
}
|
||||
|
||||
/* copy the events into the new list */
|
||||
for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
|
||||
iterator j = old_events.begin ();
|
||||
EventTime const limit = i->from + i->length;
|
||||
EventTime const dx = i->to - i->from;
|
||||
while (j != old_events.end () && (*j)->when <= limit) {
|
||||
if ((*j)->when >= i->from) {
|
||||
ControlEvent* ev = new ControlEvent (**j);
|
||||
ev->when += dx;
|
||||
_events.push_back (ev);
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_frozen) {
|
||||
_events.sort (event_time_less_than);
|
||||
} else {
|
||||
_sort_pending = true;
|
||||
}
|
||||
|
||||
reposition_for_rt_add (0);
|
||||
mark_dirty ();
|
||||
}
|
||||
|
||||
maybe_signal_changed ();
|
||||
}
|
||||
|
||||
} // namespace Evoral
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user