#include <gtkmm2ext/choice.h>
#include <gtkmm2ext/popup.h>
-#include "ardour/audioengine.h"
-#include "ardour/session.h"
-#include "ardour/audioplaylist.h"
+#include "ardour/audio_track.h"
#include "ardour/audioregion.h"
-#include "ardour/audio_diskstream.h"
-#include "ardour/utils.h"
+#include "ardour/dB.h"
#include "ardour/location.h"
-#include "ardour/audio_track.h"
-#include "ardour/audioplaylist.h"
-#include "ardour/region_factory.h"
+#include "ardour/midi_region.h"
+#include "ardour/operations.h"
#include "ardour/playlist_factory.h"
-#include "ardour/reverse.h"
-#include "ardour/transient_detector.h"
-#include "ardour/dB.h"
#include "ardour/quantize.h"
-#include "ardour/strip_silence.h"
+#include "ardour/region_factory.h"
+#include "ardour/reverse.h"
#include "ardour/route_group.h"
-#include "ardour/operations.h"
+#include "ardour/session.h"
+#include "ardour/session_playlists.h"
+#include "ardour/strip_silence.h"
+#include "ardour/transient_detector.h"
+#include "ardour/utils.h"
#include "ardour_ui.h"
#include "debug.h"
void
Editor::undo (uint32_t n)
{
+ if (_drags->active ()) {
+ _drags->abort ();
+ }
+
if (_session) {
_session->undo (n);
}
void
Editor::redo (uint32_t n)
{
+ if (_drags->active ()) {
+ _drags->abort ();
+ }
+
if (_session) {
_session->redo (n);
}
TimeAxisView *ontrack = 0;
TrackViewList tlist;
-
+
if (!selection->tracks.empty()) {
- tlist = selection->tracks;
+ tlist = selection->tracks.filter_to_unique_playlists ();
} else {
- tlist = track_views;
+ tlist = track_views.filter_to_unique_playlists ();
}
while (pos < _session->current_end_frame() && !at_end) {
new_leftmost = 0;
}
+ if (new_leftmost < 0) {
+ new_leftmost = 0;
+ }
+
reposition_and_zoom (new_leftmost, new_fpu);
}
Location * looploc = _session->locations()->auto_loop_location();
Location * punchloc = _session->locations()->auto_punch_location();
+ Location * sessionloc = _session->locations()->session_range_location();
_session->locations()->clear_ranges ();
// re-add these
if (looploc) _session->locations()->add (looploc);
if (punchloc) _session->locations()->add (punchloc);
+ if (sessionloc) _session->locations()->add (sessionloc);
XMLNode &after = _session->locations()->get_state();
_session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
}
}
+void
+Editor::do_layer_operation (LayerOperation op)
+{
+ if (selection->regions.empty ()) {
+ return;
+ }
+
+ bool const multiple = selection->regions.size() > 1;
+ switch (op) {
+ case Raise:
+ if (multiple) {
+ begin_reversible_command (_("raise regions"));
+ } else {
+ begin_reversible_command (_("raise region"));
+ }
+ break;
+
+ case RaiseToTop:
+ if (multiple) {
+ begin_reversible_command (_("raise regions to top"));
+ } else {
+ begin_reversible_command (_("raise region to top"));
+ }
+ break;
+
+ case Lower:
+ if (multiple) {
+ begin_reversible_command (_("lower regions"));
+ } else {
+ begin_reversible_command (_("lower region"));
+ }
+ break;
+
+ case LowerToBottom:
+ if (multiple) {
+ begin_reversible_command (_("lower regions to bottom"));
+ } else {
+ begin_reversible_command (_("lower region"));
+ }
+ break;
+ }
+
+ set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
+ for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ (*i)->clear_owned_changes ();
+ }
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ boost::shared_ptr<Region> r = (*i)->region ();
+ switch (op) {
+ case Raise:
+ r->raise ();
+ break;
+ case RaiseToTop:
+ r->raise_to_top ();
+ break;
+ case Lower:
+ r->lower ();
+ break;
+ case LowerToBottom:
+ r->lower_to_bottom ();
+ }
+ }
+
+ for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ vector<Command*> cmds;
+ (*i)->rdiff (cmds);
+ _session->add_commands (cmds);
+ }
+
+ commit_reversible_command ();
+}
+
void
Editor::raise_region ()
{
- selection->foreach_region (&Region::raise);
+ do_layer_operation (Raise);
}
void
Editor::raise_region_to_top ()
{
- selection->foreach_region (&Region::raise_to_top);
+ do_layer_operation (RaiseToTop);
}
void
Editor::lower_region ()
{
- selection->foreach_region (&Region::lower);
+ do_layer_operation (Lower);
}
void
Editor::lower_region_to_bottom ()
{
- selection->foreach_region (&Region::lower_to_bottom);
+ do_layer_operation (LowerToBottom);
}
/** Show the region editor for the selected regions */
d.set_size_request (300, -1);
d.set_position (Gtk::WIN_POS_MOUSE);
- entry.set_text (selection->regions.front()->region()->name());
+ entry.set_text (rs.front()->region()->name());
entry.select_region (0, -1);
entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
framepos_t start = selection->time[clicked_selection].start;
framepos_t end = selection->time[clicked_selection].end;
- sort_track_selection ();
+ TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+ sort_track_selection (ts);
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
boost::shared_ptr<Region> current;
boost::shared_ptr<Playlist> playlist;
framepos_t internal_start;
t = selection->tracks;
}
- return t;
+ return t.filter_to_unique_playlists();
}
void
RegionSelection new_selection;
TrackViewList tmptracks = get_tracks_for_range_action ();
- sort_track_selection (&tmptracks);
+ sort_track_selection (tmptracks);
for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
{
vector<boost::shared_ptr<Playlist> > playlists;
boost::shared_ptr<Playlist> playlist;
- TrackViewList* ts;
+ TrackViewList ts;
if (selection->tracks.empty()) {
- ts = &track_views;
+ ts = track_views.filter_to_unique_playlists();
} else {
- sort_track_selection ();
- ts = &selection->tracks;
+ ts = selection->tracks.filter_to_unique_playlists ();
}
- for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
+ sort_track_selection (ts);
+
+ for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
RouteTimeAxisView* rtv;
begin_reversible_command (Operations::fill_selection);
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+
+ for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
if ((playlist = (*i)->playlist()) == 0) {
continue;
boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
+ if (!r) {
+ continue;
+ }
+
if (replace) {
list<AudioRange> ranges;
ranges.push_back (AudioRange (start, start+cnt, 0));
/* we only want to cut regions if some are selected */
- if (!selection->regions.empty()) {
- rs = selection->regions;
- }
-
switch (current_mouse_mode()) {
case MouseObject:
+ rs = get_regions_from_selection ();
if (!rs.empty() || !selection->points.empty()) {
begin_reversible_command (opname + _(" objects"));
begin_reversible_command (_("remove region"));
playlist->clear_changes ();
+ playlist->clear_owned_changes ();
playlist->remove_region (clicked_regionview->region());
+
+ /* We might have removed regions, which alters other regions' layering_index,
+ so we need to do a recursive diff here.
+ */
+ vector<Command*> cmds;
+ playlist->rdiff (cmds);
+ _session->add_commands (cmds);
+
_session->add_command(new StatefulDiffCommand (playlist));
commit_reversible_command ();
}
continue;
}
- vector<boost::shared_ptr<Playlist> >::iterator i;
-
- //only prep history if this is a new playlist.
- for (i = playlists.begin(); i != playlists.end(); ++i) {
- if ((*i) == playlist) {
- break;
- }
- }
-
- if (i == playlists.end()) {
-
- playlist->clear_changes ();
- playlist->freeze ();
+ /* get_regions_from_selection_and_entered() guarantees that
+ the playlists involved are unique, so there is no need
+ to check here.
+ */
- playlists.push_back (playlist);
- }
+ playlists.push_back (playlist);
+ playlist->clear_changes ();
+ playlist->clear_owned_changes ();
+ playlist->freeze ();
playlist->remove_region (*rl);
}
for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
(*pl)->thaw ();
+
+ /* We might have removed regions, which alters other regions' layering_index,
+ so we need to do a recursive diff here.
+ */
+ vector<Command*> cmds;
+ (*pl)->rdiff (cmds);
+ _session->add_commands (cmds);
+
_session->add_command(new StatefulDiffCommand (*pl));
}
if (fl == freezelist.end()) {
pl->clear_changes();
+ pl->clear_owned_changes ();
pl->freeze ();
freezelist.insert (pl);
}
for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
(*pl)->thaw ();
+
+ /* We might have removed regions, which alters other regions' layering_index,
+ so we need to do a recursive diff here.
+ */
+ vector<Command*> cmds;
+ (*pl)->rdiff (cmds);
+ _session->add_commands (cmds);
+
_session->add_command (new StatefulDiffCommand (*pl));
}
}
void
Editor::cut_copy_ranges (CutCopyOp op)
{
- TrackViewList* ts;
- TrackViewList entered;
+ TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
/* Sort the track selection now, so that it if is used, the playlists
selected by the calls below to cut_copy_clear are in the order that
their tracks appear in the editor. This makes things like paste
of ranges work properly.
*/
- sort_track_selection (&selection->tracks);
- if (selection->tracks.empty()) {
+ sort_track_selection (ts);
+
+ if (ts.empty()) {
if (!entered_track) {
return;
}
- entered.push_back (entered_track);
- ts = &entered;
- } else {
- ts = &selection->tracks;
- }
+ ts.push_back (entered_track);
+ }
- for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
+ for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
(*i)->cut_copy_clear (*selection, op);
}
}
void
-Editor::paste (float times)
+Editor::paste (float times, bool from_context)
{
DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
- paste_internal (get_preferred_edit_position(), times);
+
+ paste_internal (get_preferred_edit_position (false, from_context), times);
}
void
if (!selection->tracks.empty()) {
/* there are some selected tracks, so paste to them */
- sort_track_selection ();
- ts = selection->tracks;
+ ts = selection->tracks.filter_to_unique_playlists ();
+ sort_track_selection (ts);
} else if (_last_cut_copy_source_track) {
/* otherwise paste to the track that the cut/copy came from;
see discussion in mantis #3333.
ri = new_regions.begin();
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+
+ for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
if ((playlist = (*i)->playlist()) == 0) {
continue;
}
begin_reversible_command (_("nudge track"));
- for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+
+ for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
if ((playlist = (*i)->playlist()) == 0) {
continue;
}
void
-Editor::insert_patch_change ()
+Editor::insert_patch_change (bool from_context)
{
RegionSelection rs = get_regions_from_selection_and_entered ();
+
if (rs.empty ()) {
return;
}
- framepos_t const p = get_preferred_edit_position (false);
+ const framepos_t p = get_preferred_edit_position (false, from_context);
Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
PatchChangeDialog d (0, _session, empty, Gtk::Stock::ADD);
if (arv->audio_region()->apply (filter, progress) == 0) {
playlist->clear_changes ();
+ playlist->clear_owned_changes ();
if (filter.results.empty ()) {
}
+ /* We might have removed regions, which alters other regions' layering_index,
+ so we need to do a recursive diff here.
+ */
+ vector<Command*> cmds;
+ playlist->rdiff (cmds);
+ _session->add_commands (cmds);
+
_session->add_command(new StatefulDiffCommand (playlist));
} else {
goto out;
}
}
+void
+Editor::toggle_solo ()
+{
+ bool new_state = false;
+ bool first = true;
+ boost::shared_ptr<RouteList> rl (new RouteList);
+
+ for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
+
+ if (!rtav) {
+ continue;
+ }
+
+ if (first) {
+ new_state = !rtav->route()->soloed ();
+ first = false;
+ }
+
+ rl->push_back (rtav->route());
+ }
+
+ _session->set_solo (rl, new_state, Session::rt_cleanup, true);
+}
+
+void
+Editor::toggle_mute ()
+{
+ bool new_state = false;
+ bool first = true;
+ boost::shared_ptr<RouteList> rl (new RouteList);
+
+ for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+ RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
+
+ if (!rtav) {
+ continue;
+ }
+
+ if (first) {
+ new_state = !rtav->route()->muted();
+ first = false;
+ }
+
+ rl->push_back (rtav->route());
+ }
+
+ _session->set_mute (rl, new_state, Session::rt_cleanup, true);
+}
+
+void
+Editor::toggle_solo_isolate ()
+{
+}
void
Editor::set_fade_length (bool in)
Editor::toggle_region_fades (int dir)
{
boost::shared_ptr<AudioRegion> ar;
- bool yn;
+ bool yn = false;
RegionSelection rs = get_regions_from_selection_and_entered ();
we have frames per bar, and beats per bar, so ...
*/
- double frames_per_beat = length / m.beats_per_bar();
+ /* XXXX METER MATH */
+
+ double frames_per_beat = length / m.divisions_per_bar();
/* beats per minute = */
AnalysisFeatureList::const_iterator x;
pl->clear_changes ();
+ pl->clear_owned_changes ();
x = positions.begin();
pl->thaw ();
+ /* We might have removed regions, which alters other regions' layering_index,
+ so we need to do a recursive diff here.
+ */
+ vector<Command*> cmds;
+ pl->rdiff (cmds);
+ _session->add_commands (cmds);
+
_session->add_command (new StatefulDiffCommand (pl));
if (select_new) {
if (!selection->tracks.empty()) {
- for (TrackSelection::iterator t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
+ /* don't waste time searching for transients in duplicate playlists.
+ */
+
+ TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+
+ for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
get_preferred_edit_position(),
d.distance(),
opt,
+ d.all_playlists(),
d.move_glued(),
d.move_markers(),
d.move_glued_markers(),
}
void
-Editor::insert_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
- bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
+Editor::insert_time (
+ framepos_t pos, framecnt_t frames, InsertTimeOption opt,
+ bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
+ )
{
bool commit = false;
begin_reversible_command (_("insert time"));
- for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
+ TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
+
+ for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
+
/* regions */
- boost::shared_ptr<Playlist> pl = (*x)->playlist();
- if (pl) {
+ /* don't operate on any playlist more than once, which could
+ * happen if "all playlists" is enabled, but there is more
+ * than 1 track using playlists "from" a given track.
+ */
- pl->clear_changes ();
- pl->clear_owned_changes ();
+ set<boost::shared_ptr<Playlist> > pl;
+
+ if (all_playlists) {
+ RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
+ if (rtav) {
+ vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
+ for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
+ pl.insert (*p);
+ }
+ }
+ } else {
+ if ((*x)->playlist ()) {
+ pl.insert ((*x)->playlist ());
+ }
+ }
+
+ for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
+
+ (*i)->clear_changes ();
+ (*i)->clear_owned_changes ();
if (opt == SplitIntersected) {
- pl->split (pos);
+ (*i)->split (pos);
}
- pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
+ (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
vector<Command*> cmds;
- pl->rdiff (cmds);
+ (*i)->rdiff (cmds);
_session->add_commands (cmds);
- _session->add_command (new StatefulDiffCommand (pl));
+ _session->add_command (new StatefulDiffCommand (*i));
commit = true;
}