2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
31 #include <gtkmm/messagedialog.h>
33 #include "pbd/error.h"
34 #include "pbd/basename.h"
35 #include "pbd/pthread_utils.h"
36 #include "pbd/memento_command.h"
37 #include "pbd/unwind.h"
38 #include "pbd/whitespace.h"
39 #include "pbd/stateful_diff_command.h"
41 #include "gtkmm2ext/utils.h"
43 #include "widgets/choice.h"
44 #include "widgets/popup.h"
45 #include "widgets/prompter.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/audioregion.h"
49 #include "ardour/boost_debug.h"
50 #include "ardour/dB.h"
51 #include "ardour/location.h"
52 #include "ardour/midi_region.h"
53 #include "ardour/midi_track.h"
54 #include "ardour/operations.h"
55 #include "ardour/playlist_factory.h"
56 #include "ardour/profile.h"
57 #include "ardour/quantize.h"
58 #include "ardour/legatize.h"
59 #include "ardour/region_factory.h"
60 #include "ardour/reverse.h"
61 #include "ardour/session.h"
62 #include "ardour/session_playlists.h"
63 #include "ardour/strip_silence.h"
64 #include "ardour/transient_detector.h"
65 #include "ardour/transpose.h"
66 #include "ardour/vca_manager.h"
68 #include "canvas/canvas.h"
71 #include "audio_region_view.h"
72 #include "audio_streamview.h"
73 #include "audio_time_axis.h"
74 #include "automation_region_view.h"
75 #include "automation_time_axis.h"
76 #include "control_point.h"
80 #include "editor_cursors.h"
81 #include "editor_drag.h"
82 #include "editor_regions.h"
83 #include "editor_routes.h"
84 #include "gui_thread.h"
85 #include "insert_remove_time_dialog.h"
86 #include "interthread_progress_window.h"
87 #include "item_counts.h"
89 #include "midi_region_view.h"
91 #include "mixer_strip.h"
92 #include "mouse_cursors.h"
93 #include "normalize_dialog.h"
95 #include "paste_context.h"
96 #include "patch_change_dialog.h"
97 #include "quantize_dialog.h"
98 #include "region_gain_line.h"
99 #include "rgb_macros.h"
100 #include "route_time_axis.h"
101 #include "selection.h"
102 #include "selection_templates.h"
103 #include "streamview.h"
104 #include "strip_silence_dialog.h"
105 #include "time_axis_view.h"
107 #include "transpose_dialog.h"
108 #include "transform_dialog.h"
109 #include "ui_config.h"
110 #include "vca_time_axis.h"
112 #include "pbd/i18n.h"
115 using namespace ARDOUR;
118 using namespace Gtkmm2ext;
119 using namespace ArdourWidgets;
120 using namespace Editing;
121 using Gtkmm2ext::Keyboard;
123 /***********************************************************************
125 ***********************************************************************/
128 Editor::undo (uint32_t n)
130 if (_session && _session->actively_recording()) {
131 /* no undo allowed while recording. Session will check also,
132 but we don't even want to get to that.
137 if (_drags->active ()) {
143 if (_session->undo_depth() == 0) {
144 undo_action->set_sensitive(false);
146 redo_action->set_sensitive(true);
147 begin_selection_op_history ();
152 Editor::redo (uint32_t n)
154 if (_session && _session->actively_recording()) {
155 /* no redo allowed while recording. Session will check also,
156 but we don't even want to get to that.
161 if (_drags->active ()) {
167 if (_session->redo_depth() == 0) {
168 redo_action->set_sensitive(false);
170 undo_action->set_sensitive(true);
171 begin_selection_op_history ();
176 Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
180 RegionSelection pre_selected_regions = selection->regions;
181 bool working_on_selection = !pre_selected_regions.empty();
183 list<boost::shared_ptr<Playlist> > used_playlists;
184 list<RouteTimeAxisView*> used_trackviews;
186 if (regions.empty()) {
190 begin_reversible_command (_("split"));
192 // if splitting a single region, and snap-to is using
193 // region boundaries, don't pay attention to them
195 if (regions.size() == 1) {
196 switch (_snap_type) {
197 case SnapToRegionStart:
198 case SnapToRegionSync:
199 case SnapToRegionEnd:
212 EditorFreeze(); /* Emit Signal */
215 for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
217 RegionSelection::iterator tmp;
219 /* XXX this test needs to be more complicated, to make sure we really
220 have something to split.
223 if (!(*a)->region()->covers (where.frame)) {
231 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
239 /* we haven't seen this playlist before */
241 /* remember used playlists so we can thaw them later */
242 used_playlists.push_back(pl);
244 TimeAxisView& tv = (*a)->get_time_axis_view();
245 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
247 used_trackviews.push_back (rtv);
254 pl->clear_changes ();
255 pl->split_region ((*a)->region(), where);
256 _session->add_command (new StatefulDiffCommand (pl));
262 latest_regionviews.clear ();
264 vector<sigc::connection> region_added_connections;
266 for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
267 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
270 while (used_playlists.size() > 0) {
271 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
273 used_playlists.pop_front();
276 for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
281 EditorThaw(); /* Emit Signal */
284 if (working_on_selection) {
285 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
287 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
288 /* There are three classes of regions that we might want selected after
289 splitting selected regions:
290 - regions selected before the split operation, and unaffected by it
291 - newly-created regions before the split
292 - newly-created regions after the split
295 if (rsas & Existing) {
296 // region selections that existed before the split.
297 selection->add ( pre_selected_regions );
300 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
301 if ((*ri)->region()->position() < where.frame) {
302 // new regions created before the split
303 if (rsas & NewlyCreatedLeft) {
304 selection->add (*ri);
307 // new regions created after the split
308 if (rsas & NewlyCreatedRight) {
309 selection->add (*ri);
314 if( working_on_selection ) {
315 selection->add (latest_regionviews); //these are the new regions created after the split
319 commit_reversible_command ();
322 /** Move one extreme of the current range selection. If more than one range is selected,
323 * the start of the earliest range or the end of the latest range is moved.
325 * @param move_end true to move the end of the current range selection, false to move
327 * @param next true to move the extreme to the next region boundary, false to move to
331 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
333 if (selection->time.start() == selection->time.end_frame()) {
337 framepos_t start = selection->time.start ();
338 framepos_t end = selection->time.end_frame ();
340 /* the position of the thing we may move */
341 framepos_t pos = move_end ? end : start;
342 int dir = next ? 1 : -1;
344 /* so we don't find the current region again */
345 if (dir > 0 || pos > 0) {
349 framepos_t const target = get_region_boundary (pos, dir, true, false);
364 begin_reversible_selection_op (_("alter selection"));
365 selection->set_preserving_all_ranges (start, end);
366 commit_reversible_selection_op ();
370 Editor::nudge_forward_release (GdkEventButton* ev)
372 if (ev->state & Keyboard::PrimaryModifier) {
373 nudge_forward (false, true);
375 nudge_forward (false, false);
381 Editor::nudge_backward_release (GdkEventButton* ev)
383 if (ev->state & Keyboard::PrimaryModifier) {
384 nudge_backward (false, true);
386 nudge_backward (false, false);
393 Editor::nudge_forward (bool next, bool force_playhead)
396 framepos_t next_distance;
402 RegionSelection rs = get_regions_from_selection_and_entered ();
404 if (!force_playhead && !rs.empty()) {
406 begin_reversible_command (_("nudge regions forward"));
408 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
409 boost::shared_ptr<Region> r ((*i)->region());
411 distance = get_nudge_distance (r->position(), next_distance);
414 distance = next_distance;
418 r->set_position (r->position() + distance);
419 _session->add_command (new StatefulDiffCommand (r));
422 commit_reversible_command ();
425 } else if (!force_playhead && !selection->markers.empty()) {
428 bool in_command = false;
429 const int32_t divisions = get_grid_music_divisions (0);
431 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
433 Location* loc = find_location_from_marker ((*i), is_start);
437 XMLNode& before (loc->get_state());
440 distance = get_nudge_distance (loc->start(), next_distance);
442 distance = next_distance;
444 if (max_framepos - distance > loc->start() + loc->length()) {
445 loc->set_start (loc->start() + distance, false, true, divisions);
447 loc->set_start (max_framepos - loc->length(), false, true, divisions);
450 distance = get_nudge_distance (loc->end(), next_distance);
452 distance = next_distance;
454 if (max_framepos - distance > loc->end()) {
455 loc->set_end (loc->end() + distance, false, true, divisions);
457 loc->set_end (max_framepos, false, true, divisions);
459 if (loc->is_session_range()) {
460 _session->set_end_is_free (false);
464 begin_reversible_command (_("nudge location forward"));
467 XMLNode& after (loc->get_state());
468 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
473 commit_reversible_command ();
476 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
477 _session->request_locate (playhead_cursor->current_frame () + distance);
482 Editor::nudge_backward (bool next, bool force_playhead)
485 framepos_t next_distance;
491 RegionSelection rs = get_regions_from_selection_and_entered ();
493 if (!force_playhead && !rs.empty()) {
495 begin_reversible_command (_("nudge regions backward"));
497 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
498 boost::shared_ptr<Region> r ((*i)->region());
500 distance = get_nudge_distance (r->position(), next_distance);
503 distance = next_distance;
508 if (r->position() > distance) {
509 r->set_position (r->position() - distance);
513 _session->add_command (new StatefulDiffCommand (r));
516 commit_reversible_command ();
518 } else if (!force_playhead && !selection->markers.empty()) {
521 bool in_command = false;
523 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
525 Location* loc = find_location_from_marker ((*i), is_start);
529 XMLNode& before (loc->get_state());
532 distance = get_nudge_distance (loc->start(), next_distance);
534 distance = next_distance;
536 if (distance < loc->start()) {
537 loc->set_start (loc->start() - distance, false, true, get_grid_music_divisions(0));
539 loc->set_start (0, false, true, get_grid_music_divisions(0));
542 distance = get_nudge_distance (loc->end(), next_distance);
545 distance = next_distance;
548 if (distance < loc->end() - loc->length()) {
549 loc->set_end (loc->end() - distance, false, true, get_grid_music_divisions(0));
551 loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
553 if (loc->is_session_range()) {
554 _session->set_end_is_free (false);
558 begin_reversible_command (_("nudge location forward"));
561 XMLNode& after (loc->get_state());
562 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
566 commit_reversible_command ();
571 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
573 if (playhead_cursor->current_frame () > distance) {
574 _session->request_locate (playhead_cursor->current_frame () - distance);
576 _session->goto_start();
582 Editor::nudge_forward_capture_offset ()
584 RegionSelection rs = get_regions_from_selection_and_entered ();
586 if (!_session || rs.empty()) {
590 begin_reversible_command (_("nudge forward"));
592 framepos_t const distance = _session->worst_output_latency();
594 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
595 boost::shared_ptr<Region> r ((*i)->region());
598 r->set_position (r->position() + distance);
599 _session->add_command(new StatefulDiffCommand (r));
602 commit_reversible_command ();
606 Editor::nudge_backward_capture_offset ()
608 RegionSelection rs = get_regions_from_selection_and_entered ();
610 if (!_session || rs.empty()) {
614 begin_reversible_command (_("nudge backward"));
616 framepos_t const distance = _session->worst_output_latency();
618 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
619 boost::shared_ptr<Region> r ((*i)->region());
623 if (r->position() > distance) {
624 r->set_position (r->position() - distance);
628 _session->add_command(new StatefulDiffCommand (r));
631 commit_reversible_command ();
634 struct RegionSelectionPositionSorter {
635 bool operator() (RegionView* a, RegionView* b) {
636 return a->region()->position() < b->region()->position();
641 Editor::sequence_regions ()
644 framepos_t r_end_prev;
652 RegionSelection rs = get_regions_from_selection_and_entered ();
653 rs.sort(RegionSelectionPositionSorter());
657 bool in_command = false;
659 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
660 boost::shared_ptr<Region> r ((*i)->region());
668 if(r->position_locked())
675 r->set_position(r_end_prev);
679 begin_reversible_command (_("sequence regions"));
682 _session->add_command (new StatefulDiffCommand (r));
684 r_end=r->position() + r->length();
690 commit_reversible_command ();
699 Editor::move_to_start ()
701 _session->goto_start ();
705 Editor::move_to_end ()
708 _session->request_locate (_session->current_end_frame());
712 Editor::build_region_boundary_cache ()
715 vector<RegionPoint> interesting_points;
716 boost::shared_ptr<Region> r;
717 TrackViewList tracks;
720 region_boundary_cache.clear ();
726 bool maybe_first_frame = false;
728 switch (_snap_type) {
729 case SnapToRegionStart:
730 interesting_points.push_back (Start);
731 maybe_first_frame = true;
733 case SnapToRegionEnd:
734 interesting_points.push_back (End);
736 case SnapToRegionSync:
737 interesting_points.push_back (SyncPoint);
739 case SnapToRegionBoundary:
740 interesting_points.push_back (Start);
741 interesting_points.push_back (End);
742 maybe_first_frame = true;
745 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
746 abort(); /*NOTREACHED*/
750 TimeAxisView *ontrack = 0;
753 if (!selection->tracks.empty()) {
754 tlist = selection->tracks.filter_to_unique_playlists ();
756 tlist = track_views.filter_to_unique_playlists ();
759 if (maybe_first_frame) {
760 TrackViewList::const_iterator i;
761 for (i = tlist.begin(); i != tlist.end(); ++i) {
762 boost::shared_ptr<Playlist> pl = (*i)->playlist();
763 if (pl && pl->count_regions_at (0)) {
764 region_boundary_cache.push_back (0);
770 while (pos < _session->current_end_frame() && !at_end) {
773 framepos_t lpos = max_framepos;
775 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
777 if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
778 if (*p == interesting_points.back()) {
781 /* move to next point type */
787 rpos = r->first_frame();
791 rpos = r->last_frame();
795 rpos = r->sync_position ();
806 /* prevent duplicates, but we don't use set<> because we want to be able
810 vector<framepos_t>::iterator ri;
812 for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
818 if (ri == region_boundary_cache.end()) {
819 region_boundary_cache.push_back (rpos);
826 /* finally sort to be sure that the order is correct */
828 sort (region_boundary_cache.begin(), region_boundary_cache.end());
831 boost::shared_ptr<Region>
832 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
834 TrackViewList::iterator i;
835 framepos_t closest = max_framepos;
836 boost::shared_ptr<Region> ret;
839 framepos_t track_frame;
840 RouteTimeAxisView *rtav;
842 for (i = tracks.begin(); i != tracks.end(); ++i) {
845 boost::shared_ptr<Region> r;
849 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
855 rpos = r->first_frame ();
859 rpos = r->last_frame ();
863 rpos = r->sync_position ();
868 distance = rpos - frame;
870 distance = frame - rpos;
873 if (distance < closest) {
885 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
887 framecnt_t distance = max_framepos;
888 framepos_t current_nearest = -1;
890 for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
891 framepos_t contender;
894 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
900 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
904 d = ::llabs (pos - contender);
907 current_nearest = contender;
912 return current_nearest;
916 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
921 if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
923 if (!selection->tracks.empty()) {
925 target = find_next_region_boundary (pos, dir, selection->tracks);
929 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
930 get_onscreen_tracks (tvl);
931 target = find_next_region_boundary (pos, dir, tvl);
933 target = find_next_region_boundary (pos, dir, track_views);
939 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
940 get_onscreen_tracks (tvl);
941 target = find_next_region_boundary (pos, dir, tvl);
943 target = find_next_region_boundary (pos, dir, track_views);
951 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
953 framepos_t pos = playhead_cursor->current_frame ();
960 // so we don't find the current region again..
961 if (dir > 0 || pos > 0) {
965 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
969 _session->request_locate (target);
973 Editor::cursor_to_next_region_boundary (bool with_selection)
975 cursor_to_region_boundary (with_selection, 1);
979 Editor::cursor_to_previous_region_boundary (bool with_selection)
981 cursor_to_region_boundary (with_selection, -1);
985 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
987 boost::shared_ptr<Region> r;
988 framepos_t pos = cursor->current_frame ();
994 TimeAxisView *ontrack = 0;
996 // so we don't find the current region again..
1000 if (!selection->tracks.empty()) {
1002 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1004 } else if (clicked_axisview) {
1007 t.push_back (clicked_axisview);
1009 r = find_next_region (pos, point, dir, t, &ontrack);
1013 r = find_next_region (pos, point, dir, track_views, &ontrack);
1022 pos = r->first_frame ();
1026 pos = r->last_frame ();
1030 pos = r->sync_position ();
1034 if (cursor == playhead_cursor) {
1035 _session->request_locate (pos);
1037 cursor->set_position (pos);
1042 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1044 cursor_to_region_point (cursor, point, 1);
1048 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1050 cursor_to_region_point (cursor, point, -1);
1054 Editor::cursor_to_selection_start (EditorCursor *cursor)
1058 switch (mouse_mode) {
1060 if (!selection->regions.empty()) {
1061 pos = selection->regions.start();
1066 if (!selection->time.empty()) {
1067 pos = selection->time.start ();
1075 if (cursor == playhead_cursor) {
1076 _session->request_locate (pos);
1078 cursor->set_position (pos);
1083 Editor::cursor_to_selection_end (EditorCursor *cursor)
1087 switch (mouse_mode) {
1089 if (!selection->regions.empty()) {
1090 pos = selection->regions.end_frame();
1095 if (!selection->time.empty()) {
1096 pos = selection->time.end_frame ();
1104 if (cursor == playhead_cursor) {
1105 _session->request_locate (pos);
1107 cursor->set_position (pos);
1112 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1122 if (selection->markers.empty()) {
1126 if (!mouse_frame (mouse, ignored)) {
1130 add_location_mark (mouse);
1133 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1137 framepos_t pos = loc->start();
1139 // so we don't find the current region again..
1140 if (dir > 0 || pos > 0) {
1144 if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1148 loc->move_to (target, 0);
1152 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1154 selected_marker_to_region_boundary (with_selection, 1);
1158 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1160 selected_marker_to_region_boundary (with_selection, -1);
1164 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1166 boost::shared_ptr<Region> r;
1171 if (!_session || selection->markers.empty()) {
1175 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1179 TimeAxisView *ontrack = 0;
1183 // so we don't find the current region again..
1187 if (!selection->tracks.empty()) {
1189 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1193 r = find_next_region (pos, point, dir, track_views, &ontrack);
1202 pos = r->first_frame ();
1206 pos = r->last_frame ();
1210 pos = r->adjust_to_sync (r->first_frame());
1214 loc->move_to (pos, 0);
1218 Editor::selected_marker_to_next_region_point (RegionPoint point)
1220 selected_marker_to_region_point (point, 1);
1224 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1226 selected_marker_to_region_point (point, -1);
1230 Editor::selected_marker_to_selection_start ()
1236 if (!_session || selection->markers.empty()) {
1240 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1244 switch (mouse_mode) {
1246 if (!selection->regions.empty()) {
1247 pos = selection->regions.start();
1252 if (!selection->time.empty()) {
1253 pos = selection->time.start ();
1261 loc->move_to (pos, 0);
1265 Editor::selected_marker_to_selection_end ()
1271 if (!_session || selection->markers.empty()) {
1275 if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1279 switch (mouse_mode) {
1281 if (!selection->regions.empty()) {
1282 pos = selection->regions.end_frame();
1287 if (!selection->time.empty()) {
1288 pos = selection->time.end_frame ();
1296 loc->move_to (pos, 0);
1300 Editor::scroll_playhead (bool forward)
1302 framepos_t pos = playhead_cursor->current_frame ();
1303 framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1306 if (pos == max_framepos) {
1310 if (pos < max_framepos - delta) {
1329 _session->request_locate (pos);
1333 Editor::cursor_align (bool playhead_to_edit)
1339 if (playhead_to_edit) {
1341 if (selection->markers.empty()) {
1345 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1348 const int32_t divisions = get_grid_music_divisions (0);
1349 /* move selected markers to playhead */
1351 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1354 Location* loc = find_location_from_marker (*i, ignored);
1356 if (loc->is_mark()) {
1357 loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
1359 loc->set (playhead_cursor->current_frame (),
1360 playhead_cursor->current_frame () + loc->length(), true, divisions);
1367 Editor::scroll_backward (float pages)
1369 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1370 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1373 if (leftmost_frame < cnt) {
1376 frame = leftmost_frame - cnt;
1379 reset_x_origin (frame);
1383 Editor::scroll_forward (float pages)
1385 framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1386 framepos_t const cnt = (framepos_t) floor (pages * one_page);
1389 if (max_framepos - cnt < leftmost_frame) {
1390 frame = max_framepos - cnt;
1392 frame = leftmost_frame + cnt;
1395 reset_x_origin (frame);
1399 Editor::scroll_tracks_down ()
1401 double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1402 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1403 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1406 vertical_adjustment.set_value (vert_value);
1410 Editor::scroll_tracks_up ()
1412 vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1416 Editor::scroll_tracks_down_line ()
1418 double vert_value = vertical_adjustment.get_value() + 60;
1420 if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1421 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1424 vertical_adjustment.set_value (vert_value);
1428 Editor::scroll_tracks_up_line ()
1430 reset_y_origin (vertical_adjustment.get_value() - 60);
1434 Editor::select_topmost_track ()
1436 const double top_of_trackviews = vertical_adjustment.get_value();
1437 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1438 if ((*t)->hidden()) {
1441 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1443 selection->set (*t);
1450 Editor::scroll_down_one_track (bool skip_child_views)
1452 TrackViewList::reverse_iterator next = track_views.rend();
1453 const double top_of_trackviews = vertical_adjustment.get_value();
1455 for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1456 if ((*t)->hidden()) {
1460 /* If this is the upper-most visible trackview, we want to display
1461 * the one above it (next)
1463 * Note that covers_y_position() is recursive and includes child views
1465 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1468 if (skip_child_views) {
1471 /* automation lane (one level, non-recursive)
1473 * - if no automation lane exists -> move to next tack
1474 * - if the first (here: bottom-most) matches -> move to next tack
1475 * - if no y-axis match is found -> the current track is at the top
1476 * -> move to last (here: top-most) automation lane
1478 TimeAxisView::Children kids = (*t)->get_child_list();
1479 TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1481 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1482 if ((*ci)->hidden()) {
1486 std::pair<TimeAxisView*,double> dev;
1487 dev = (*ci)->covers_y_position (top_of_trackviews);
1489 /* some automation lane is currently at the top */
1490 if (ci == kids.rbegin()) {
1491 /* first (bottom-most) autmation lane is at the top.
1492 * -> move to next track
1501 if (nkid != kids.rend()) {
1502 ensure_time_axis_view_is_visible (**nkid, true);
1510 /* move to the track below the first one that covers the */
1512 if (next != track_views.rend()) {
1513 ensure_time_axis_view_is_visible (**next, true);
1521 Editor::scroll_up_one_track (bool skip_child_views)
1523 TrackViewList::iterator prev = track_views.end();
1524 double top_of_trackviews = vertical_adjustment.get_value ();
1526 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1528 if ((*t)->hidden()) {
1532 /* find the trackview at the top of the trackview group
1534 * Note that covers_y_position() is recursive and includes child views
1536 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1539 if (skip_child_views) {
1542 /* automation lane (one level, non-recursive)
1544 * - if no automation lane exists -> move to prev tack
1545 * - if no y-axis match is found -> the current track is at the top -> move to prev track
1546 * (actually last automation lane of previous track, see below)
1547 * - if first (top-most) lane is at the top -> move to this track
1548 * - else move up one lane
1550 TimeAxisView::Children kids = (*t)->get_child_list();
1551 TimeAxisView::Children::iterator pkid = kids.end();
1553 for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1554 if ((*ci)->hidden()) {
1558 std::pair<TimeAxisView*,double> dev;
1559 dev = (*ci)->covers_y_position (top_of_trackviews);
1561 /* some automation lane is currently at the top */
1562 if (ci == kids.begin()) {
1563 /* first (top-most) autmation lane is at the top.
1564 * jump directly to this track's top
1566 ensure_time_axis_view_is_visible (**t, true);
1569 else if (pkid != kids.end()) {
1570 /* some other automation lane is at the top.
1571 * move up to prev automation lane.
1573 ensure_time_axis_view_is_visible (**pkid, true);
1576 assert(0); // not reached
1587 if (prev != track_views.end()) {
1588 // move to bottom-most automation-lane of the previous track
1589 TimeAxisView::Children kids = (*prev)->get_child_list();
1590 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1591 if (!skip_child_views) {
1592 // find the last visible lane
1593 for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1594 if (!(*ci)->hidden()) {
1600 if (pkid != kids.rend()) {
1601 ensure_time_axis_view_is_visible (**pkid, true);
1603 ensure_time_axis_view_is_visible (**prev, true);
1612 Editor::scroll_left_step ()
1614 framepos_t xdelta = (current_page_samples() / 8);
1616 if (leftmost_frame > xdelta) {
1617 reset_x_origin (leftmost_frame - xdelta);
1625 Editor::scroll_right_step ()
1627 framepos_t xdelta = (current_page_samples() / 8);
1629 if (max_framepos - xdelta > leftmost_frame) {
1630 reset_x_origin (leftmost_frame + xdelta);
1632 reset_x_origin (max_framepos - current_page_samples());
1637 Editor::scroll_left_half_page ()
1639 framepos_t xdelta = (current_page_samples() / 2);
1640 if (leftmost_frame > xdelta) {
1641 reset_x_origin (leftmost_frame - xdelta);
1648 Editor::scroll_right_half_page ()
1650 framepos_t xdelta = (current_page_samples() / 2);
1651 if (max_framepos - xdelta > leftmost_frame) {
1652 reset_x_origin (leftmost_frame + xdelta);
1654 reset_x_origin (max_framepos - current_page_samples());
1661 Editor::tav_zoom_step (bool coarser)
1663 DisplaySuspender ds;
1667 if (selection->tracks.empty()) {
1670 ts = &selection->tracks;
1673 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1674 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1675 tv->step_height (coarser);
1680 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1682 DisplaySuspender ds;
1686 if (selection->tracks.empty() || force_all) {
1689 ts = &selection->tracks;
1692 for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1693 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1694 uint32_t h = tv->current_height ();
1699 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1704 tv->set_height (h + 5);
1710 Editor::temporal_zoom_step_mouse_focus_scale (bool zoom_out, double scale)
1712 Editing::ZoomFocus temp_focus = zoom_focus;
1713 zoom_focus = Editing::ZoomFocusMouse;
1714 temporal_zoom_step_scale (zoom_out, scale);
1715 zoom_focus = temp_focus;
1719 Editor::temporal_zoom_step_mouse_focus (bool zoom_out)
1721 temporal_zoom_step_mouse_focus_scale (zoom_out, 2.0);
1725 Editor::temporal_zoom_step (bool zoom_out)
1727 temporal_zoom_step_scale (zoom_out, 2.0);
1731 Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
1733 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
1735 framecnt_t nspp = samples_per_pixel;
1739 if (nspp == samples_per_pixel) {
1744 if (nspp == samples_per_pixel) {
1749 // ToDo: encapsulate all of this into something like editor::get_session_extents() or editor::leftmost(), rightmost()
1751 //ToDo: also incorporate automation regions (in case the session has no audio/midi but is just used for automating plugins or the like)
1753 //calculate the extents of all regions in every playlist
1754 framecnt_t session_extent_start = 0;
1755 framecnt_t session_extent_end = 0;
1757 boost::shared_ptr<RouteList> rl = _session->get_routes();
1758 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1759 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*r);
1761 boost::shared_ptr<Playlist> pl = tr->playlist();
1763 pair<framepos_t, framepos_t> e;
1764 e = pl->get_extent();
1765 if (e.first < session_extent_start) {
1766 session_extent_start = e.first;
1768 if (e.second > session_extent_end) {
1769 session_extent_end = e.second;
1775 framecnt_t session_extents = session_extent_end - session_extent_start;
1777 //in a session with no regions, use the start/end markers to set max zoom
1778 framecnt_t const session_length = _session->current_end_frame() - _session->current_start_frame ();
1779 if ( session_length > session_extents )
1780 session_extents = session_length;
1782 //in a session with no regions or start/end markers, use 2 minutes to set max zoom
1783 framecnt_t const min_length = _session->nominal_frame_rate()*60*2;
1784 if ( min_length > session_extents )
1785 session_extents = min_length;
1787 //convert to samples-per-pixel and limit our zoom to this value
1788 framecnt_t session_extents_pp = session_extents / _visible_canvas_width;
1789 if (nspp > session_extents_pp)
1790 nspp = session_extents_pp;
1793 temporal_zoom (nspp);
1797 Editor::temporal_zoom (framecnt_t fpp)
1803 framepos_t current_page = current_page_samples();
1804 framepos_t current_leftmost = leftmost_frame;
1805 framepos_t current_rightmost;
1806 framepos_t current_center;
1807 framepos_t new_page_size;
1808 framepos_t half_page_size;
1809 framepos_t leftmost_after_zoom = 0;
1811 bool in_track_canvas;
1812 bool use_mouse_frame = true;
1816 if (fpp == samples_per_pixel) {
1820 // Imposing an arbitrary limit to zoom out as too much zoom out produces
1821 // segfaults for lack of memory. If somebody decides this is not high enough I
1822 // believe it can be raisen to higher values but some limit must be in place.
1824 // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1825 // all of which is used for the editor track displays. The whole day
1826 // would be 4147200000 samples, so 2592000 samples per pixel.
1828 nfpp = min (fpp, (framecnt_t) 2592000);
1829 nfpp = max ((framecnt_t) 1, nfpp);
1831 new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1832 half_page_size = new_page_size / 2;
1834 switch (zoom_focus) {
1836 leftmost_after_zoom = current_leftmost;
1839 case ZoomFocusRight:
1840 current_rightmost = leftmost_frame + current_page;
1841 if (current_rightmost < new_page_size) {
1842 leftmost_after_zoom = 0;
1844 leftmost_after_zoom = current_rightmost - new_page_size;
1848 case ZoomFocusCenter:
1849 current_center = current_leftmost + (current_page/2);
1850 if (current_center < half_page_size) {
1851 leftmost_after_zoom = 0;
1853 leftmost_after_zoom = current_center - half_page_size;
1857 case ZoomFocusPlayhead:
1858 /* centre playhead */
1859 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1862 leftmost_after_zoom = 0;
1863 } else if (l > max_framepos) {
1864 leftmost_after_zoom = max_framepos - new_page_size;
1866 leftmost_after_zoom = (framepos_t) l;
1870 case ZoomFocusMouse:
1871 /* try to keep the mouse over the same point in the display */
1873 if (_drags->active()) {
1874 where = _drags->current_pointer_frame ();
1875 } else if (!mouse_frame (where, in_track_canvas)) {
1876 use_mouse_frame = false;
1879 if (use_mouse_frame) {
1880 l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1883 leftmost_after_zoom = 0;
1884 } else if (l > max_framepos) {
1885 leftmost_after_zoom = max_framepos - new_page_size;
1887 leftmost_after_zoom = (framepos_t) l;
1890 /* use playhead instead */
1891 where = playhead_cursor->current_frame ();
1893 if (where < half_page_size) {
1894 leftmost_after_zoom = 0;
1896 leftmost_after_zoom = where - half_page_size;
1902 /* try to keep the edit point in the same place */
1903 where = get_preferred_edit_position ();
1907 double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1910 leftmost_after_zoom = 0;
1911 } else if (l > max_framepos) {
1912 leftmost_after_zoom = max_framepos - new_page_size;
1914 leftmost_after_zoom = (framepos_t) l;
1918 /* edit point not defined */
1925 // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1927 reposition_and_zoom (leftmost_after_zoom, nfpp);
1931 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1933 /* this func helps make sure we leave a little space
1934 at each end of the editor so that the zoom doesn't fit the region
1935 precisely to the screen.
1938 GdkScreen* screen = gdk_screen_get_default ();
1939 const gint pixwidth = gdk_screen_get_width (screen);
1940 const gint mmwidth = gdk_screen_get_width_mm (screen);
1941 const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1942 const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1944 const framepos_t range = end - start;
1945 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1946 const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1948 if (start > extra_samples) {
1949 start -= extra_samples;
1954 if (max_framepos - extra_samples > end) {
1955 end += extra_samples;
1962 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1964 start = max_framepos;
1968 //ToDo: if notes are selected, set extents to that selection
1970 //ToDo: if control points are selected, set extents to that selection
1972 if ( !selection->regions.empty() ) {
1973 RegionSelection rs = get_regions_from_selection_and_entered ();
1975 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1977 if ((*i)->region()->position() < start) {
1978 start = (*i)->region()->position();
1981 if ((*i)->region()->last_frame() + 1 > end) {
1982 end = (*i)->region()->last_frame() + 1;
1986 } else if (!selection->time.empty()) {
1987 start = selection->time.start();
1988 end = selection->time.end_frame();
1990 ret = false; //no selection found
1993 if ((start == 0 && end == 0) || end < start) {
2002 Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
2004 if (!selection) return;
2006 //ToDo: if notes are selected, zoom to that
2008 //ToDo: if control points are selected, zoom to that
2010 if (axes == Horizontal || axes == Both) {
2012 framepos_t start, end;
2013 if (get_selection_extents (start, end)) {
2014 calc_extra_zoom_edges (start, end);
2015 temporal_zoom_by_frame (start, end);
2019 if (axes == Vertical || axes == Both) {
2025 Editor::temporal_zoom_session ()
2027 ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
2030 framecnt_t start = _session->current_start_frame();
2031 framecnt_t end = _session->current_end_frame();
2033 if (_session->actively_recording () ) {
2034 framepos_t cur = playhead_cursor->current_frame ();
2036 /* recording beyond the end marker; zoom out
2037 * by 5 seconds more so that if 'follow
2038 * playhead' is active we don't immediately
2041 end = cur + _session->frame_rate() * 5;
2045 if ((start == 0 && end == 0) || end < start) {
2049 calc_extra_zoom_edges(start, end);
2051 temporal_zoom_by_frame (start, end);
2056 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2058 if (!_session) return;
2060 if ((start == 0 && end == 0) || end < start) {
2064 framepos_t range = end - start;
2066 const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2068 framepos_t new_page = range;
2069 framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2070 framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2072 if (new_leftmost > middle) {
2076 if (new_leftmost < 0) {
2080 reposition_and_zoom (new_leftmost, new_fpp);
2084 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2090 framecnt_t range_before = frame - leftmost_frame;
2094 if (samples_per_pixel <= 1) {
2097 new_spp = samples_per_pixel + (samples_per_pixel/2);
2099 range_before += range_before/2;
2101 if (samples_per_pixel >= 1) {
2102 new_spp = samples_per_pixel - (samples_per_pixel/2);
2104 /* could bail out here since we cannot zoom any finer,
2105 but leave that to the equality test below
2107 new_spp = samples_per_pixel;
2110 range_before -= range_before/2;
2113 if (new_spp == samples_per_pixel) {
2117 /* zoom focus is automatically taken as @param frame when this
2121 framepos_t new_leftmost = frame - (framepos_t)range_before;
2123 if (new_leftmost > frame) {
2127 if (new_leftmost < 0) {
2131 reposition_and_zoom (new_leftmost, new_spp);
2136 Editor::choose_new_marker_name(string &name) {
2138 if (!UIConfiguration::instance().get_name_new_markers()) {
2139 /* don't prompt user for a new name */
2143 Prompter dialog (true);
2145 dialog.set_prompt (_("New Name:"));
2147 dialog.set_title (_("New Location Marker"));
2149 dialog.set_name ("MarkNameWindow");
2150 dialog.set_size_request (250, -1);
2151 dialog.set_position (Gtk::WIN_POS_MOUSE);
2153 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2154 dialog.set_initial_text (name);
2158 switch (dialog.run ()) {
2159 case RESPONSE_ACCEPT:
2165 dialog.get_result(name);
2172 Editor::add_location_from_selection ()
2176 if (selection->time.empty()) {
2180 if (_session == 0 || clicked_axisview == 0) {
2184 framepos_t start = selection->time[clicked_selection].start;
2185 framepos_t end = selection->time[clicked_selection].end;
2187 _session->locations()->next_available_name(rangename,"selection");
2188 Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
2190 begin_reversible_command (_("add marker"));
2192 XMLNode &before = _session->locations()->get_state();
2193 _session->locations()->add (location, true);
2194 XMLNode &after = _session->locations()->get_state();
2195 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2197 commit_reversible_command ();
2201 Editor::add_location_mark (framepos_t where)
2205 select_new_marker = true;
2207 _session->locations()->next_available_name(markername,"mark");
2208 if (!choose_new_marker_name(markername)) {
2211 Location *location = new Location (*_session, where, where, markername, Location::IsMark, get_grid_music_divisions (0));
2212 begin_reversible_command (_("add marker"));
2214 XMLNode &before = _session->locations()->get_state();
2215 _session->locations()->add (location, true);
2216 XMLNode &after = _session->locations()->get_state();
2217 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2219 commit_reversible_command ();
2223 Editor::set_session_start_from_playhead ()
2229 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2230 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2232 XMLNode &before = loc->get_state();
2234 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2236 XMLNode &after = loc->get_state();
2238 begin_reversible_command (_("Set session start"));
2240 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2242 commit_reversible_command ();
2247 Editor::set_session_end_from_playhead ()
2253 if ((loc = _session->locations()->session_range_location()) == 0) { //should never happen
2254 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2256 XMLNode &before = loc->get_state();
2258 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2260 XMLNode &after = loc->get_state();
2262 begin_reversible_command (_("Set session start"));
2264 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2266 commit_reversible_command ();
2269 _session->set_end_is_free (false);
2274 Editor::toggle_location_at_playhead_cursor ()
2276 if (!do_remove_location_at_playhead_cursor())
2278 add_location_from_playhead_cursor();
2283 Editor::add_location_from_playhead_cursor ()
2285 add_location_mark (_session->audible_frame());
2289 Editor::do_remove_location_at_playhead_cursor ()
2291 bool removed = false;
2294 XMLNode &before = _session->locations()->get_state();
2296 //find location(s) at this time
2297 Locations::LocationList locs;
2298 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2299 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2300 if ((*i)->is_mark()) {
2301 _session->locations()->remove (*i);
2308 begin_reversible_command (_("remove marker"));
2309 XMLNode &after = _session->locations()->get_state();
2310 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2311 commit_reversible_command ();
2318 Editor::remove_location_at_playhead_cursor ()
2320 do_remove_location_at_playhead_cursor ();
2323 /** Add a range marker around each selected region */
2325 Editor::add_locations_from_region ()
2327 RegionSelection rs = get_regions_from_selection_and_entered ();
2332 bool commit = false;
2334 XMLNode &before = _session->locations()->get_state();
2336 for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2338 boost::shared_ptr<Region> region = (*i)->region ();
2340 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
2342 _session->locations()->add (location, true);
2347 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2348 XMLNode &after = _session->locations()->get_state();
2349 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2350 commit_reversible_command ();
2354 /** Add a single range marker around all selected regions */
2356 Editor::add_location_from_region ()
2358 RegionSelection rs = get_regions_from_selection_and_entered ();
2364 XMLNode &before = _session->locations()->get_state();
2368 if (rs.size() > 1) {
2369 _session->locations()->next_available_name(markername, "regions");
2371 RegionView* rv = *(rs.begin());
2372 boost::shared_ptr<Region> region = rv->region();
2373 markername = region->name();
2376 if (!choose_new_marker_name(markername)) {
2380 // single range spanning all selected
2381 Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
2382 _session->locations()->add (location, true);
2384 begin_reversible_command (_("add marker"));
2385 XMLNode &after = _session->locations()->get_state();
2386 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2387 commit_reversible_command ();
2393 Editor::jump_forward_to_mark ()
2399 framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2405 _session->request_locate (pos, _session->transport_rolling());
2409 Editor::jump_backward_to_mark ()
2415 framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2417 //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
2418 if ( _session->transport_rolling() ) {
2419 if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
2420 framepos_t prior = _session->locations()->first_mark_before ( pos );
2429 _session->request_locate (pos, _session->transport_rolling());
2435 framepos_t const pos = _session->audible_frame ();
2438 _session->locations()->next_available_name (markername, "mark");
2440 if (!choose_new_marker_name (markername)) {
2444 _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark, 0), true);
2448 Editor::clear_markers ()
2451 begin_reversible_command (_("clear markers"));
2453 XMLNode &before = _session->locations()->get_state();
2454 _session->locations()->clear_markers ();
2455 XMLNode &after = _session->locations()->get_state();
2456 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2458 commit_reversible_command ();
2463 Editor::clear_ranges ()
2466 begin_reversible_command (_("clear ranges"));
2468 XMLNode &before = _session->locations()->get_state();
2470 _session->locations()->clear_ranges ();
2472 XMLNode &after = _session->locations()->get_state();
2473 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2475 commit_reversible_command ();
2480 Editor::clear_locations ()
2482 begin_reversible_command (_("clear locations"));
2484 XMLNode &before = _session->locations()->get_state();
2485 _session->locations()->clear ();
2486 XMLNode &after = _session->locations()->get_state();
2487 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2489 commit_reversible_command ();
2493 Editor::unhide_markers ()
2495 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2496 Location *l = (*i).first;
2497 if (l->is_hidden() && l->is_mark()) {
2498 l->set_hidden(false, this);
2504 Editor::unhide_ranges ()
2506 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2507 Location *l = (*i).first;
2508 if (l->is_hidden() && l->is_range_marker()) {
2509 l->set_hidden(false, this);
2514 /* INSERT/REPLACE */
2517 Editor::insert_region_list_selection (float times)
2519 RouteTimeAxisView *tv = 0;
2520 boost::shared_ptr<Playlist> playlist;
2522 if (clicked_routeview != 0) {
2523 tv = clicked_routeview;
2524 } else if (!selection->tracks.empty()) {
2525 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2528 } else if (entered_track != 0) {
2529 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2536 if ((playlist = tv->playlist()) == 0) {
2540 boost::shared_ptr<Region> region = _regions->get_single_selection ();
2545 begin_reversible_command (_("insert region"));
2546 playlist->clear_changes ();
2547 playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2548 if (Config->get_edit_mode() == Ripple)
2549 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2551 _session->add_command(new StatefulDiffCommand (playlist));
2552 commit_reversible_command ();
2555 /* BUILT-IN EFFECTS */
2558 Editor::reverse_selection ()
2563 /* GAIN ENVELOPE EDITING */
2566 Editor::edit_envelope ()
2573 Editor::transition_to_rolling (bool fwd)
2579 if (_session->config.get_external_sync()) {
2580 switch (Config->get_sync_source()) {
2584 /* transport controlled by the master */
2589 if (_session->is_auditioning()) {
2590 _session->cancel_audition ();
2594 _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2598 Editor::play_from_start ()
2600 _session->request_locate (_session->current_start_frame(), true);
2604 Editor::play_from_edit_point ()
2606 _session->request_locate (get_preferred_edit_position(), true);
2610 Editor::play_from_edit_point_and_return ()
2612 framepos_t start_frame;
2613 framepos_t return_frame;
2615 start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2617 if (_session->transport_rolling()) {
2618 _session->request_locate (start_frame, false);
2622 /* don't reset the return frame if its already set */
2624 if ((return_frame = _session->requested_return_frame()) < 0) {
2625 return_frame = _session->audible_frame();
2628 if (start_frame >= 0) {
2629 _session->request_roll_at_and_return (start_frame, return_frame);
2634 Editor::play_selection ()
2636 framepos_t start, end;
2637 if (!get_selection_extents ( start, end))
2640 AudioRange ar (start, end, 0);
2641 list<AudioRange> lar;
2644 _session->request_play_range (&lar, true);
2649 Editor::maybe_locate_with_edit_preroll (framepos_t location)
2651 if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
2654 location -= _session->preroll_samples (location);
2656 //don't try to locate before the beginning of time
2661 //if follow_playhead is on, keep the playhead on the screen
2662 if ( _follow_playhead )
2663 if ( location < leftmost_frame )
2664 location = leftmost_frame;
2666 _session->request_locate( location );
2670 Editor::play_with_preroll ()
2672 framepos_t start, end;
2673 if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
2674 const framepos_t preroll = _session->preroll_samples (start);
2676 framepos_t ret = start;
2678 if (start > preroll) {
2679 start = start - preroll;
2682 end = end + preroll; //"post-roll"
2684 AudioRange ar (start, end, 0);
2685 list<AudioRange> lar;
2688 _session->request_play_range (&lar, true);
2689 _session->set_requested_return_frame (ret); //force auto-return to return to range start, without the preroll
2691 framepos_t ph = playhead_cursor->current_frame ();
2692 const framepos_t preroll = _session->preroll_samples (ph);
2695 start = ph - preroll;
2699 _session->request_locate (start, true);
2700 _session->set_requested_return_frame (ph); //force auto-return to return to playhead location, without the preroll
2705 Editor::rec_with_preroll ()
2707 framepos_t ph = playhead_cursor->current_frame ();
2708 framepos_t preroll = _session->preroll_samples (ph);
2709 _session->request_preroll_record_trim (ph, preroll);
2713 Editor::rec_with_count_in ()
2715 _session->request_count_in_record ();
2719 Editor::play_location (Location& location)
2721 if (location.start() <= location.end()) {
2725 _session->request_bounded_roll (location.start(), location.end());
2729 Editor::loop_location (Location& location)
2731 if (location.start() <= location.end()) {
2737 if ((tll = transport_loop_location()) != 0) {
2738 tll->set (location.start(), location.end());
2740 // enable looping, reposition and start rolling
2741 _session->request_locate (tll->start(), true);
2742 _session->request_play_loop (true);
2747 Editor::do_layer_operation (LayerOperation op)
2749 if (selection->regions.empty ()) {
2753 bool const multiple = selection->regions.size() > 1;
2757 begin_reversible_command (_("raise regions"));
2759 begin_reversible_command (_("raise region"));
2765 begin_reversible_command (_("raise regions to top"));
2767 begin_reversible_command (_("raise region to top"));
2773 begin_reversible_command (_("lower regions"));
2775 begin_reversible_command (_("lower region"));
2781 begin_reversible_command (_("lower regions to bottom"));
2783 begin_reversible_command (_("lower region"));
2788 set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2789 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2790 (*i)->clear_owned_changes ();
2793 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2794 boost::shared_ptr<Region> r = (*i)->region ();
2806 r->lower_to_bottom ();
2810 for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2811 vector<Command*> cmds;
2813 _session->add_commands (cmds);
2816 commit_reversible_command ();
2820 Editor::raise_region ()
2822 do_layer_operation (Raise);
2826 Editor::raise_region_to_top ()
2828 do_layer_operation (RaiseToTop);
2832 Editor::lower_region ()
2834 do_layer_operation (Lower);
2838 Editor::lower_region_to_bottom ()
2840 do_layer_operation (LowerToBottom);
2843 /** Show the region editor for the selected regions */
2845 Editor::show_region_properties ()
2847 selection->foreach_regionview (&RegionView::show_region_editor);
2850 /** Show the midi list editor for the selected MIDI regions */
2852 Editor::show_midi_list_editor ()
2854 selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2858 Editor::rename_region ()
2860 RegionSelection rs = get_regions_from_selection_and_entered ();
2866 ArdourDialog d (_("Rename Region"), true, false);
2868 Label label (_("New name:"));
2871 hbox.set_spacing (6);
2872 hbox.pack_start (label, false, false);
2873 hbox.pack_start (entry, true, true);
2875 d.get_vbox()->set_border_width (12);
2876 d.get_vbox()->pack_start (hbox, false, false);
2878 d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2879 d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2881 d.set_size_request (300, -1);
2883 entry.set_text (rs.front()->region()->name());
2884 entry.select_region (0, -1);
2886 entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2892 int const ret = d.run();
2896 if (ret != RESPONSE_OK) {
2900 std::string str = entry.get_text();
2901 strip_whitespace_edges (str);
2903 rs.front()->region()->set_name (str);
2904 _regions->redisplay ();
2908 /** Start an audition of the first selected region */
2910 Editor::play_edit_range ()
2912 framepos_t start, end;
2914 if (get_edit_op_range (start, end)) {
2915 _session->request_bounded_roll (start, end);
2920 Editor::play_selected_region ()
2922 framepos_t start = max_framepos;
2925 RegionSelection rs = get_regions_from_selection_and_entered ();
2931 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2932 if ((*i)->region()->position() < start) {
2933 start = (*i)->region()->position();
2935 if ((*i)->region()->last_frame() + 1 > end) {
2936 end = (*i)->region()->last_frame() + 1;
2940 _session->request_bounded_roll (start, end);
2944 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2946 _session->audition_region (region);
2950 Editor::region_from_selection ()
2952 if (clicked_axisview == 0) {
2956 if (selection->time.empty()) {
2960 framepos_t start = selection->time[clicked_selection].start;
2961 framepos_t end = selection->time[clicked_selection].end;
2963 TrackViewList tracks = get_tracks_for_range_action ();
2965 framepos_t selection_cnt = end - start + 1;
2967 for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2968 boost::shared_ptr<Region> current;
2969 boost::shared_ptr<Playlist> pl;
2970 framepos_t internal_start;
2973 if ((pl = (*i)->playlist()) == 0) {
2977 if ((current = pl->top_region_at (start)) == 0) {
2981 internal_start = start - current->position();
2982 RegionFactory::region_name (new_name, current->name(), true);
2986 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2987 plist.add (ARDOUR::Properties::length, selection_cnt);
2988 plist.add (ARDOUR::Properties::name, new_name);
2989 plist.add (ARDOUR::Properties::layer, 0);
2991 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2996 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2998 if (selection->time.empty() || selection->tracks.empty()) {
3002 framepos_t start, end;
3003 if (clicked_selection) {
3004 start = selection->time[clicked_selection].start;
3005 end = selection->time[clicked_selection].end;
3007 start = selection->time.start();
3008 end = selection->time.end_frame();
3011 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3012 sort_track_selection (ts);
3014 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3015 boost::shared_ptr<Region> current;
3016 boost::shared_ptr<Playlist> playlist;
3017 framepos_t internal_start;
3020 if ((playlist = (*i)->playlist()) == 0) {
3024 if ((current = playlist->top_region_at(start)) == 0) {
3028 internal_start = start - current->position();
3029 RegionFactory::region_name (new_name, current->name(), true);
3033 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
3034 plist.add (ARDOUR::Properties::length, end - start + 1);
3035 plist.add (ARDOUR::Properties::name, new_name);
3037 new_regions.push_back (RegionFactory::create (current, plist));
3042 Editor::split_multichannel_region ()
3044 RegionSelection rs = get_regions_from_selection_and_entered ();
3050 vector< boost::shared_ptr<Region> > v;
3052 for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
3053 (*x)->region()->separate_by_channel (*_session, v);
3058 Editor::new_region_from_selection ()
3060 region_from_selection ();
3061 cancel_selection ();
3065 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
3067 switch (rv->region()->coverage (ar->start, ar->end - 1)) {
3068 // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
3069 case Evoral::OverlapNone:
3077 * - selected tracks, or if there are none...
3078 * - tracks containing selected regions, or if there are none...
3083 Editor::get_tracks_for_range_action () const
3087 if (selection->tracks.empty()) {
3089 /* use tracks with selected regions */
3091 RegionSelection rs = selection->regions;
3093 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3094 TimeAxisView* tv = &(*i)->get_time_axis_view();
3096 if (!t.contains (tv)) {
3102 /* no regions and no tracks: use all tracks */
3108 t = selection->tracks;
3111 return t.filter_to_unique_playlists();
3115 Editor::separate_regions_between (const TimeSelection& ts)
3117 bool in_command = false;
3118 boost::shared_ptr<Playlist> playlist;
3119 RegionSelection new_selection;
3121 TrackViewList tmptracks = get_tracks_for_range_action ();
3122 sort_track_selection (tmptracks);
3124 for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3126 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3132 if (!rtv->is_track()) {
3136 /* no edits to destructive tracks */
3138 if (rtv->track()->destructive()) {
3142 if ((playlist = rtv->playlist()) != 0) {
3144 playlist->clear_changes ();
3146 /* XXX need to consider musical time selections here at some point */
3148 for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3150 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3151 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3153 latest_regionviews.clear ();
3155 playlist->partition ((*t).start, (*t).end, false);
3159 if (!latest_regionviews.empty()) {
3161 rtv->view()->foreach_regionview (sigc::bind (
3162 sigc::ptr_fun (add_if_covered),
3163 &(*t), &new_selection));
3166 begin_reversible_command (_("separate"));
3170 /* pick up changes to existing regions */
3172 vector<Command*> cmds;
3173 playlist->rdiff (cmds);
3174 _session->add_commands (cmds);
3176 /* pick up changes to the playlist itself (adds/removes)
3179 _session->add_command(new StatefulDiffCommand (playlist));
3186 // selection->set (new_selection);
3188 commit_reversible_command ();
3192 struct PlaylistState {
3193 boost::shared_ptr<Playlist> playlist;
3197 /** Take tracks from get_tracks_for_range_action and cut any regions
3198 * on those tracks so that the tracks are empty over the time
3202 Editor::separate_region_from_selection ()
3204 /* preferentially use *all* ranges in the time selection if we're in range mode
3205 to allow discontiguous operation, since get_edit_op_range() currently
3206 returns a single range.
3209 if (!selection->time.empty()) {
3211 separate_regions_between (selection->time);
3218 if (get_edit_op_range (start, end)) {
3220 AudioRange ar (start, end, 1);
3224 separate_regions_between (ts);
3230 Editor::separate_region_from_punch ()
3232 Location* loc = _session->locations()->auto_punch_location();
3234 separate_regions_using_location (*loc);
3239 Editor::separate_region_from_loop ()
3241 Location* loc = _session->locations()->auto_loop_location();
3243 separate_regions_using_location (*loc);
3248 Editor::separate_regions_using_location (Location& loc)
3250 if (loc.is_mark()) {
3254 AudioRange ar (loc.start(), loc.end(), 1);
3259 separate_regions_between (ts);
3262 /** Separate regions under the selected region */
3264 Editor::separate_under_selected_regions ()
3266 vector<PlaylistState> playlists;
3270 rs = get_regions_from_selection_and_entered();
3272 if (!_session || rs.empty()) {
3276 begin_reversible_command (_("separate region under"));
3278 list<boost::shared_ptr<Region> > regions_to_remove;
3280 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3281 // we can't just remove the region(s) in this loop because
3282 // this removes them from the RegionSelection, and they thus
3283 // disappear from underneath the iterator, and the ++i above
3284 // SEGVs in a puzzling fashion.
3286 // so, first iterate over the regions to be removed from rs and
3287 // add them to the regions_to_remove list, and then
3288 // iterate over the list to actually remove them.
3290 regions_to_remove.push_back ((*i)->region());
3293 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3295 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3298 // is this check necessary?
3302 vector<PlaylistState>::iterator i;
3304 //only take state if this is a new playlist.
3305 for (i = playlists.begin(); i != playlists.end(); ++i) {
3306 if ((*i).playlist == playlist) {
3311 if (i == playlists.end()) {
3313 PlaylistState before;
3314 before.playlist = playlist;
3315 before.before = &playlist->get_state();
3316 playlist->clear_changes ();
3317 playlist->freeze ();
3318 playlists.push_back(before);
3321 //Partition on the region bounds
3322 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3324 //Re-add region that was just removed due to the partition operation
3325 playlist->add_region( (*rl), (*rl)->first_frame() );
3328 vector<PlaylistState>::iterator pl;
3330 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3331 (*pl).playlist->thaw ();
3332 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3335 commit_reversible_command ();
3339 Editor::crop_region_to_selection ()
3341 if (!selection->time.empty()) {
3343 begin_reversible_command (_("Crop Regions to Time Selection"));
3344 for (std::list<AudioRange>::iterator i = selection->time.begin(); i != selection->time.end(); ++i) {
3345 crop_region_to ((*i).start, (*i).end);
3347 commit_reversible_command();
3353 if (get_edit_op_range (start, end)) {
3354 begin_reversible_command (_("Crop Regions to Edit Range"));
3356 crop_region_to (start, end);
3358 commit_reversible_command();
3365 Editor::crop_region_to (framepos_t start, framepos_t end)
3367 vector<boost::shared_ptr<Playlist> > playlists;
3368 boost::shared_ptr<Playlist> playlist;
3371 if (selection->tracks.empty()) {
3372 ts = track_views.filter_to_unique_playlists();
3374 ts = selection->tracks.filter_to_unique_playlists ();
3377 sort_track_selection (ts);
3379 for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3381 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
3387 boost::shared_ptr<Track> t = rtv->track();
3389 if (t != 0 && ! t->destructive()) {
3391 if ((playlist = rtv->playlist()) != 0) {
3392 playlists.push_back (playlist);
3397 if (playlists.empty()) {
3402 framepos_t new_start;
3404 framecnt_t new_length;
3406 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3408 /* Only the top regions at start and end have to be cropped */
3409 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3410 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3412 vector<boost::shared_ptr<Region> > regions;
3414 if (region_at_start != 0) {
3415 regions.push_back (region_at_start);
3417 if (region_at_end != 0) {
3418 regions.push_back (region_at_end);
3421 /* now adjust lengths */
3422 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3424 pos = (*i)->position();
3425 new_start = max (start, pos);
3426 if (max_framepos - pos > (*i)->length()) {
3427 new_end = pos + (*i)->length() - 1;
3429 new_end = max_framepos;
3431 new_end = min (end, new_end);
3432 new_length = new_end - new_start + 1;
3434 (*i)->clear_changes ();
3435 (*i)->trim_to (new_start, new_length);
3436 _session->add_command (new StatefulDiffCommand (*i));
3442 Editor::region_fill_track ()
3444 boost::shared_ptr<Playlist> playlist;
3445 RegionSelection regions = get_regions_from_selection_and_entered ();
3446 RegionSelection foo;
3448 framepos_t const end = _session->current_end_frame ();
3450 if (regions.empty () || regions.end_frame () + 1 >= end) {
3454 framepos_t const start_frame = regions.start ();
3455 framepos_t const end_frame = regions.end_frame ();
3456 framecnt_t const gap = end_frame - start_frame + 1;
3458 begin_reversible_command (Operations::region_fill);
3460 selection->clear_regions ();
3462 for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3464 boost::shared_ptr<Region> r ((*i)->region());
3466 TimeAxisView& tv = (*i)->get_time_axis_view();
3467 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3468 latest_regionviews.clear ();
3469 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3471 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3472 playlist = (*i)->region()->playlist();
3473 playlist->clear_changes ();
3474 playlist->duplicate_until (r, position, gap, end);
3475 _session->add_command(new StatefulDiffCommand (playlist));
3479 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3483 selection->set (foo);
3486 commit_reversible_command ();
3490 Editor::set_region_sync_position ()
3492 set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3496 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3498 bool in_command = false;
3500 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3502 if (!(*r)->region()->covers (where)) {
3506 boost::shared_ptr<Region> region ((*r)->region());
3509 begin_reversible_command (_("set sync point"));
3513 region->clear_changes ();
3514 region->set_sync_position (where);
3515 _session->add_command(new StatefulDiffCommand (region));
3519 commit_reversible_command ();
3523 /** Remove the sync positions of the selection */
3525 Editor::remove_region_sync ()
3527 RegionSelection rs = get_regions_from_selection_and_entered ();
3533 begin_reversible_command (_("remove region sync"));
3535 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3537 (*i)->region()->clear_changes ();
3538 (*i)->region()->clear_sync_position ();
3539 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3542 commit_reversible_command ();
3546 Editor::naturalize_region ()
3548 RegionSelection rs = get_regions_from_selection_and_entered ();
3554 if (rs.size() > 1) {
3555 begin_reversible_command (_("move regions to original position"));
3557 begin_reversible_command (_("move region to original position"));
3560 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3561 (*i)->region()->clear_changes ();
3562 (*i)->region()->move_to_natural_position ();
3563 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3566 commit_reversible_command ();
3570 Editor::align_regions (RegionPoint what)
3572 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3578 begin_reversible_command (_("align selection"));
3580 framepos_t const position = get_preferred_edit_position ();
3582 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3583 align_region_internal ((*i)->region(), what, position);
3586 commit_reversible_command ();
3589 struct RegionSortByTime {
3590 bool operator() (const RegionView* a, const RegionView* b) {
3591 return a->region()->position() < b->region()->position();
3596 Editor::align_regions_relative (RegionPoint point)
3598 RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3604 framepos_t const position = get_preferred_edit_position ();
3606 framepos_t distance = 0;
3610 list<RegionView*> sorted;
3611 rs.by_position (sorted);
3613 boost::shared_ptr<Region> r ((*sorted.begin())->region());
3618 if (position > r->position()) {
3619 distance = position - r->position();
3621 distance = r->position() - position;
3627 if (position > r->last_frame()) {
3628 distance = position - r->last_frame();
3629 pos = r->position() + distance;
3631 distance = r->last_frame() - position;
3632 pos = r->position() - distance;
3638 pos = r->adjust_to_sync (position);
3639 if (pos > r->position()) {
3640 distance = pos - r->position();
3642 distance = r->position() - pos;
3648 if (pos == r->position()) {
3652 begin_reversible_command (_("align selection (relative)"));
3654 /* move first one specially */
3656 r->clear_changes ();
3657 r->set_position (pos);
3658 _session->add_command(new StatefulDiffCommand (r));
3660 /* move rest by the same amount */
3664 for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3666 boost::shared_ptr<Region> region ((*i)->region());
3668 region->clear_changes ();
3671 region->set_position (region->position() + distance);
3673 region->set_position (region->position() - distance);
3676 _session->add_command(new StatefulDiffCommand (region));
3680 commit_reversible_command ();
3684 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3686 begin_reversible_command (_("align region"));
3687 align_region_internal (region, point, position);
3688 commit_reversible_command ();
3692 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3694 region->clear_changes ();
3698 region->set_position (region->adjust_to_sync (position));
3702 if (position > region->length()) {
3703 region->set_position (position - region->length());
3708 region->set_position (position);
3712 _session->add_command(new StatefulDiffCommand (region));
3716 Editor::trim_region_front ()
3722 Editor::trim_region_back ()
3724 trim_region (false);
3728 Editor::trim_region (bool front)
3730 framepos_t where = get_preferred_edit_position();
3731 RegionSelection rs = get_regions_from_selection_and_edit_point ();
3737 begin_reversible_command (front ? _("trim front") : _("trim back"));
3739 for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3740 if (!(*i)->region()->locked()) {
3742 (*i)->region()->clear_changes ();
3745 (*i)->region()->trim_front (where);
3747 (*i)->region()->trim_end (where);
3750 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3754 commit_reversible_command ();
3757 /** Trim the end of the selected regions to the position of the edit cursor */
3759 Editor::trim_region_to_loop ()
3761 Location* loc = _session->locations()->auto_loop_location();
3765 trim_region_to_location (*loc, _("trim to loop"));
3769 Editor::trim_region_to_punch ()
3771 Location* loc = _session->locations()->auto_punch_location();
3775 trim_region_to_location (*loc, _("trim to punch"));
3779 Editor::trim_region_to_location (const Location& loc, const char* str)
3781 RegionSelection rs = get_regions_from_selection_and_entered ();
3782 bool in_command = false;
3784 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3785 RegionView* rv = (*x);
3787 /* require region to span proposed trim */
3788 switch (rv->region()->coverage (loc.start(), loc.end())) {
3789 case Evoral::OverlapInternal:
3795 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3803 start = loc.start();
3806 rv->region()->clear_changes ();
3807 rv->region()->trim_to (start, (end - start));
3810 begin_reversible_command (str);
3813 _session->add_command(new StatefulDiffCommand (rv->region()));
3817 commit_reversible_command ();
3822 Editor::trim_region_to_previous_region_end ()
3824 return trim_to_region(false);
3828 Editor::trim_region_to_next_region_start ()
3830 return trim_to_region(true);
3834 Editor::trim_to_region(bool forward)
3836 RegionSelection rs = get_regions_from_selection_and_entered ();
3837 bool in_command = false;
3839 boost::shared_ptr<Region> next_region;
3841 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3843 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3849 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3855 boost::shared_ptr<Region> region = arv->region();
3856 boost::shared_ptr<Playlist> playlist (region->playlist());
3858 region->clear_changes ();
3862 next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3868 region->trim_end (next_region->first_frame() - 1);
3869 arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3873 next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3879 region->trim_front (next_region->last_frame() + 1);
3880 arv->region_changed (ARDOUR::bounds_change);
3884 begin_reversible_command (_("trim to region"));
3887 _session->add_command(new StatefulDiffCommand (region));
3891 commit_reversible_command ();
3896 Editor::unfreeze_route ()
3898 if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3902 clicked_routeview->track()->unfreeze ();
3906 Editor::_freeze_thread (void* arg)
3908 return static_cast<Editor*>(arg)->freeze_thread ();
3912 Editor::freeze_thread ()
3914 /* create event pool because we may need to talk to the session */
3915 SessionEvent::create_per_thread_pool ("freeze events", 64);
3916 /* create per-thread buffers for process() tree to use */
3917 clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3918 current_interthread_info->done = true;
3923 Editor::freeze_route ()
3929 /* stop transport before we start. this is important */
3931 _session->request_transport_speed (0.0);
3933 /* wait for just a little while, because the above call is asynchronous */
3935 Glib::usleep (250000);
3937 if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3941 if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3943 _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3944 "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3946 d.set_title (_("Cannot freeze"));
3951 if (clicked_routeview->track()->has_external_redirects()) {
3952 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3953 "Freezing will only process the signal as far as the first send/insert/return."),
3954 clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3956 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3957 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3958 d.set_title (_("Freeze Limits"));
3960 int response = d.run ();
3963 case Gtk::RESPONSE_CANCEL:
3970 InterThreadInfo itt;
3971 current_interthread_info = &itt;
3973 InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3975 pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3977 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3979 while (!itt.done && !itt.cancel) {
3980 gtk_main_iteration ();
3983 pthread_join (itt.thread, 0);
3984 current_interthread_info = 0;
3988 Editor::bounce_range_selection (bool replace, bool enable_processing)
3990 if (selection->time.empty()) {
3994 TrackSelection views = selection->tracks;
3996 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3998 if (enable_processing) {
4000 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4002 if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
4004 _("You can't perform this operation because the processing of the signal "
4005 "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
4006 "You can do this without processing, which is a different operation.")
4008 d.set_title (_("Cannot bounce"));
4015 framepos_t start = selection->time[clicked_selection].start;
4016 framepos_t end = selection->time[clicked_selection].end;
4017 framepos_t cnt = end - start + 1;
4018 bool in_command = false;
4020 for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
4022 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
4028 boost::shared_ptr<Playlist> playlist;
4030 if ((playlist = rtv->playlist()) == 0) {
4034 InterThreadInfo itt;
4036 playlist->clear_changes ();
4037 playlist->clear_owned_changes ();
4039 boost::shared_ptr<Region> r;
4041 if (enable_processing) {
4042 r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4044 r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4052 list<AudioRange> ranges;
4053 ranges.push_back (AudioRange (start, start+cnt, 0));
4054 playlist->cut (ranges); // discard result
4055 playlist->add_region (r, start);
4059 begin_reversible_command (_("bounce range"));
4062 vector<Command*> cmds;
4063 playlist->rdiff (cmds);
4064 _session->add_commands (cmds);
4066 _session->add_command (new StatefulDiffCommand (playlist));
4070 commit_reversible_command ();
4074 /** Delete selected regions, automation points or a time range */
4078 //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4079 //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4080 bool deleted = false;
4081 if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4082 deleted = current_mixer_strip->delete_processors ();
4088 /** Cut selected regions, automation points or a time range */
4095 /** Copy selected regions, automation points or a time range */
4103 /** @return true if a Cut, Copy or Clear is possible */
4105 Editor::can_cut_copy () const
4107 if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4114 /** Cut, copy or clear selected regions, automation points or a time range.
4115 * @param op Operation (Delete, Cut, Copy or Clear)
4118 Editor::cut_copy (CutCopyOp op)
4120 /* only cancel selection if cut/copy is successful.*/
4126 opname = _("delete");
4135 opname = _("clear");
4139 /* if we're deleting something, and the mouse is still pressed,
4140 the thing we started a drag for will be gone when we release
4141 the mouse button(s). avoid this. see part 2 at the end of
4145 if (op == Delete || op == Cut || op == Clear) {
4146 if (_drags->active ()) {
4151 if ( op != Delete ) { //"Delete" doesn't change copy/paste buf
4152 cut_buffer->clear ();
4155 if (entered_marker) {
4157 /* cut/delete op while pointing at a marker */
4160 Location* loc = find_location_from_marker (entered_marker, ignored);
4162 if (_session && loc) {
4163 entered_marker = NULL;
4164 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4171 switch (mouse_mode) {
4174 begin_reversible_command (opname + ' ' + X_("MIDI"));
4176 commit_reversible_command ();
4182 bool did_edit = false;
4184 if (!selection->regions.empty() || !selection->points.empty()) {
4185 begin_reversible_command (opname + ' ' + _("objects"));
4188 if (!selection->regions.empty()) {
4189 cut_copy_regions (op, selection->regions);
4191 if (op == Cut || op == Delete) {
4192 selection->clear_regions ();
4196 if (!selection->points.empty()) {
4197 cut_copy_points (op);
4199 if (op == Cut || op == Delete) {
4200 selection->clear_points ();
4203 } else if (selection->time.empty()) {
4204 framepos_t start, end;
4205 /* no time selection, see if we can get an edit range
4208 if (get_edit_op_range (start, end)) {
4209 selection->set (start, end);
4211 } else if (!selection->time.empty()) {
4212 begin_reversible_command (opname + ' ' + _("range"));
4215 cut_copy_ranges (op);
4217 if (op == Cut || op == Delete) {
4218 selection->clear_time ();
4223 /* reset repeated paste state */
4225 last_paste_pos = -1;
4226 commit_reversible_command ();
4229 if (op == Delete || op == Cut || op == Clear) {
4235 struct AutomationRecord {
4236 AutomationRecord () : state (0) , line(NULL) {}
4237 AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4239 XMLNode* state; ///< state before any operation
4240 const AutomationLine* line; ///< line this came from
4241 boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4244 struct PointsSelectionPositionSorter {
4245 bool operator() (ControlPoint* a, ControlPoint* b) {
4246 return (*(a->model()))->when < (*(b->model()))->when;
4250 /** Cut, copy or clear selected automation points.
4251 * @param op Operation (Cut, Copy or Clear)
4254 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4256 if (selection->points.empty ()) {
4260 /* XXX: not ideal, as there may be more than one track involved in the point selection */
4261 _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4263 /* Keep a record of the AutomationLists that we end up using in this operation */
4264 typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4267 /* user could select points in any order */
4268 selection->points.sort(PointsSelectionPositionSorter ());
4270 /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4271 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4272 const AutomationLine& line = (*sel_point)->line();
4273 const boost::shared_ptr<AutomationList> al = line.the_list();
4274 if (lists.find (al) == lists.end ()) {
4275 /* We haven't seen this list yet, so make a record for it. This includes
4276 taking a copy of its current state, in case this is needed for undo later.
4278 lists[al] = AutomationRecord (&al->get_state (), &line);
4282 if (op == Cut || op == Copy) {
4283 /* This operation will involve putting things in the cut buffer, so create an empty
4284 ControlList for each of our source lists to put the cut buffer data in.
4286 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4287 i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4290 /* Add all selected points to the relevant copy ControlLists */
4291 MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
4292 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4293 boost::shared_ptr<AutomationList> al = (*sel_point)->line().the_list();
4294 AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
4296 lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
4298 /* Update earliest MIDI start time in beats */
4299 earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
4301 /* Update earliest session start time in frames */
4302 start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
4306 /* Snap start time backwards, so copy/paste is snap aligned. */
4308 if (earliest == Evoral::Beats::max()) {
4309 earliest = Evoral::Beats(); // Weird... don't offset
4311 earliest.round_down_to_beat();
4313 if (start.frame == std::numeric_limits<double>::max()) {
4314 start.frame = 0; // Weird... don't offset
4316 snap_to(start, RoundDownMaybe);
4319 const double line_offset = midi ? earliest.to_double() : start.frame;
4320 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4321 /* Correct this copy list so that it is relative to the earliest
4322 start time, so relative ordering between points is preserved
4323 when copying from several lists and the paste starts at the
4324 earliest copied piece of data. */
4325 boost::shared_ptr<Evoral::ControlList> &al_cpy = i->second.copy;
4326 for (AutomationList::iterator ctrl_evt = al_cpy->begin(); ctrl_evt != al_cpy->end(); ++ctrl_evt) {
4327 (*ctrl_evt)->when -= line_offset;
4330 /* And add it to the cut buffer */
4331 cut_buffer->add (al_cpy);
4335 if (op == Delete || op == Cut) {
4336 /* This operation needs to remove things from the main AutomationList, so do that now */
4338 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4339 i->first->freeze ();
4342 /* Remove each selected point from its AutomationList */
4343 for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
4344 AutomationLine& line = (*sel_point)->line ();
4345 boost::shared_ptr<AutomationList> al = line.the_list();
4349 if (dynamic_cast<AudioRegionGainLine*> (&line)) {
4350 /* removing of first and last gain point in region gain lines is prohibited*/
4351 if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
4357 al->erase ((*sel_point)->model ());
4361 /* Thaw the lists and add undo records for them */
4362 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4363 boost::shared_ptr<AutomationList> al = i->first;
4365 _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4370 /** Cut, copy or clear selected automation points.
4371 * @param op Operation (Cut, Copy or Clear)
4374 Editor::cut_copy_midi (CutCopyOp op)
4376 Evoral::Beats earliest = Evoral::Beats::max();
4377 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4378 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4380 if (!mrv->selection().empty()) {
4381 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4383 mrv->cut_copy_clear (op);
4385 /* XXX: not ideal, as there may be more than one track involved in the selection */
4386 _last_cut_copy_source_track = &mrv->get_time_axis_view();
4390 if (!selection->points.empty()) {
4391 cut_copy_points (op, earliest, true);
4392 if (op == Cut || op == Delete) {
4393 selection->clear_points ();
4398 struct lt_playlist {
4399 bool operator () (const PlaylistState& a, const PlaylistState& b) {
4400 return a.playlist < b.playlist;
4404 struct PlaylistMapping {
4406 boost::shared_ptr<Playlist> pl;
4408 PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4411 /** Remove `clicked_regionview' */
4413 Editor::remove_clicked_region ()
4415 if (clicked_routeview == 0 || clicked_regionview == 0) {
4419 begin_reversible_command (_("remove region"));
4421 boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4423 playlist->clear_changes ();
4424 playlist->clear_owned_changes ();
4425 playlist->remove_region (clicked_regionview->region());
4426 if (Config->get_edit_mode() == Ripple)
4427 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4429 /* We might have removed regions, which alters other regions' layering_index,
4430 so we need to do a recursive diff here.
4432 vector<Command*> cmds;
4433 playlist->rdiff (cmds);
4434 _session->add_commands (cmds);
4436 _session->add_command(new StatefulDiffCommand (playlist));
4437 commit_reversible_command ();
4441 /** Remove the selected regions */
4443 Editor::remove_selected_regions ()
4445 RegionSelection rs = get_regions_from_selection_and_entered ();
4447 if (!_session || rs.empty()) {
4451 list<boost::shared_ptr<Region> > regions_to_remove;
4453 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4454 // we can't just remove the region(s) in this loop because
4455 // this removes them from the RegionSelection, and they thus
4456 // disappear from underneath the iterator, and the ++i above
4457 // SEGVs in a puzzling fashion.
4459 // so, first iterate over the regions to be removed from rs and
4460 // add them to the regions_to_remove list, and then
4461 // iterate over the list to actually remove them.
4463 regions_to_remove.push_back ((*i)->region());
4466 vector<boost::shared_ptr<Playlist> > playlists;
4468 for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4470 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4473 // is this check necessary?
4477 /* get_regions_from_selection_and_entered() guarantees that
4478 the playlists involved are unique, so there is no need
4482 playlists.push_back (playlist);
4484 playlist->clear_changes ();
4485 playlist->clear_owned_changes ();
4486 playlist->freeze ();
4487 playlist->remove_region (*rl);
4488 if (Config->get_edit_mode() == Ripple)
4489 playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4493 vector<boost::shared_ptr<Playlist> >::iterator pl;
4494 bool in_command = false;
4496 for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4499 /* We might have removed regions, which alters other regions' layering_index,
4500 so we need to do a recursive diff here.
4504 begin_reversible_command (_("remove region"));
4507 vector<Command*> cmds;
4508 (*pl)->rdiff (cmds);
4509 _session->add_commands (cmds);
4511 _session->add_command(new StatefulDiffCommand (*pl));
4515 commit_reversible_command ();
4519 /** Cut, copy or clear selected regions.
4520 * @param op Operation (Cut, Copy or Clear)
4523 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4525 /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4526 a map when we want ordered access to both elements. i think.
4529 vector<PlaylistMapping> pmap;
4531 framepos_t first_position = max_framepos;
4533 typedef set<boost::shared_ptr<Playlist> > FreezeList;
4534 FreezeList freezelist;
4536 /* get ordering correct before we cut/copy */
4538 rs.sort_by_position_and_track ();
4540 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4542 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4544 if (op == Cut || op == Clear || op == Delete) {
4545 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4548 FreezeList::iterator fl;
4550 // only take state if this is a new playlist.
4551 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4557 if (fl == freezelist.end()) {
4558 pl->clear_changes();
4559 pl->clear_owned_changes ();
4561 freezelist.insert (pl);
4566 TimeAxisView* tv = &(*x)->get_time_axis_view();
4567 vector<PlaylistMapping>::iterator z;
4569 for (z = pmap.begin(); z != pmap.end(); ++z) {
4570 if ((*z).tv == tv) {
4575 if (z == pmap.end()) {
4576 pmap.push_back (PlaylistMapping (tv));
4580 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4582 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4585 /* region not yet associated with a playlist (e.g. unfinished
4592 TimeAxisView& tv = (*x)->get_time_axis_view();
4593 boost::shared_ptr<Playlist> npl;
4594 RegionSelection::iterator tmp;
4601 vector<PlaylistMapping>::iterator z;
4603 for (z = pmap.begin(); z != pmap.end(); ++z) {
4604 if ((*z).tv == &tv) {
4609 assert (z != pmap.end());
4612 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4620 boost::shared_ptr<Region> r = (*x)->region();
4621 boost::shared_ptr<Region> _xx;
4627 pl->remove_region (r);
4628 if (Config->get_edit_mode() == Ripple)
4629 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4633 _xx = RegionFactory::create (r);
4634 npl->add_region (_xx, r->position() - first_position);
4635 pl->remove_region (r);
4636 if (Config->get_edit_mode() == Ripple)
4637 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4641 /* copy region before adding, so we're not putting same object into two different playlists */
4642 npl->add_region (RegionFactory::create (r), r->position() - first_position);
4646 pl->remove_region (r);
4647 if (Config->get_edit_mode() == Ripple)
4648 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4657 list<boost::shared_ptr<Playlist> > foo;
4659 /* the pmap is in the same order as the tracks in which selected regions occurred */
4661 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4664 foo.push_back ((*i).pl);
4669 cut_buffer->set (foo);
4673 _last_cut_copy_source_track = 0;
4675 _last_cut_copy_source_track = pmap.front().tv;
4679 for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4682 /* We might have removed regions, which alters other regions' layering_index,
4683 so we need to do a recursive diff here.
4685 vector<Command*> cmds;
4686 (*pl)->rdiff (cmds);
4687 _session->add_commands (cmds);
4689 _session->add_command (new StatefulDiffCommand (*pl));
4694 Editor::cut_copy_ranges (CutCopyOp op)
4696 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4698 /* Sort the track selection now, so that it if is used, the playlists
4699 selected by the calls below to cut_copy_clear are in the order that
4700 their tracks appear in the editor. This makes things like paste
4701 of ranges work properly.
4704 sort_track_selection (ts);
4707 if (!entered_track) {
4710 ts.push_back (entered_track);
4713 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4714 (*i)->cut_copy_clear (*selection, op);
4719 Editor::paste (float times, bool from_context)
4721 DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4722 MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
4723 paste_internal (where.frame, times, 0);
4727 Editor::mouse_paste ()
4729 MusicFrame where (0, 0);
4731 if (!mouse_frame (where.frame, ignored)) {
4736 paste_internal (where.frame, 1, where.division);
4740 Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
4742 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4744 if (cut_buffer->empty(internal_editing())) {
4748 if (position == max_framepos) {
4749 position = get_preferred_edit_position();
4750 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4753 if (position == last_paste_pos) {
4754 /* repeated paste in the same position */
4757 /* paste in new location, reset repeated paste state */
4759 last_paste_pos = position;
4762 /* get everything in the correct order */
4765 if (!selection->tracks.empty()) {
4766 /* If there is a track selection, paste into exactly those tracks and
4767 * only those tracks. This allows the user to be explicit and override
4768 * the below "do the reasonable thing" logic. */
4769 ts = selection->tracks.filter_to_unique_playlists ();
4770 sort_track_selection (ts);
4772 /* Figure out which track to base the paste at. */
4773 TimeAxisView* base_track = NULL;
4774 if (_edit_point == Editing::EditAtMouse && entered_track) {
4775 /* With the mouse edit point, paste onto the track under the mouse. */
4776 base_track = entered_track;
4777 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4778 /* With the mouse edit point, paste onto the track of the region under the mouse. */
4779 base_track = &entered_regionview->get_time_axis_view();
4780 } else if (_last_cut_copy_source_track) {
4781 /* Paste to the track that the cut/copy came from (see mantis #333). */
4782 base_track = _last_cut_copy_source_track;
4784 /* This is "impossible" since we've copied... well, do nothing. */
4788 /* Walk up to parent if necessary, so base track is a route. */
4789 while (base_track->get_parent()) {
4790 base_track = base_track->get_parent();
4793 /* Add base track and all tracks below it. The paste logic will select
4794 the appropriate object types from the cut buffer in relative order. */
4795 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4796 if ((*i)->order() >= base_track->order()) {
4801 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4802 sort_track_selection (ts);
4804 /* Add automation children of each track in order, for pasting several lines. */
4805 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4806 /* Add any automation children for pasting several lines */
4807 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4812 typedef RouteTimeAxisView::AutomationTracks ATracks;
4813 const ATracks& atracks = rtv->automation_tracks();
4814 for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4815 i = ts.insert(i, a->second.get());
4820 /* We now have a list of trackviews starting at base_track, including
4821 automation children, in the order shown in the editor, e.g. R1,
4822 R1.A1, R1.A2, R2, R2.A1, ... */
4825 begin_reversible_command (Operations::paste);
4827 if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4828 dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4829 /* Only one line copied, and one automation track selected. Do a
4830 "greedy" paste from one automation type to another. */
4832 PasteContext ctx(paste_count, times, ItemCounts(), true);
4833 ts.front()->paste (position, *cut_buffer, ctx, sub_num);
4837 /* Paste into tracks */
4839 PasteContext ctx(paste_count, times, ItemCounts(), false);
4840 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4841 (*i)->paste (position, *cut_buffer, ctx, sub_num);
4845 commit_reversible_command ();
4849 Editor::duplicate_regions (float times)
4851 RegionSelection rs (get_regions_from_selection_and_entered());
4852 duplicate_some_regions (rs, times);
4856 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4858 if (regions.empty ()) {
4862 boost::shared_ptr<Playlist> playlist;
4863 RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection
4864 RegionSelection foo;
4866 framepos_t const start_frame = regions.start ();
4867 framepos_t const end_frame = regions.end_frame ();
4868 framecnt_t const gap = end_frame - start_frame + 1;
4870 begin_reversible_command (Operations::duplicate_region);
4872 selection->clear_regions ();
4874 for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4876 boost::shared_ptr<Region> r ((*i)->region());
4878 TimeAxisView& tv = (*i)->get_time_axis_view();
4879 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4880 latest_regionviews.clear ();
4881 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4883 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4884 playlist = (*i)->region()->playlist();
4885 playlist->clear_changes ();
4886 playlist->duplicate (r, position, gap, times);
4887 _session->add_command(new StatefulDiffCommand (playlist));
4891 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4895 selection->set (foo);
4898 commit_reversible_command ();
4902 Editor::duplicate_selection (float times)
4904 if (selection->time.empty() || selection->tracks.empty()) {
4908 boost::shared_ptr<Playlist> playlist;
4910 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4912 bool in_command = false;
4914 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4915 if ((playlist = (*i)->playlist()) == 0) {
4918 playlist->clear_changes ();
4920 if (clicked_selection) {
4921 playlist->duplicate_range (selection->time[clicked_selection], times);
4923 playlist->duplicate_ranges (selection->time, times);
4927 begin_reversible_command (_("duplicate range selection"));
4930 _session->add_command (new StatefulDiffCommand (playlist));
4935 if (times == 1.0f) {
4936 // now "move" range selection to after the current range selection
4937 framecnt_t distance = 0;
4939 if (clicked_selection) {
4941 selection->time[clicked_selection].end - selection->time[clicked_selection].start;
4943 distance = selection->time.end_frame () - selection->time.start ();
4946 selection->move_time (distance);
4948 commit_reversible_command ();
4952 /** Reset all selected points to the relevant default value */
4954 Editor::reset_point_selection ()
4956 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4957 ARDOUR::AutomationList::iterator j = (*i)->model ();
4958 (*j)->value = (*i)->line().the_list()->descriptor ().normal;
4963 Editor::center_playhead ()
4965 float const page = _visible_canvas_width * samples_per_pixel;
4966 center_screen_internal (playhead_cursor->current_frame (), page);
4970 Editor::center_edit_point ()
4972 float const page = _visible_canvas_width * samples_per_pixel;
4973 center_screen_internal (get_preferred_edit_position(), page);
4976 /** Caller must begin and commit a reversible command */
4978 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4980 playlist->clear_changes ();
4982 _session->add_command (new StatefulDiffCommand (playlist));
4986 Editor::nudge_track (bool use_edit, bool forwards)
4988 boost::shared_ptr<Playlist> playlist;
4989 framepos_t distance;
4990 framepos_t next_distance;
4994 start = get_preferred_edit_position();
4999 if ((distance = get_nudge_distance (start, next_distance)) == 0) {
5003 if (selection->tracks.empty()) {
5007 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5008 bool in_command = false;
5010 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5012 if ((playlist = (*i)->playlist()) == 0) {
5016 playlist->clear_changes ();
5017 playlist->clear_owned_changes ();
5019 playlist->nudge_after (start, distance, forwards);
5022 begin_reversible_command (_("nudge track"));
5025 vector<Command*> cmds;
5027 playlist->rdiff (cmds);
5028 _session->add_commands (cmds);
5030 _session->add_command (new StatefulDiffCommand (playlist));
5034 commit_reversible_command ();
5039 Editor::remove_last_capture ()
5041 vector<string> choices;
5048 if (Config->get_verify_remove_last_capture()) {
5049 prompt = _("Do you really want to destroy the last capture?"
5050 "\n(This is destructive and cannot be undone)");
5052 choices.push_back (_("No, do nothing."));
5053 choices.push_back (_("Yes, destroy it."));
5055 Choice prompter (_("Destroy last capture"), prompt, choices);
5057 if (prompter.run () == 1) {
5058 _session->remove_last_capture ();
5059 _regions->redisplay ();
5063 _session->remove_last_capture();
5064 _regions->redisplay ();
5069 Editor::normalize_region ()
5075 RegionSelection rs = get_regions_from_selection_and_entered ();
5081 NormalizeDialog dialog (rs.size() > 1);
5083 if (dialog.run () != RESPONSE_ACCEPT) {
5087 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5090 /* XXX: should really only count audio regions here */
5091 int const regions = rs.size ();
5093 /* Make a list of the selected audio regions' maximum amplitudes, and also
5094 obtain the maximum amplitude of them all.
5096 list<double> max_amps;
5097 list<double> rms_vals;
5100 bool use_rms = dialog.constrain_rms ();
5102 for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5103 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5107 dialog.descend (1.0 / regions);
5108 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5110 double r = arv->audio_region()->rms (&dialog);
5111 max_rms = max (max_rms, r);
5112 rms_vals.push_back (r);
5116 /* the user cancelled the operation */
5120 max_amps.push_back (a);
5121 max_amp = max (max_amp, a);
5125 list<double>::const_iterator a = max_amps.begin ();
5126 list<double>::const_iterator l = rms_vals.begin ();
5127 bool in_command = false;
5129 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5130 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5135 arv->region()->clear_changes ();
5137 double amp = dialog.normalize_individually() ? *a : max_amp;
5138 double target = dialog.target_peak (); // dB
5141 double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5142 const double t_rms = dialog.target_rms ();
5143 const gain_t c_peak = dB_to_coefficient (target);
5144 const gain_t c_rms = dB_to_coefficient (t_rms);
5145 if ((amp_rms / c_rms) > (amp / c_peak)) {
5151 arv->audio_region()->normalize (amp, target);
5154 begin_reversible_command (_("normalize"));
5157 _session->add_command (new StatefulDiffCommand (arv->region()));
5164 commit_reversible_command ();
5170 Editor::reset_region_scale_amplitude ()
5176 RegionSelection rs = get_regions_from_selection_and_entered ();
5182 bool in_command = false;
5184 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5185 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5188 arv->region()->clear_changes ();
5189 arv->audio_region()->set_scale_amplitude (1.0f);
5192 begin_reversible_command ("reset gain");
5195 _session->add_command (new StatefulDiffCommand (arv->region()));
5199 commit_reversible_command ();
5204 Editor::adjust_region_gain (bool up)
5206 RegionSelection rs = get_regions_from_selection_and_entered ();
5208 if (!_session || rs.empty()) {
5212 bool in_command = false;
5214 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5215 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5220 arv->region()->clear_changes ();
5222 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5230 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5233 begin_reversible_command ("adjust region gain");
5236 _session->add_command (new StatefulDiffCommand (arv->region()));
5240 commit_reversible_command ();
5245 Editor::reset_region_gain ()
5247 RegionSelection rs = get_regions_from_selection_and_entered ();
5249 if (!_session || rs.empty()) {
5253 bool in_command = false;
5255 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5256 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5261 arv->region()->clear_changes ();
5263 arv->audio_region()->set_scale_amplitude (1.0f);
5266 begin_reversible_command ("reset region gain");
5269 _session->add_command (new StatefulDiffCommand (arv->region()));
5273 commit_reversible_command ();
5278 Editor::reverse_region ()
5284 Reverse rev (*_session);
5285 apply_filter (rev, _("reverse regions"));
5289 Editor::strip_region_silence ()
5295 RegionSelection rs = get_regions_from_selection_and_entered ();
5301 std::list<RegionView*> audio_only;
5303 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5304 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5306 audio_only.push_back (arv);
5310 assert (!audio_only.empty());
5312 StripSilenceDialog d (_session, audio_only);
5313 int const r = d.run ();
5317 if (r == Gtk::RESPONSE_OK) {
5318 ARDOUR::AudioIntervalMap silences;
5319 d.silences (silences);
5320 StripSilence s (*_session, silences, d.fade_length());
5322 apply_filter (s, _("strip silence"), &d);
5327 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5329 Evoral::Sequence<Evoral::Beats>::Notes selected;
5330 mrv.selection_as_notelist (selected, true);
5332 vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5333 v.push_back (selected);
5335 Evoral::Beats pos_beats = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
5337 return op (mrv.midi_region()->model(), pos_beats, v);
5341 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5347 bool in_command = false;
5349 for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5350 RegionSelection::const_iterator tmp = r;
5353 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5356 Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5359 begin_reversible_command (op.name ());
5363 _session->add_command (cmd);
5371 commit_reversible_command ();
5376 Editor::fork_region ()
5378 RegionSelection rs = get_regions_from_selection_and_entered ();
5384 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5385 bool in_command = false;
5389 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5390 RegionSelection::iterator tmp = r;
5393 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5397 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5398 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5399 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5402 begin_reversible_command (_("Fork Region(s)"));
5405 playlist->clear_changes ();
5406 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5407 _session->add_command(new StatefulDiffCommand (playlist));
5409 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5417 commit_reversible_command ();
5422 Editor::quantize_region ()
5425 quantize_regions(get_regions_from_selection_and_entered ());
5430 Editor::quantize_regions (const RegionSelection& rs)
5432 if (rs.n_midi_regions() == 0) {
5436 if (!quantize_dialog) {
5437 quantize_dialog = new QuantizeDialog (*this);
5440 if (quantize_dialog->is_mapped()) {
5441 /* in progress already */
5445 quantize_dialog->present ();
5446 const int r = quantize_dialog->run ();
5447 quantize_dialog->hide ();
5449 if (r == Gtk::RESPONSE_OK) {
5450 Quantize quant (quantize_dialog->snap_start(),
5451 quantize_dialog->snap_end(),
5452 quantize_dialog->start_grid_size(),
5453 quantize_dialog->end_grid_size(),
5454 quantize_dialog->strength(),
5455 quantize_dialog->swing(),
5456 quantize_dialog->threshold());
5458 apply_midi_note_edit_op (quant, rs);
5463 Editor::legatize_region (bool shrink_only)
5466 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5471 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5473 if (rs.n_midi_regions() == 0) {
5477 Legatize legatize(shrink_only);
5478 apply_midi_note_edit_op (legatize, rs);
5482 Editor::transform_region ()
5485 transform_regions(get_regions_from_selection_and_entered ());
5490 Editor::transform_regions (const RegionSelection& rs)
5492 if (rs.n_midi_regions() == 0) {
5499 const int r = td.run();
5502 if (r == Gtk::RESPONSE_OK) {
5503 Transform transform(td.get());
5504 apply_midi_note_edit_op(transform, rs);
5509 Editor::transpose_region ()
5512 transpose_regions(get_regions_from_selection_and_entered ());
5517 Editor::transpose_regions (const RegionSelection& rs)
5519 if (rs.n_midi_regions() == 0) {
5524 int const r = d.run ();
5526 if (r == RESPONSE_ACCEPT) {
5527 Transpose transpose(d.semitones ());
5528 apply_midi_note_edit_op (transpose, rs);
5533 Editor::insert_patch_change (bool from_context)
5535 RegionSelection rs = get_regions_from_selection_and_entered ();
5541 const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5543 /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5544 there may be more than one, but the PatchChangeDialog can only offer
5545 one set of patch menus.
5547 MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5549 Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5550 PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5552 if (d.run() == RESPONSE_CANCEL) {
5556 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5557 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5559 if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5560 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5567 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5569 RegionSelection rs = get_regions_from_selection_and_entered ();
5575 CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5576 bool in_command = false;
5581 int const N = rs.size ();
5583 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5584 RegionSelection::iterator tmp = r;
5587 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5589 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5592 progress->descend (1.0 / N);
5595 if (arv->audio_region()->apply (filter, progress) == 0) {
5597 playlist->clear_changes ();
5598 playlist->clear_owned_changes ();
5601 begin_reversible_command (command);
5605 if (filter.results.empty ()) {
5607 /* no regions returned; remove the old one */
5608 playlist->remove_region (arv->region ());
5612 std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5614 /* first region replaces the old one */
5615 playlist->replace_region (arv->region(), *res, (*res)->position());
5619 while (res != filter.results.end()) {
5620 playlist->add_region (*res, (*res)->position());
5626 /* We might have removed regions, which alters other regions' layering_index,
5627 so we need to do a recursive diff here.
5629 vector<Command*> cmds;
5630 playlist->rdiff (cmds);
5631 _session->add_commands (cmds);
5633 _session->add_command(new StatefulDiffCommand (playlist));
5637 progress->ascend ();
5646 commit_reversible_command ();
5651 Editor::external_edit_region ()
5657 Editor::reset_region_gain_envelopes ()
5659 RegionSelection rs = get_regions_from_selection_and_entered ();
5661 if (!_session || rs.empty()) {
5665 bool in_command = false;
5667 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5668 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5670 boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5671 XMLNode& before (alist->get_state());
5673 arv->audio_region()->set_default_envelope ();
5676 begin_reversible_command (_("reset region gain"));
5679 _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5684 commit_reversible_command ();
5689 Editor::set_region_gain_visibility (RegionView* rv)
5691 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5693 arv->update_envelope_visibility();
5698 Editor::set_gain_envelope_visibility ()
5704 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5705 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5707 v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5713 Editor::toggle_gain_envelope_active ()
5715 if (_ignore_region_action) {
5719 RegionSelection rs = get_regions_from_selection_and_entered ();
5721 if (!_session || rs.empty()) {
5725 bool in_command = false;
5727 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5728 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5730 arv->region()->clear_changes ();
5731 arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5734 begin_reversible_command (_("region gain envelope active"));
5737 _session->add_command (new StatefulDiffCommand (arv->region()));
5742 commit_reversible_command ();
5747 Editor::toggle_region_lock ()
5749 if (_ignore_region_action) {
5753 RegionSelection rs = get_regions_from_selection_and_entered ();
5755 if (!_session || rs.empty()) {
5759 begin_reversible_command (_("toggle region lock"));
5761 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5762 (*i)->region()->clear_changes ();
5763 (*i)->region()->set_locked (!(*i)->region()->locked());
5764 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5767 commit_reversible_command ();
5771 Editor::toggle_region_video_lock ()
5773 if (_ignore_region_action) {
5777 RegionSelection rs = get_regions_from_selection_and_entered ();
5779 if (!_session || rs.empty()) {
5783 begin_reversible_command (_("Toggle Video Lock"));
5785 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5786 (*i)->region()->clear_changes ();
5787 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5788 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5791 commit_reversible_command ();
5795 Editor::toggle_region_lock_style ()
5797 if (_ignore_region_action) {
5801 RegionSelection rs = get_regions_from_selection_and_entered ();
5803 if (!_session || rs.empty()) {
5807 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5808 vector<Widget*> proxies = a->get_proxies();
5809 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5813 begin_reversible_command (_("toggle region lock style"));
5815 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5816 (*i)->region()->clear_changes ();
5817 PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5818 (*i)->region()->set_position_lock_style (ns);
5819 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5822 commit_reversible_command ();
5826 Editor::toggle_opaque_region ()
5828 if (_ignore_region_action) {
5832 RegionSelection rs = get_regions_from_selection_and_entered ();
5834 if (!_session || rs.empty()) {
5838 begin_reversible_command (_("change region opacity"));
5840 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5841 (*i)->region()->clear_changes ();
5842 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5843 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5846 commit_reversible_command ();
5850 Editor::toggle_record_enable ()
5852 bool new_state = false;
5854 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5855 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5858 if (!rtav->is_track())
5862 new_state = !rtav->track()->rec_enable_control()->get_value();
5866 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5871 Editor::toggle_solo ()
5873 bool new_state = false;
5875 boost::shared_ptr<ControlList> cl (new ControlList);
5877 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5878 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5880 if (!stav || !stav->stripable()->solo_control()) {
5885 new_state = !stav->stripable()->solo_control()->soloed ();
5889 cl->push_back (stav->stripable()->solo_control());
5892 _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5896 Editor::toggle_mute ()
5898 bool new_state = false;
5900 boost::shared_ptr<ControlList> cl (new ControlList);
5902 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5903 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5905 if (!stav || !stav->stripable()->mute_control()) {
5910 new_state = !stav->stripable()->mute_control()->muted();
5914 cl->push_back (stav->stripable()->mute_control());
5917 _session->set_controls (cl, new_state, Controllable::UseGroup);
5921 Editor::toggle_solo_isolate ()
5927 Editor::fade_range ()
5929 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5931 begin_reversible_command (_("fade range"));
5933 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5934 (*i)->fade_range (selection->time);
5937 commit_reversible_command ();
5942 Editor::set_fade_length (bool in)
5944 RegionSelection rs = get_regions_from_selection_and_entered ();
5950 /* we need a region to measure the offset from the start */
5952 RegionView* rv = rs.front ();
5954 framepos_t pos = get_preferred_edit_position();
5958 if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5959 /* edit point is outside the relevant region */
5964 if (pos <= rv->region()->position()) {
5968 len = pos - rv->region()->position();
5969 cmd = _("set fade in length");
5971 if (pos >= rv->region()->last_frame()) {
5975 len = rv->region()->last_frame() - pos;
5976 cmd = _("set fade out length");
5979 bool in_command = false;
5981 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5982 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5988 boost::shared_ptr<AutomationList> alist;
5990 alist = tmp->audio_region()->fade_in();
5992 alist = tmp->audio_region()->fade_out();
5995 XMLNode &before = alist->get_state();
5998 tmp->audio_region()->set_fade_in_length (len);
5999 tmp->audio_region()->set_fade_in_active (true);
6001 tmp->audio_region()->set_fade_out_length (len);
6002 tmp->audio_region()->set_fade_out_active (true);
6006 begin_reversible_command (cmd);
6009 XMLNode &after = alist->get_state();
6010 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
6014 commit_reversible_command ();
6019 Editor::set_fade_in_shape (FadeShape shape)
6021 RegionSelection rs = get_regions_from_selection_and_entered ();
6026 bool in_command = false;
6028 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6029 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6035 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6036 XMLNode &before = alist->get_state();
6038 tmp->audio_region()->set_fade_in_shape (shape);
6041 begin_reversible_command (_("set fade in shape"));
6044 XMLNode &after = alist->get_state();
6045 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6049 commit_reversible_command ();
6054 Editor::set_fade_out_shape (FadeShape shape)
6056 RegionSelection rs = get_regions_from_selection_and_entered ();
6061 bool in_command = false;
6063 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6064 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6070 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6071 XMLNode &before = alist->get_state();
6073 tmp->audio_region()->set_fade_out_shape (shape);
6076 begin_reversible_command (_("set fade out shape"));
6079 XMLNode &after = alist->get_state();
6080 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6084 commit_reversible_command ();
6089 Editor::set_fade_in_active (bool yn)
6091 RegionSelection rs = get_regions_from_selection_and_entered ();
6096 bool in_command = false;
6098 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6099 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6106 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6108 ar->clear_changes ();
6109 ar->set_fade_in_active (yn);
6112 begin_reversible_command (_("set fade in active"));
6115 _session->add_command (new StatefulDiffCommand (ar));
6119 commit_reversible_command ();
6124 Editor::set_fade_out_active (bool yn)
6126 RegionSelection rs = get_regions_from_selection_and_entered ();
6131 bool in_command = false;
6133 for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6134 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6140 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6142 ar->clear_changes ();
6143 ar->set_fade_out_active (yn);
6146 begin_reversible_command (_("set fade out active"));
6149 _session->add_command(new StatefulDiffCommand (ar));
6153 commit_reversible_command ();
6158 Editor::toggle_region_fades (int dir)
6160 if (_ignore_region_action) {
6164 boost::shared_ptr<AudioRegion> ar;
6167 RegionSelection rs = get_regions_from_selection_and_entered ();
6173 RegionSelection::iterator i;
6174 for (i = rs.begin(); i != rs.end(); ++i) {
6175 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6177 yn = ar->fade_out_active ();
6179 yn = ar->fade_in_active ();
6185 if (i == rs.end()) {
6189 /* XXX should this undo-able? */
6190 bool in_command = false;
6192 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6193 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6196 ar->clear_changes ();
6198 if (dir == 1 || dir == 0) {
6199 ar->set_fade_in_active (!yn);
6202 if (dir == -1 || dir == 0) {
6203 ar->set_fade_out_active (!yn);
6206 begin_reversible_command (_("toggle fade active"));
6209 _session->add_command(new StatefulDiffCommand (ar));
6213 commit_reversible_command ();
6218 /** Update region fade visibility after its configuration has been changed */
6220 Editor::update_region_fade_visibility ()
6222 bool _fade_visibility = _session->config.get_show_region_fades ();
6224 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6225 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6227 if (_fade_visibility) {
6228 v->audio_view()->show_all_fades ();
6230 v->audio_view()->hide_all_fades ();
6237 Editor::set_edit_point ()
6240 MusicFrame where (0, 0);
6242 if (!mouse_frame (where.frame, ignored)) {
6248 if (selection->markers.empty()) {
6250 mouse_add_new_marker (where.frame);
6255 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6258 loc->move_to (where.frame, where.division);
6264 Editor::set_playhead_cursor ()
6266 if (entered_marker) {
6267 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6269 MusicFrame where (0, 0);
6272 if (!mouse_frame (where.frame, ignored)) {
6279 _session->request_locate (where.frame, _session->transport_rolling());
6283 //not sure what this was for; remove it for now.
6284 // if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6285 // cancel_time_selection();
6291 Editor::split_region ()
6293 if (_drags->active ()) {
6297 //if a range is selected, separate it
6298 if ( !selection->time.empty()) {
6299 separate_regions_between (selection->time);
6303 //if no range was selected, try to find some regions to split
6304 if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc.
6306 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6307 const framepos_t pos = get_preferred_edit_position();
6308 const int32_t division = get_grid_music_divisions (0);
6309 MusicFrame where (pos, division);
6315 split_regions_at (where, rs);
6321 Editor::select_next_stripable (bool routes_only)
6323 if (selection->tracks.empty()) {
6324 selection->set (track_views.front());
6328 TimeAxisView* current = selection->tracks.front();
6332 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6334 if (*i == current) {
6336 if (i != track_views.end()) {
6339 current = (*(track_views.begin()));
6340 //selection->set (*(track_views.begin()));
6347 RouteUI* rui = dynamic_cast<RouteUI *>(current);
6348 valid = rui && rui->route()->active();
6350 valid = 0 != current->stripable ().get();
6353 } while (current->hidden() || !valid);
6355 selection->set (current);
6357 ensure_time_axis_view_is_visible (*current, false);
6361 Editor::select_prev_stripable (bool routes_only)
6363 if (selection->tracks.empty()) {
6364 selection->set (track_views.front());
6368 TimeAxisView* current = selection->tracks.front();
6372 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6374 if (*i == current) {
6376 if (i != track_views.rend()) {
6379 current = *(track_views.rbegin());
6385 RouteUI* rui = dynamic_cast<RouteUI *>(current);
6386 valid = rui && rui->route()->active();
6388 valid = 0 != current->stripable ().get();
6391 } while (current->hidden() || !valid);
6393 selection->set (current);
6395 ensure_time_axis_view_is_visible (*current, false);
6399 Editor::set_loop_from_selection (bool play)
6401 if (_session == 0) {
6405 framepos_t start, end;
6406 if (!get_selection_extents ( start, end))
6409 set_loop_range (start, end, _("set loop range from selection"));
6412 _session->request_play_loop (true, true);
6417 Editor::set_loop_from_region (bool play)
6419 framepos_t start, end;
6420 if (!get_selection_extents ( start, end))
6423 set_loop_range (start, end, _("set loop range from region"));
6426 _session->request_locate (start, true);
6427 _session->request_play_loop (true);
6432 Editor::set_punch_from_selection ()
6434 if (_session == 0) {
6438 framepos_t start, end;
6439 if (!get_selection_extents ( start, end))
6442 set_punch_range (start, end, _("set punch range from selection"));
6446 Editor::set_auto_punch_range ()
6448 // auto punch in/out button from a single button
6449 // If Punch In is unset, set punch range from playhead to end, enable punch in
6450 // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6451 // rewound beyond the Punch In marker, in which case that marker will be moved back
6452 // to the current playhead position.
6453 // If punch out is set, it clears the punch range and Punch In/Out buttons
6455 if (_session == 0) {
6459 Location* tpl = transport_punch_location();
6460 framepos_t now = playhead_cursor->current_frame();
6461 framepos_t begin = now;
6462 framepos_t end = _session->current_end_frame();
6464 if (!_session->config.get_punch_in()) {
6465 // First Press - set punch in and create range from here to eternity
6466 set_punch_range (begin, end, _("Auto Punch In"));
6467 _session->config.set_punch_in(true);
6468 } else if (tpl && !_session->config.get_punch_out()) {
6469 // Second press - update end range marker and set punch_out
6470 if (now < tpl->start()) {
6471 // playhead has been rewound - move start back and pretend nothing happened
6473 set_punch_range (begin, end, _("Auto Punch In/Out"));
6475 // normal case for 2nd press - set the punch out
6476 end = playhead_cursor->current_frame ();
6477 set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6478 _session->config.set_punch_out(true);
6481 if (_session->config.get_punch_out()) {
6482 _session->config.set_punch_out(false);
6485 if (_session->config.get_punch_in()) {
6486 _session->config.set_punch_in(false);
6491 // third press - unset punch in/out and remove range
6492 _session->locations()->remove(tpl);
6499 Editor::set_session_extents_from_selection ()
6501 if (_session == 0) {
6505 framepos_t start, end;
6506 if (!get_selection_extents ( start, end))
6510 if ((loc = _session->locations()->session_range_location()) == 0) {
6511 _session->set_session_extents (start, end); // this will create a new session range; no need for UNDO
6513 XMLNode &before = loc->get_state();
6515 _session->set_session_extents (start, end);
6517 XMLNode &after = loc->get_state();
6519 begin_reversible_command (_("set session start/end from selection"));
6521 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6523 commit_reversible_command ();
6526 _session->set_end_is_free (false);
6530 Editor::set_punch_start_from_edit_point ()
6534 MusicFrame start (0, 0);
6535 framepos_t end = max_framepos;
6537 //use the existing punch end, if any
6538 Location* tpl = transport_punch_location();
6543 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6544 start.frame = _session->audible_frame();
6546 start.frame = get_preferred_edit_position();
6549 //snap the selection start/end
6552 //if there's not already a sensible selection endpoint, go "forever"
6553 if (start.frame > end ) {
6557 set_punch_range (start.frame, end, _("set punch start from EP"));
6563 Editor::set_punch_end_from_edit_point ()
6567 framepos_t start = 0;
6568 MusicFrame end (max_framepos, 0);
6570 //use the existing punch start, if any
6571 Location* tpl = transport_punch_location();
6573 start = tpl->start();
6576 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6577 end.frame = _session->audible_frame();
6579 end.frame = get_preferred_edit_position();
6582 //snap the selection start/end
6585 set_punch_range (start, end.frame, _("set punch end from EP"));
6591 Editor::set_loop_start_from_edit_point ()
6595 MusicFrame start (0, 0);
6596 framepos_t end = max_framepos;
6598 //use the existing loop end, if any
6599 Location* tpl = transport_loop_location();
6604 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6605 start.frame = _session->audible_frame();
6607 start.frame = get_preferred_edit_position();
6610 //snap the selection start/end
6613 //if there's not already a sensible selection endpoint, go "forever"
6614 if (start.frame > end ) {
6618 set_loop_range (start.frame, end, _("set loop start from EP"));
6624 Editor::set_loop_end_from_edit_point ()
6628 framepos_t start = 0;
6629 MusicFrame end (max_framepos, 0);
6631 //use the existing loop start, if any
6632 Location* tpl = transport_loop_location();
6634 start = tpl->start();
6637 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6638 end.frame = _session->audible_frame();
6640 end.frame = get_preferred_edit_position();
6643 //snap the selection start/end
6646 set_loop_range (start, end.frame, _("set loop end from EP"));
6651 Editor::set_punch_from_region ()
6653 framepos_t start, end;
6654 if (!get_selection_extents ( start, end))
6657 set_punch_range (start, end, _("set punch range from region"));
6661 Editor::pitch_shift_region ()
6663 RegionSelection rs = get_regions_from_selection_and_entered ();
6665 RegionSelection audio_rs;
6666 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6667 if (dynamic_cast<AudioRegionView*> (*i)) {
6668 audio_rs.push_back (*i);
6672 if (audio_rs.empty()) {
6676 pitch_shift (audio_rs, 1.2);
6680 Editor::set_tempo_from_region ()
6682 RegionSelection rs = get_regions_from_selection_and_entered ();
6684 if (!_session || rs.empty()) {
6688 RegionView* rv = rs.front();
6690 define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6694 Editor::use_range_as_bar ()
6696 framepos_t start, end;
6697 if (get_edit_op_range (start, end)) {
6698 define_one_bar (start, end);
6703 Editor::define_one_bar (framepos_t start, framepos_t end)
6705 framepos_t length = end - start;
6707 const Meter& m (_session->tempo_map().meter_at_frame (start));
6709 /* length = 1 bar */
6711 /* We're going to deliver a constant tempo here,
6712 so we can use frames per beat to determine length.
6713 now we want frames per beat.
6714 we have frames per bar, and beats per bar, so ...
6717 /* XXXX METER MATH */
6719 double frames_per_beat = length / m.divisions_per_bar();
6721 /* beats per minute = */
6723 double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6725 /* now decide whether to:
6727 (a) set global tempo
6728 (b) add a new tempo marker
6732 const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6734 bool do_global = false;
6736 if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6738 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6739 at the start, or create a new marker
6742 vector<string> options;
6743 options.push_back (_("Cancel"));
6744 options.push_back (_("Add new marker"));
6745 options.push_back (_("Set global tempo"));
6748 _("Define one bar"),
6749 _("Do you want to set the global tempo or add a new tempo marker?"),
6753 c.set_default_response (2);
6769 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6770 if the marker is at the region starter, change it, otherwise add
6775 begin_reversible_command (_("set tempo from region"));
6776 XMLNode& before (_session->tempo_map().get_state());
6779 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6780 } else if (t.frame() == start) {
6781 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6783 /* constant tempo */
6784 const Tempo tempo (beats_per_minute, t.note_type());
6785 _session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
6788 XMLNode& after (_session->tempo_map().get_state());
6790 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6791 commit_reversible_command ();
6795 Editor::split_region_at_transients ()
6797 AnalysisFeatureList positions;
6799 RegionSelection rs = get_regions_from_selection_and_entered ();
6801 if (!_session || rs.empty()) {
6805 begin_reversible_command (_("split regions"));
6807 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6809 RegionSelection::iterator tmp;
6814 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6817 ar->transients (positions);
6818 split_region_at_points ((*i)->region(), positions, true);
6825 commit_reversible_command ();
6830 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6832 bool use_rhythmic_rodent = false;
6834 boost::shared_ptr<Playlist> pl = r->playlist();
6836 list<boost::shared_ptr<Region> > new_regions;
6842 if (positions.empty()) {
6846 if (positions.size() > 20 && can_ferret) {
6847 std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
6848 MessageDialog msg (msgstr,
6851 Gtk::BUTTONS_OK_CANCEL);
6854 msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6855 msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6857 msg.set_secondary_text (_("Press OK to continue with this split operation"));
6860 msg.set_title (_("Excessive split?"));
6863 int response = msg.run();
6869 case RESPONSE_APPLY:
6870 use_rhythmic_rodent = true;
6877 if (use_rhythmic_rodent) {
6878 show_rhythm_ferret ();
6882 AnalysisFeatureList::const_iterator x;
6884 pl->clear_changes ();
6885 pl->clear_owned_changes ();
6887 x = positions.begin();
6889 if (x == positions.end()) {
6894 pl->remove_region (r);
6898 framepos_t rstart = r->first_frame ();
6899 framepos_t rend = r->last_frame ();
6901 while (x != positions.end()) {
6903 /* deal with positons that are out of scope of present region bounds */
6904 if (*x <= rstart || *x > rend) {
6909 /* file start = original start + how far we from the initial position ? */
6911 framepos_t file_start = r->start() + pos;
6913 /* length = next position - current position */
6915 framepos_t len = (*x) - pos - rstart;
6917 /* XXX we do we really want to allow even single-sample regions?
6918 * shouldn't we have some kind of lower limit on region size?
6927 if (RegionFactory::region_name (new_name, r->name())) {
6931 /* do NOT announce new regions 1 by one, just wait till they are all done */
6935 plist.add (ARDOUR::Properties::start, file_start);
6936 plist.add (ARDOUR::Properties::length, len);
6937 plist.add (ARDOUR::Properties::name, new_name);
6938 plist.add (ARDOUR::Properties::layer, 0);
6939 // TODO set transients_offset
6941 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6942 /* because we set annouce to false, manually add the new region to the
6945 RegionFactory::map_add (nr);
6947 pl->add_region (nr, rstart + pos);
6950 new_regions.push_front(nr);
6959 RegionFactory::region_name (new_name, r->name());
6961 /* Add the final region */
6964 plist.add (ARDOUR::Properties::start, r->start() + pos);
6965 plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6966 plist.add (ARDOUR::Properties::name, new_name);
6967 plist.add (ARDOUR::Properties::layer, 0);
6969 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6970 /* because we set annouce to false, manually add the new region to the
6973 RegionFactory::map_add (nr);
6974 pl->add_region (nr, r->position() + pos);
6977 new_regions.push_front(nr);
6982 /* We might have removed regions, which alters other regions' layering_index,
6983 so we need to do a recursive diff here.
6985 vector<Command*> cmds;
6987 _session->add_commands (cmds);
6989 _session->add_command (new StatefulDiffCommand (pl));
6993 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6994 set_selected_regionview_from_region_list ((*i), Selection::Add);
7000 Editor::place_transient()
7006 RegionSelection rs = get_regions_from_selection_and_edit_point ();
7012 framepos_t where = get_preferred_edit_position();
7014 begin_reversible_command (_("place transient"));
7016 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7017 (*r)->region()->add_transient(where);
7020 commit_reversible_command ();
7024 Editor::remove_transient(ArdourCanvas::Item* item)
7030 ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
7033 AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
7034 _arv->remove_transient (*(float*) _line->get_data ("position"));
7038 Editor::snap_regions_to_grid ()
7040 list <boost::shared_ptr<Playlist > > used_playlists;
7042 RegionSelection rs = get_regions_from_selection_and_entered ();
7044 if (!_session || rs.empty()) {
7048 begin_reversible_command (_("snap regions to grid"));
7050 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7052 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7054 if (!pl->frozen()) {
7055 /* we haven't seen this playlist before */
7057 /* remember used playlists so we can thaw them later */
7058 used_playlists.push_back(pl);
7061 (*r)->region()->clear_changes ();
7063 MusicFrame start ((*r)->region()->first_frame (), 0);
7065 (*r)->region()->set_position (start.frame, start.division);
7066 _session->add_command(new StatefulDiffCommand ((*r)->region()));
7069 while (used_playlists.size() > 0) {
7070 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7072 used_playlists.pop_front();
7075 commit_reversible_command ();
7079 Editor::close_region_gaps ()
7081 list <boost::shared_ptr<Playlist > > used_playlists;
7083 RegionSelection rs = get_regions_from_selection_and_entered ();
7085 if (!_session || rs.empty()) {
7089 Dialog dialog (_("Close Region Gaps"));
7092 table.set_spacings (12);
7093 table.set_border_width (12);
7094 Label* l = manage (left_aligned_label (_("Crossfade length")));
7095 table.attach (*l, 0, 1, 0, 1);
7097 SpinButton spin_crossfade (1, 0);
7098 spin_crossfade.set_range (0, 15);
7099 spin_crossfade.set_increments (1, 1);
7100 spin_crossfade.set_value (5);
7101 table.attach (spin_crossfade, 1, 2, 0, 1);
7103 table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7105 l = manage (left_aligned_label (_("Pull-back length")));
7106 table.attach (*l, 0, 1, 1, 2);
7108 SpinButton spin_pullback (1, 0);
7109 spin_pullback.set_range (0, 100);
7110 spin_pullback.set_increments (1, 1);
7111 spin_pullback.set_value(30);
7112 table.attach (spin_pullback, 1, 2, 1, 2);
7114 table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7116 dialog.get_vbox()->pack_start (table);
7117 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7118 dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7121 if (dialog.run () == RESPONSE_CANCEL) {
7125 framepos_t crossfade_len = spin_crossfade.get_value();
7126 framepos_t pull_back_frames = spin_pullback.get_value();
7128 crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7129 pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7131 /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7133 begin_reversible_command (_("close region gaps"));
7136 boost::shared_ptr<Region> last_region;
7138 rs.sort_by_position_and_track();
7140 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7142 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7144 if (!pl->frozen()) {
7145 /* we haven't seen this playlist before */
7147 /* remember used playlists so we can thaw them later */
7148 used_playlists.push_back(pl);
7152 framepos_t position = (*r)->region()->position();
7154 if (idx == 0 || position < last_region->position()){
7155 last_region = (*r)->region();
7160 (*r)->region()->clear_changes ();
7161 (*r)->region()->trim_front( (position - pull_back_frames));
7163 last_region->clear_changes ();
7164 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7166 _session->add_command (new StatefulDiffCommand ((*r)->region()));
7167 _session->add_command (new StatefulDiffCommand (last_region));
7169 last_region = (*r)->region();
7173 while (used_playlists.size() > 0) {
7174 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7176 used_playlists.pop_front();
7179 commit_reversible_command ();
7183 Editor::tab_to_transient (bool forward)
7185 AnalysisFeatureList positions;
7187 RegionSelection rs = get_regions_from_selection_and_entered ();
7193 framepos_t pos = _session->audible_frame ();
7195 if (!selection->tracks.empty()) {
7197 /* don't waste time searching for transients in duplicate playlists.
7200 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7202 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7204 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7207 boost::shared_ptr<Track> tr = rtv->track();
7209 boost::shared_ptr<Playlist> pl = tr->playlist ();
7211 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7214 positions.push_back (result);
7227 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7228 (*r)->region()->get_transients (positions);
7232 TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7235 AnalysisFeatureList::iterator x;
7237 for (x = positions.begin(); x != positions.end(); ++x) {
7243 if (x != positions.end ()) {
7244 _session->request_locate (*x);
7248 AnalysisFeatureList::reverse_iterator x;
7250 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7256 if (x != positions.rend ()) {
7257 _session->request_locate (*x);
7263 Editor::playhead_forward_to_grid ()
7269 MusicFrame pos (playhead_cursor->current_frame (), 0);
7271 if (pos.frame < max_framepos - 1) {
7273 snap_to_internal (pos, RoundUpAlways, false, true);
7274 _session->request_locate (pos.frame);
7280 Editor::playhead_backward_to_grid ()
7286 MusicFrame pos (playhead_cursor->current_frame (), 0);
7288 if (pos.frame > 2) {
7290 snap_to_internal (pos, RoundDownAlways, false, true);
7291 _session->request_locate (pos.frame);
7296 Editor::set_track_height (Height h)
7298 TrackSelection& ts (selection->tracks);
7300 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7301 (*x)->set_height_enum (h);
7306 Editor::toggle_tracks_active ()
7308 TrackSelection& ts (selection->tracks);
7310 bool target = false;
7316 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7317 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7321 target = !rtv->_route->active();
7324 rtv->_route->set_active (target, this);
7330 Editor::remove_tracks ()
7332 /* this will delete GUI objects that may be the subject of an event
7333 handler in which this method is called. Defer actual deletion to the
7334 next idle callback, when all event handling is finished.
7336 Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7340 Editor::idle_remove_tracks ()
7342 Session::StateProtector sp (_session);
7344 return false; /* do not call again */
7348 Editor::_remove_tracks ()
7350 TrackSelection& ts (selection->tracks);
7356 vector<string> choices;
7361 const char* trackstr;
7364 vector<boost::shared_ptr<Route> > routes;
7365 vector<boost::shared_ptr<VCA> > vcas;
7366 bool special_bus = false;
7368 for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7369 VCATimeAxisView* vtv = dynamic_cast<VCATimeAxisView*> (*x);
7371 vcas.push_back (vtv->vca());
7375 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7379 if (rtv->is_track()) {
7384 routes.push_back (rtv->_route);
7386 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7391 if (special_bus && !Config->get_allow_special_bus_removal()) {
7392 MessageDialog msg (_("That would be bad news ...."),
7396 msg.set_secondary_text (string_compose (_(
7397 "Removing the master or monitor bus is such a bad idea\n\
7398 that %1 is not going to allow it.\n\
7400 If you really want to do this sort of thing\n\
7401 edit your ardour.rc file to set the\n\
7402 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7409 if (ntracks + nbusses + nvcas == 0) {
7415 trackstr = P_("track", "tracks", ntracks);
7416 busstr = P_("bus", "busses", nbusses);
7417 vcastr = P_("VCA", "VCAs", nvcas);
7419 if (ntracks > 0 && nbusses > 0 && nvcas > 0) {
7420 title = _("Remove various strips");
7421 prompt = string_compose (_("Do you really want to remove %1 %2, %3 %4 and %5 %6?"),
7422 ntracks, trackstr, nbusses, busstr, nvcas, vcastr);
7424 else if (ntracks > 0 && nbusses > 0) {
7425 title = string_compose (_("Remove %1 and %2"), trackstr, busstr);
7426 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7427 ntracks, trackstr, nbusses, busstr);
7429 else if (ntracks > 0 && nvcas > 0) {
7430 title = string_compose (_("Remove %1 and %2"), trackstr, vcastr);
7431 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7432 ntracks, trackstr, nvcas, vcastr);
7434 else if (nbusses > 0 && nvcas > 0) {
7435 title = string_compose (_("Remove %1 and %2"), busstr, vcastr);
7436 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7437 nbusses, busstr, nvcas, vcastr);
7439 else if (ntracks > 0) {
7440 title = string_compose (_("Remove %1"), trackstr);
7441 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7444 else if (nbusses > 0) {
7445 title = string_compose (_("Remove %1"), busstr);
7446 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7449 else if (nvcas > 0) {
7450 title = string_compose (_("Remove %1"), vcastr);
7451 prompt = string_compose (_("Do you really want to remove %1 %2?"),
7459 prompt += "\n" + string_compose ("(You may also lose the playlists associated with the %1)", trackstr) + "\n";
7462 prompt += "\n" + string(_("This action cannot be undone, and the session file will be overwritten!"));
7464 choices.push_back (_("No, do nothing."));
7465 if (ntracks + nbusses + nvcas > 1) {
7466 choices.push_back (_("Yes, remove them."));
7468 choices.push_back (_("Yes, remove it."));
7471 Choice prompter (title, prompt, choices);
7473 if (prompter.run () != 1) {
7477 if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7478 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7479 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7480 * likely because deletion requires selection) this will call
7481 * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7482 * It's likewise likely that the route that has just been displayed in the
7483 * Editor-Mixer will be next in line for deletion.
7485 * So simply switch to the master-bus (if present)
7487 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7488 if ((*i)->stripable ()->is_master ()) {
7489 set_selected_mixer_strip (*(*i));
7496 PresentationInfo::ChangeSuspender cs;
7497 DisplaySuspender ds;
7499 boost::shared_ptr<RouteList> rl (new RouteList);
7500 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7503 _session->remove_routes (rl);
7505 for (vector<boost::shared_ptr<VCA> >::iterator x = vcas.begin(); x != vcas.end(); ++x) {
7506 _session->vca_manager().remove_vca (*x);
7510 /* TrackSelection and RouteList leave scope,
7511 * destructors are called,
7512 * diskstream drops references, save_state is called (again for every track)
7517 Editor::do_insert_time ()
7519 if (selection->tracks.empty()) {
7523 InsertRemoveTimeDialog d (*this);
7524 int response = d.run ();
7526 if (response != RESPONSE_OK) {
7530 if (d.distance() == 0) {
7537 d.intersected_region_action (),
7541 d.move_glued_markers(),
7542 d.move_locked_markers(),
7548 Editor::insert_time (
7549 framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7550 bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7554 if (Config->get_edit_mode() == Lock) {
7557 bool in_command = false;
7559 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7561 for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7565 /* don't operate on any playlist more than once, which could
7566 * happen if "all playlists" is enabled, but there is more
7567 * than 1 track using playlists "from" a given track.
7570 set<boost::shared_ptr<Playlist> > pl;
7572 if (all_playlists) {
7573 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7574 if (rtav && rtav->track ()) {
7575 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7576 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7581 if ((*x)->playlist ()) {
7582 pl.insert ((*x)->playlist ());
7586 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7588 (*i)->clear_changes ();
7589 (*i)->clear_owned_changes ();
7592 begin_reversible_command (_("insert time"));
7596 if (opt == SplitIntersected) {
7597 /* non musical split */
7598 (*i)->split (MusicFrame (pos, 0));
7601 (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7603 vector<Command*> cmds;
7605 _session->add_commands (cmds);
7607 _session->add_command (new StatefulDiffCommand (*i));
7611 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7614 begin_reversible_command (_("insert time"));
7617 rtav->route ()->shift (pos, frames);
7624 const int32_t divisions = get_grid_music_divisions (0);
7625 XMLNode& before (_session->locations()->get_state());
7626 Locations::LocationList copy (_session->locations()->list());
7628 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7630 Locations::LocationList::const_iterator tmp;
7632 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7633 bool const was_locked = (*i)->locked ();
7634 if (locked_markers_too) {
7638 if ((*i)->start() >= pos) {
7639 // move end first, in case we're moving by more than the length of the range
7640 if (!(*i)->is_mark()) {
7641 (*i)->set_end ((*i)->end() + frames, false, true, divisions);
7643 (*i)->set_start ((*i)->start() + frames, false, true, divisions);
7655 begin_reversible_command (_("insert time"));
7658 XMLNode& after (_session->locations()->get_state());
7659 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7665 begin_reversible_command (_("insert time"));
7668 XMLNode& before (_session->tempo_map().get_state());
7669 _session->tempo_map().insert_time (pos, frames);
7670 XMLNode& after (_session->tempo_map().get_state());
7671 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7675 commit_reversible_command ();
7680 Editor::do_remove_time ()
7682 if (selection->tracks.empty()) {
7686 InsertRemoveTimeDialog d (*this, true);
7688 int response = d.run ();
7690 if (response != RESPONSE_OK) {
7694 framecnt_t distance = d.distance();
7696 if (distance == 0) {
7706 d.move_glued_markers(),
7707 d.move_locked_markers(),
7713 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7714 bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7716 if (Config->get_edit_mode() == Lock) {
7717 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7720 bool in_command = false;
7722 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7724 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7728 XMLNode &before = pl->get_state();
7731 begin_reversible_command (_("remove time"));
7735 std::list<AudioRange> rl;
7736 AudioRange ar(pos, pos+frames, 0);
7739 pl->shift (pos, -frames, true, ignore_music_glue);
7741 XMLNode &after = pl->get_state();
7743 _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7747 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7750 begin_reversible_command (_("remove time"));
7753 rtav->route ()->shift (pos, -frames);
7757 const int32_t divisions = get_grid_music_divisions (0);
7758 std::list<Location*> loc_kill_list;
7763 XMLNode& before (_session->locations()->get_state());
7764 Locations::LocationList copy (_session->locations()->list());
7766 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7767 if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7769 bool const was_locked = (*i)->locked ();
7770 if (locked_markers_too) {
7774 if (!(*i)->is_mark()) { // it's a range; have to handle both start and end
7775 if ((*i)->end() >= pos
7776 && (*i)->end() < pos+frames
7777 && (*i)->start() >= pos
7778 && (*i)->end() < pos+frames) { // range is completely enclosed; kill it
7780 loc_kill_list.push_back(*i);
7781 } else { // only start or end is included, try to do the right thing
7782 // move start before moving end, to avoid trying to move the end to before the start
7783 // if we're removing more time than the length of the range
7784 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7785 // start is within cut
7786 (*i)->set_start (pos, false, true,divisions); // bring the start marker to the beginning of the cut
7788 } else if ((*i)->start() >= pos+frames) {
7789 // start (and thus entire range) lies beyond end of cut
7790 (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7793 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7794 // end is inside cut
7795 (*i)->set_end (pos, false, true, divisions); // bring the end to the cut
7797 } else if ((*i)->end() >= pos+frames) {
7798 // end is beyond end of cut
7799 (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7804 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7805 loc_kill_list.push_back(*i);
7807 } else if ((*i)->start() >= pos) {
7808 (*i)->set_start ((*i)->start() -frames, false, true, divisions);
7818 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7819 _session->locations()->remove( *i );
7824 begin_reversible_command (_("remove time"));
7827 XMLNode& after (_session->locations()->get_state());
7828 _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7833 XMLNode& before (_session->tempo_map().get_state());
7835 if (_session->tempo_map().remove_time (pos, frames) ) {
7837 begin_reversible_command (_("remove time"));
7840 XMLNode& after (_session->tempo_map().get_state());
7841 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7846 commit_reversible_command ();
7851 Editor::fit_selection ()
7853 if (!selection->tracks.empty()) {
7854 fit_tracks (selection->tracks);
7858 /* no selected tracks - use tracks with selected regions */
7860 if (!selection->regions.empty()) {
7861 for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7862 tvl.push_back (&(*r)->get_time_axis_view ());
7868 } else if (internal_editing()) {
7869 /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7872 if (entered_track) {
7873 tvl.push_back (entered_track);
7881 Editor::fit_tracks (TrackViewList & tracks)
7883 if (tracks.empty()) {
7887 uint32_t child_heights = 0;
7888 int visible_tracks = 0;
7890 for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7892 if (!(*t)->marked_for_display()) {
7896 child_heights += (*t)->effective_height() - (*t)->current_height();
7900 /* compute the per-track height from:
7902 * total canvas visible height
7903 * - height that will be taken by visible children of selected tracks
7904 * - height of the ruler/hscroll area
7906 uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7907 double first_y_pos = DBL_MAX;
7909 if (h < TimeAxisView::preset_height (HeightSmall)) {
7910 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7911 /* too small to be displayed */
7915 undo_visual_stack.push_back (current_visual_state (true));
7916 PBD::Unwinder<bool> nsv (no_save_visual, true);
7918 /* build a list of all tracks, including children */
7921 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7923 TimeAxisView::Children c = (*i)->get_child_list ();
7924 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7925 all.push_back (j->get());
7930 // find selection range.
7931 // if someone knows how to user TrackViewList::iterator for this
7933 int selected_top = -1;
7934 int selected_bottom = -1;
7936 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7937 if ((*t)->marked_for_display ()) {
7938 if (tracks.contains(*t)) {
7939 if (selected_top == -1) {
7942 selected_bottom = i;
7948 for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7949 if ((*t)->marked_for_display ()) {
7950 if (tracks.contains(*t)) {
7951 (*t)->set_height (h);
7952 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7954 if (i > selected_top && i < selected_bottom) {
7955 hide_track_in_display (*t);
7962 set the controls_layout height now, because waiting for its size
7963 request signal handler will cause the vertical adjustment setting to fail
7966 controls_layout.property_height () = _full_canvas_height;
7967 vertical_adjustment.set_value (first_y_pos);
7969 redo_visual_stack.push_back (current_visual_state (true));
7971 visible_tracks_selector.set_text (_("Sel"));
7975 Editor::save_visual_state (uint32_t n)
7977 while (visual_states.size() <= n) {
7978 visual_states.push_back (0);
7981 if (visual_states[n] != 0) {
7982 delete visual_states[n];
7985 visual_states[n] = current_visual_state (true);
7990 Editor::goto_visual_state (uint32_t n)
7992 if (visual_states.size() <= n) {
7996 if (visual_states[n] == 0) {
8000 use_visual_state (*visual_states[n]);
8004 Editor::start_visual_state_op (uint32_t n)
8006 save_visual_state (n);
8008 PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
8010 snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
8011 pup->set_text (buf);
8016 Editor::cancel_visual_state_op (uint32_t n)
8018 goto_visual_state (n);
8022 Editor::toggle_region_mute ()
8024 if (_ignore_region_action) {
8028 RegionSelection rs = get_regions_from_selection_and_entered ();
8034 if (rs.size() > 1) {
8035 begin_reversible_command (_("mute regions"));
8037 begin_reversible_command (_("mute region"));
8040 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
8042 (*i)->region()->playlist()->clear_changes ();
8043 (*i)->region()->set_muted (!(*i)->region()->muted ());
8044 _session->add_command (new StatefulDiffCommand ((*i)->region()));
8048 commit_reversible_command ();
8052 Editor::combine_regions ()
8054 /* foreach track with selected regions, take all selected regions
8055 and join them into a new region containing the subregions (as a
8059 typedef set<RouteTimeAxisView*> RTVS;
8062 if (selection->regions.empty()) {
8066 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8067 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8070 tracks.insert (rtv);
8074 begin_reversible_command (_("combine regions"));
8076 vector<RegionView*> new_selection;
8078 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8081 if ((rv = (*i)->combine_regions ()) != 0) {
8082 new_selection.push_back (rv);
8086 selection->clear_regions ();
8087 for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
8088 selection->add (*i);
8091 commit_reversible_command ();
8095 Editor::uncombine_regions ()
8097 typedef set<RouteTimeAxisView*> RTVS;
8100 if (selection->regions.empty()) {
8104 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8105 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8108 tracks.insert (rtv);
8112 begin_reversible_command (_("uncombine regions"));
8114 for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8115 (*i)->uncombine_regions ();
8118 commit_reversible_command ();
8122 Editor::toggle_midi_input_active (bool flip_others)
8125 boost::shared_ptr<RouteList> rl (new RouteList);
8127 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8128 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8134 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8137 rl->push_back (rtav->route());
8138 onoff = !mt->input_active();
8142 _session->set_exclusive_input_active (rl, onoff, flip_others);
8145 static bool ok_fine (GdkEventAny*) { return true; }
8151 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8153 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8154 lock_dialog->get_vbox()->pack_start (*padlock);
8155 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8157 ArdourButton* b = manage (new ArdourButton);
8158 b->set_name ("lock button");
8159 b->set_text (_("Click to unlock"));
8160 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8161 lock_dialog->get_vbox()->pack_start (*b);
8163 lock_dialog->get_vbox()->show_all ();
8164 lock_dialog->set_size_request (200, 200);
8167 delete _main_menu_disabler;
8168 _main_menu_disabler = new MainMenuDisabler;
8170 lock_dialog->present ();
8172 lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8178 lock_dialog->hide ();
8180 delete _main_menu_disabler;
8181 _main_menu_disabler = 0;
8183 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8184 start_lock_event_timing ();
8189 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8191 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8195 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8197 Timers::TimerSuspender t;
8198 label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8199 Gtkmm2ext::UI::instance()->flush_pending (1);
8203 Editor::bring_all_sources_into_session ()
8210 ArdourDialog w (_("Moving embedded files into session folder"));
8211 w.get_vbox()->pack_start (msg);
8214 /* flush all pending GUI events because we're about to start copying
8218 Timers::TimerSuspender t;
8219 Gtkmm2ext::UI::instance()->flush_pending (3);
8223 _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));